1 /* PANEL.C      (c) Copyright Roger Bowler, 1999-2010                */
2 /*              Hercules Control Panel Commands                      */
3 
4 /*              Modified for New Panel Display =NP=                  */
5 /*-------------------------------------------------------------------*/
6 /* This module is the control panel for the ESA/390 emulator.        */
7 /* It provides a command interface into hercules, and it displays    */
8 /* messages that are issued by various hercules components.          */
9 /*-------------------------------------------------------------------*/
10 
11 /*-------------------------------------------------------------------*/
12 /* Additional credits:                                               */
13 /*      breakpoint command contributed by Dan Horak                  */
14 /*      devinit command contributed by Jay Maynard                   */
15 /*      New Panel Display contributed by Dutch Owen                  */
16 /*      HMC system console commands contributed by Jan Jaeger        */
17 /*      Set/reset bad frame indicator command by Jan Jaeger          */
18 /*      attach/detach/define commands by Jan Jaeger                  */
19 /*      Panel refresh rate triva by Reed H. Petty                    */
20 /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2007      */
21 /*      64-bit address support by Roger Bowler                       */
22 /*      Display subchannel command by Nobumichi Kozawa               */
23 /*      External GUI logic contributed by "Fish" (David B. Trout)    */
24 /*      Socket Devices originally designed by Malcolm Beattie;       */
25 /*      actual implementation by "Fish" (David B. Trout).            */
26 /*-------------------------------------------------------------------*/
27 
28 #include "hstdinc.h"
29 
30 #define _PANEL_C_
31 #define _HENGINE_DLL_
32 
33 #include "hercules.h"
34 #include "devtype.h"
35 #include "opcode.h"
36 #include "history.h"
37 // #include "inline.h"
38 #include "fillfnam.h"
39 #include "hconsole.h"
40 
41 #define  DISPLAY_INSTRUCTION_OPERANDS
42 
43 #define PANEL_MAX_ROWS  (256)
44 #define PANEL_MAX_COLS  (256)
45 
46 int     redraw_msgs;                    /* 1=Redraw message area     */
47 int     redraw_cmd;                     /* 1=Redraw command line     */
48 int     redraw_status;                  /* 1=Redraw status line      */
49 
50 /*=NP================================================================*/
51 /* Global data for new panel display                                 */
52 /*   (Note: all NPD mods are identified by the string =NP=           */
53 /*===================================================================*/
54 
55 static int    NPDup = 0;               /* 1 = new panel is up       */
56 static int    NPDinit = 0;             /* 1 = new panel initialized */
57 static int    NPhelpup = 0;            /* 1 = help panel showing    */
58 static int    NPhelppaint = 1;         /* 1 = help pnl s/b painted  */
59 static int    NPhelpdown = 0;          /* 1 = help pnl coming down  */
60 static int    NPregdisp = 0;           /* which regs are displayed: */
61                                        /* 0=gpr, 1=cr, 2=ar, 3=fpr  */
62 static int    NPcmd = 0;               /* 1 = NP in command mode    */
63 static int    NPdataentry = 0;         /* 1 = NP in data-entry mode */
64 static int    NPdevsel = 0;            /* 1 = device being selected */
65 static char   NPpending;               /* pending data entry cmd    */
66 static char   NPentered[256];          /* Data which was entered    */
67 static char   NPprompt1[40];           /* Left bottom screen prompt */
68 static char   NPoldprompt1[40];        /* Left bottom screen prompt */
69 static char   NPprompt2[40];           /* Right bottom screen prompt*/
70 static char   NPoldprompt2[40];        /* Right bottom screen prompt*/
71 static char   NPsel2;                  /* dev sel part 2 cmd letter */
72 static char   NPdevice;                /* Which device is selected  */
73 static int    NPasgn;                  /* Index to dev being init'ed*/
74 static int    NPlastdev;               /* Number of devices         */
75 static int    NPcpugraph_ncpu;         /* Number of CPUs to display */
76 
77 static char  *NPregnum[]   = {" 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7",
78                               " 8"," 9","10","11","12","13","14","15"
79                              };
80 static char  *NPregnum64[] = {"0", "1", "2", "3", "4", "5", "6", "7",
81                               "8", "9", "A", "B", "C", "D", "E", "F"
82                              };
83 
84 /* Boolean fields; redraw the corresponding data field if false */
85 static int    NPcpunum_valid,
86               NPcpupct_valid,
87               NPpsw_valid,
88               NPpswstate_valid,
89               NPregs_valid,
90               NPaddr_valid,
91               NPdata_valid,
92 #ifdef OPTION_MIPS_COUNTING
93               NPmips_valid,
94               NPsios_valid,
95 #endif // OPTION_MIPS_COUNTING
96               NPdevices_valid,
97               NPcpugraph_valid;
98 
99 /* Current CPU states */
100 static U16    NPcpunum;
101 static int    NPcpupct;
102 static int    NPpswmode;
103 static int    NPpswzhost;
104 static QWORD  NPpsw;
105 static char   NPpswstate[16];
106 static int    NPregmode;
107 static int    NPregzhost;
108 static U64    NPregs64[16];
109 static U32    NPregs[16];
110 static U32    NPaddress;
111 static U32    NPdata;
112 #ifdef OPTION_MIPS_COUNTING
113 static U32    NPmips;
114 static U32    NPsios;
115 #else
116 static U64    NPinstcount;
117 #endif // OPTION_MIPS_COUNTING
118 static int    NPcpugraph;
119 static int    NPcpugraphpct[MAX_CPU_ENGINES];
120 
121 /* Current device states */
122 #define       NP_MAX_DEVICES (PANEL_MAX_ROWS - 3)
123 static int    NPonline[NP_MAX_DEVICES];
124 static U16    NPdevnum[NP_MAX_DEVICES];
125 static int    NPbusy[NP_MAX_DEVICES];
126 static U16    NPdevtype[NP_MAX_DEVICES];
127 static int    NPopen[NP_MAX_DEVICES];
128 static char   NPdevnam[NP_MAX_DEVICES][128];
129 
130 static short  NPcurrow, NPcurcol;
131 static int    NPcolorSwitch;
132 static short  NPcolorFore;
133 static short  NPcolorBack;
134 static int    NPdatalen;
135 
136 static char  *NPhelp[] = {
137 "All commands consist of one character keypresses.  The various commands are",
138 "highlighted onscreen by bright white versus the gray of other lettering.",
139 " ",
140 "Press the escape key to terminate the control panel and go to command mode.",
141 " ",
142 "Display Controls:   G - General purpose regs    C - Control regs",
143 "                    A - Access registers        F - Floating Point regs",
144 "                    I - Display main memory at 'ADDRESS'",
145 "CPU controls:       L - IPL                     S - Start CPU",
146 "                    E - External interrupt      P - Stop CPU",
147 "                    W - Exit Hercules           T - Restart interrupt",
148 "Storage update:     R - Enter ADDRESS to be updated",
149 "                    D - Enter DATA to be updated at ADDRESS",
150 "                    O - place DATA value at ADDRESS",
151 " ",
152 "Peripherals:        N - enter a new name for the device file assignment",
153 "                    U - send an I/O attention interrupt",
154 " ",
155 "In the display of devices, a green device letter means the device is online,",
156 "a lighted device address means the device is busy, and a green model number",
157 "means the attached file is open to the device",
158 " ",
159 "                    Press Escape to return to control panel operations",
160 "" };
161 
162 ///////////////////////////////////////////////////////////////////////
163 
164 #define MSG_SIZE     PANEL_MAX_COLS     /* Size of one message       */
165 #define MAX_MSGS     2048                /* Number of slots in buffer */
166 //#define MAX_MSGS     300                /* (for testing scrolling)   */
167 #define MSG_LINES    (cons_rows - 2)    /* #lines in message area    */
168 #define SCROLL_LINES (MSG_LINES - numkept) /* #of scrollable lines   */
169 #define CMD_SIZE     256                /* cmdline buffer size       */
170 
171 ///////////////////////////////////////////////////////////////////////
172 
173 static int   cons_rows = 0;             /* console height in lines   */
174 static int   cons_cols = 0;             /* console width in chars    */
175 static short cur_cons_row = 0;          /* current console row       */
176 static short cur_cons_col = 0;          /* current console column    */
177 static char *cons_term = NULL;          /* TERM env value            */
178 static char  cmdins  = 1;               /* 1==insert mode, 0==overlay*/
179 
180 static char  cmdline[CMD_SIZE+1];       /* Command line buffer       */
181 static int   cmdlen  = 0;               /* cmdline data len in bytes */
182 static int   cmdoff  = 0;               /* cmdline buffer cursor pos */
183 
184 static int   cursor_on_cmdline = 1;     /* bool: cursor on cmdline   */
185 static char  saved_cmdline[CMD_SIZE+1]; /* Saved command             */
186 static int   saved_cmdlen   = 0;        /* Saved cmdline data len    */
187 static int   saved_cmdoff   = 0;        /* Saved cmdline buffer pos  */
188 static short saved_cons_row = 0;        /* Saved console row         */
189 static short saved_cons_col = 0;        /* Saved console column      */
190 
191 static int   cmdcols = 0;               /* visible cmdline width cols*/
192 static int   cmdcol  = 0;               /* cols cmdline scrolled righ*/
193 static FILE *confp   = NULL;            /* Console file pointer      */
194 
195 ///////////////////////////////////////////////////////////////////////
196 
197 #define CMD_PREFIX_STR   "Command ==> " /* Keep same len as below!   */
198 #ifdef  OPTION_CMDTGT
199 #define CMD_PREFIX_STR1  "SCP ======> " /* Keep same len as above!   */
200 #define CMD_PREFIX_STR2  "PrioSCP ==> " /* Keep same len as above!   */
201 #endif // OPTION_CMDTGT
202 
203 #define CMD_PREFIX_LEN  (strlen(CMD_PREFIX_STR))
204 #define CMDLINE_ROW     ((short)(cons_rows-1))
205 #define CMDLINE_COL     ((short)(CMD_PREFIX_LEN+1))
206 
207 ///////////////////////////////////////////////////////////////////////
208 
209 #define ADJ_SCREEN_SIZE() \
210     do { \
211         int rows, cols; \
212         get_dim (&rows, &cols); \
213         if (rows != cons_rows || cols != cons_cols) { \
214             cons_rows = rows; \
215             cons_cols = cols; \
216             cmdcols = cons_cols - CMDLINE_COL; \
217             redraw_msgs = redraw_cmd = redraw_status = 1; \
218             NPDinit = 0; \
219             clr_screen(); \
220         } \
221     } while (0)
222 
223 #define ADJ_CMDCOL() /* (called after modifying cmdoff) */ \
224     do { \
225         if (cmdoff-cmdcol > cmdcols) { /* past right edge of screen */ \
226             cmdcol = cmdoff-cmdcols; \
227         } else if (cmdoff < cmdcol) { /* past left edge of screen */ \
228             cmdcol = cmdoff; \
229         } \
230     } while (0)
231 
232 #define PUTC_CMDLINE() \
233     do { \
234         ASSERT(cmdcol <= cmdlen); \
235         for (i=0; cmdcol+i < cmdlen && i < cmdcols; i++) \
236             draw_char (cmdline[cmdcol+i]); \
237     } while (0)
238 
239 ///////////////////////////////////////////////////////////////////////
240 
241 typedef struct _PANMSG      /* Panel message control block structure */
242 {
243     struct _PANMSG*     next;           /* --> next entry in chain   */
244     struct _PANMSG*     prev;           /* --> prev entry in chain   */
245     int                 msgnum;         /* msgbuf 0-relative entry#  */
246     char                msg[MSG_SIZE];  /* text of panel message     */
247 #if defined(OPTION_MSGCLR)
248     short               fg;             /* text color                */
249     short               bg;             /* screen background color   */
250 #if defined(OPTION_MSGHLD)
251     int                 keep:1;         /* sticky flag               */
252     struct timeval      expiration;     /* when to unstick if sticky */
253 #endif // defined(OPTION_MSGHLD)
254 #endif // defined(OPTION_MSGCLR)
255 }
256 PANMSG;                     /* Panel message control block structure */
257 
258 static PANMSG*  msgbuf;                 /* Circular message buffer   */
259 static PANMSG*  topmsg;                 /* message at top of screen  */
260 static PANMSG*  curmsg;                 /* newest message            */
261 static int      wrapped = 0;            /* wrapped-around flag       */
262 static int      numkept = 0;            /* count of kept messages    */
263 static int      npquiet = 0;            /* screen updating flag      */
264 
265 ///////////////////////////////////////////////////////////////////////
266 
267 static char *lmsbuf = NULL;             /* xxx                       */
268 static int   lmsndx = 0;                /* xxx                       */
269 static int   lmsnum = -1;               /* xxx                       */
270 static int   lmscnt = -1;               /* xxx                       */
271 static int   lmsmax = LOG_DEFSIZE/2;    /* xxx                       */
272 static int   keybfd = -1;               /* Keyboard file descriptor  */
273 
274 static REGS  copyregs, copysieregs;     /* Copied regs               */
275 
276 ///////////////////////////////////////////////////////////////////////
277 
278 #if defined(OPTION_MSGCLR)  /*  -- Message coloring build option --  */
279 #if defined(OPTION_MSGHLD)  /*  -- Sticky messages build option --   */
280 
281 #define KEEP_TIMEOUT_SECS   120         /* #seconds kept msgs expire */
282 static PANMSG*  keptmsgs;               /* start of keep chain       */
283 static PANMSG*  lastkept;               /* last entry in keep chain  */
284 
285 /*-------------------------------------------------------------------*/
286 /* Remove and Free a keep chain entry from the keep chain            */
287 /*-------------------------------------------------------------------*/
unkeep(PANMSG * pk)288 static void unkeep( PANMSG* pk )
289 {
290     if (pk->prev)
291         pk->prev->next = pk->next;
292     if (pk->next)
293         pk->next->prev = pk->prev;
294     if (pk == keptmsgs)
295         keptmsgs = pk->next;
296     if (pk == lastkept)
297         lastkept = pk->prev;
298     free( pk );
299     numkept--;
300 }
301 
302 /*-------------------------------------------------------------------*/
303 /* Allocate and Add a new kept message to the keep chain             */
304 /*-------------------------------------------------------------------*/
keep(PANMSG * p)305 static void keep( PANMSG* p )
306 {
307     PANMSG* pk;
308     ASSERT( p->keep );
309     pk = malloc( sizeof(PANMSG) );
310     memcpy( pk, p, sizeof(PANMSG) );
311     if (!keptmsgs)
312         keptmsgs = pk;
313     pk->next = NULL;
314     pk->prev = lastkept;
315     if (lastkept)
316         lastkept->next = pk;
317     lastkept = pk;
318     numkept++;
319     /* Must ensure we always have at least 2 scrollable lines */
320     while (SCROLL_LINES < 2)
321     {
322         /* Permanently unkeep oldest kept message */
323         msgbuf[keptmsgs->msgnum].keep = 0;
324         unkeep( keptmsgs );
325     }
326 }
327 
328 /*-------------------------------------------------------------------*/
329 /* Remove a kept message from the kept chain                         */
330 /*-------------------------------------------------------------------*/
unkeep_by_keepnum(int keepnum,int perm)331 static void unkeep_by_keepnum( int keepnum, int perm )
332 {
333     PANMSG* pk;
334     int i;
335 
336     /* Validate call */
337     if (!numkept || keepnum < 0 || keepnum > numkept-1)
338     {
339         ASSERT(FALSE);    // bad 'keepnum' passed!
340         return;
341     }
342 
343     /* Chase keep chain to find kept message to be unkept */
344     for (i=0, pk=keptmsgs; pk && i != keepnum; pk = pk->next, i++);
345 
346     /* If kept message found, unkeep it */
347     if (pk)
348     {
349         if (perm)
350         {
351             msgbuf[pk->msgnum].keep = 0;
352 
353 #if defined(_DEBUG) || defined(DEBUG)
354             msgbuf[pk->msgnum].fg = COLOR_YELLOW;
355 #endif // defined(_DEBUG) || defined(DEBUG)
356         }
357         unkeep(pk);
358     }
359 }
360 #endif // defined(OPTION_MSGHLD)
361 #endif // defined(OPTION_MSGCLR)
362 
363 #if defined(OPTION_MSGHLD)
364 /*-------------------------------------------------------------------*/
365 /* unkeep messages once expired                                      */
366 /*-------------------------------------------------------------------*/
expire_kept_msgs(int unconditional)367 void expire_kept_msgs(int unconditional)
368 {
369   struct timeval now;
370   PANMSG *pk = keptmsgs;
371   int i;
372 
373   gettimeofday(&now, NULL);
374 
375   while (pk)
376   {
377     for (i=0, pk=keptmsgs; pk; i++, pk = pk->next)
378     {
379       if (unconditional || now.tv_sec >= pk->expiration.tv_sec)
380       {
381         unkeep_by_keepnum(i,1); // remove message from chain
382         break;                  // start over again from the beginning
383       }
384     }
385   }
386 }
387 #endif // defined(OPTION_MSGHLD)
388 
389 #if defined(OPTION_MSGCLR)  /*  -- Message coloring build option --  */
390 /*-------------------------------------------------------------------*/
391 /* Get the color name from a string                                  */
392 /*-------------------------------------------------------------------*/
393 
394 #define CHECKCOLOR(s, cs, c, cc) if(!strncasecmp(s, cs, sizeof(cs) - 1)) { *c = cc; return(sizeof(cs) - 1); }
395 
get_color(char * string,short * color)396 int get_color(char *string, short *color)
397 {
398        CHECKCOLOR(string, "black",        color, COLOR_BLACK)
399   else CHECKCOLOR(string, "cyan",         color, COLOR_CYAN)
400   else CHECKCOLOR(string, "blue",         color, COLOR_BLUE)
401   else CHECKCOLOR(string, "darkgrey",     color, COLOR_DARK_GREY)
402   else CHECKCOLOR(string, "green",        color, COLOR_GREEN)
403   else CHECKCOLOR(string, "lightblue",    color, COLOR_LIGHT_BLUE)
404   else CHECKCOLOR(string, "lightcyan",    color, COLOR_LIGHT_CYAN)
405   else CHECKCOLOR(string, "lightgreen",   color, COLOR_LIGHT_GREEN)
406   else CHECKCOLOR(string, "lightgrey",    color, COLOR_LIGHT_GREY)
407   else CHECKCOLOR(string, "lightmagenta", color, COLOR_LIGHT_MAGENTA)
408   else CHECKCOLOR(string, "lightred",     color, COLOR_LIGHT_RED)
409   else CHECKCOLOR(string, "lightyellow",  color, COLOR_LIGHT_YELLOW)
410   else CHECKCOLOR(string, "magenta",      color, COLOR_MAGENTA)
411   else CHECKCOLOR(string, "red",          color, COLOR_RED)
412   else CHECKCOLOR(string, "white",        color, COLOR_WHITE)
413   else CHECKCOLOR(string, "yellow",       color, COLOR_YELLOW)
414   else return(0);
415 }
416 
417 /*-------------------------------------------------------------------*/
418 /* Read, process and remove the "<pnl...>" colorizing message prefix */
419 /* Syntax:                                                           */
420 /*   <pnl,token,...>                                                 */
421 /*     Mandatory prefix "<pnl,"                                      */
422 /*     followed by one or more tokens separated by ","               */
423 /*     ending with a ">"                                             */
424 /* Valid tokens:                                                     */
425 /*  color(fg, bg)   specifies the message's color                    */
426 /*  keep            keeps message on screen until removed            */
427 /*-------------------------------------------------------------------*/
colormsg(PANMSG * p)428 void colormsg(PANMSG *p)
429 {
430   int  i = 0;           // current message text index
431   int  len;             // length of color-name token
432 
433   if(!strncasecmp(p->msg, "<pnl", 4))
434   {
435     // examine "<pnl...>" panel command(s)
436     i += 4;
437     while(p->msg[i] == ',')
438     {
439       i += 1; // skip ,
440       if(!strncasecmp(&p->msg[i], "color(", 6))
441       {
442         // inspect color command
443         i += 6; // skip color(
444         len = get_color(&p->msg[i], &p->fg);
445         if(!len)
446           break; // no valid color found
447         i += len; // skip colorname
448         if(p->msg[i] != ',')
449           break; // no ,
450         i++; // skip ,
451         len = get_color(&p->msg[i], &p->bg);
452         if(!len)
453           break; // no valid color found
454         i += len; // skip colorname
455         if(p->msg[i] != ')')
456           break; // no )
457         i++; // skip )
458       }
459       else if(!strncasecmp(&p->msg[i], "keep", 4))
460       {
461 #if defined(OPTION_MSGHLD)
462         p->keep = 1;
463         gettimeofday(&p->expiration, NULL);
464         p->expiration.tv_sec += sysblk.keep_timeout_secs;
465 #endif // defined(OPTION_MSGHLD)
466         i += 4; // skip keep
467       }
468       else
469         break; // rubbish
470     }
471     if(p->msg[i] == '>')
472     {
473       // Remove "<pnl...>" string from message
474       i += 1;
475       memmove(p->msg, &p->msg[i], MSG_SIZE - i);
476       memset(&p->msg[MSG_SIZE - i], SPACE, i);
477       return;
478     }
479   }
480 
481   /* rubbish or no panel command */
482   p->fg = COLOR_DEFAULT_FG;
483   p->bg = COLOR_DEFAULT_BG;
484 #if defined(OPTION_MSGHLD)
485   p->keep = 0;
486 #endif // defined(OPTION_MSGHLD)
487 }
488 #endif // defined(OPTION_MSGCLR)
489 
490 /*-------------------------------------------------------------------*/
491 /* Screen manipulation primitives                                    */
492 /*-------------------------------------------------------------------*/
493 
beep()494 static void beep()
495 {
496     console_beep( confp );
497 }
498 
oldest_msg()499 static PANMSG* oldest_msg()
500 {
501     return (wrapped) ? curmsg->next : msgbuf;
502 }
503 
newest_msg()504 static PANMSG* newest_msg()
505 {
506     return curmsg;
507 }
508 
lines_scrolled()509 static int lines_scrolled()
510 {
511     /* return # of lines 'up' from current line that we're scrolled. */
512     if (topmsg->msgnum <= curmsg->msgnum)
513         return curmsg->msgnum - topmsg->msgnum;
514     return MAX_MSGS - (topmsg->msgnum - curmsg->msgnum);
515 }
516 
visible_lines()517 static int visible_lines()
518 {
519     return (lines_scrolled() + 1);
520 }
521 
is_currline_visible()522 static int is_currline_visible()
523 {
524     return (visible_lines() <= SCROLL_LINES);
525 }
526 
lines_remaining()527 static int lines_remaining()
528 {
529     return (SCROLL_LINES - visible_lines());
530 }
531 
scroll_up_lines(int numlines,int doexpire)532 static void scroll_up_lines( int numlines, int doexpire )
533 {
534     int i;
535 
536 #if defined(OPTION_MSGHLD)
537     if (doexpire)
538         expire_kept_msgs(0);
539 #else
540     UNREFERENCED(doexpire);
541 #endif // defined(OPTION_MSGHLD)
542 
543     for (i=0; i < numlines && topmsg != oldest_msg(); i++)
544     {
545         topmsg = topmsg->prev;
546 
547 #if defined(OPTION_MSGHLD)
548         // If new topmsg is simply the last entry in the keep chain
549         // then we didn't really backup a line (all we did was move
550         // our topmsg ptr), so if that's the case then we need to
551         // continue backing up until we reach a non-kept message.
552         // Only then is the screen actually scrolled up one line.
553 
554         while (1
555             && topmsg->keep
556             && lastkept
557             && lastkept->msgnum == topmsg->msgnum
558         )
559         {
560             unkeep( lastkept );
561             if (topmsg == oldest_msg())
562                 break;
563             topmsg = topmsg->prev;
564         }
565 #endif // defined(OPTION_MSGHLD)
566     }
567 }
568 
scroll_down_lines(int numlines,int doexpire)569 static void scroll_down_lines( int numlines, int doexpire )
570 {
571     int i;
572 
573 #if defined(OPTION_MSGHLD)
574     if (doexpire)
575         expire_kept_msgs(0);
576 #else
577     UNREFERENCED(doexpire);
578 #endif // defined(OPTION_MSGHLD)
579 
580     for (i=0; i < numlines && topmsg != newest_msg(); i++)
581     {
582 #if defined(OPTION_MSGHLD)
583         // If the topmsg should be kept and is not already in our
584         // keep chain, then adding it to our keep chain before
585         // setting topmsg to the next entry does not really scroll
586         // the screen any (all it does is move the topmsg ptr),
587         // so if that's the case then we need to keep doing that
588         // until we eventually find the next non-kept message.
589         // Only then is the screen really scrolled down one line.
590 
591         while (1
592             && topmsg->keep
593             && (!lastkept || topmsg->msgnum != lastkept->msgnum)
594         )
595         {
596             keep( topmsg );
597             topmsg = topmsg->next;
598             if (topmsg == newest_msg())
599                 break;
600         }
601 #endif // defined(OPTION_MSGHLD)
602         if (topmsg != newest_msg())
603             topmsg = topmsg->next;
604     }
605 }
606 
page_up(int doexpire)607 static void page_up( int doexpire )
608 {
609 #if defined(OPTION_MSGHLD)
610     if (doexpire)
611         expire_kept_msgs(0);
612 #else
613     UNREFERENCED(doexpire);
614 #endif // defined(OPTION_MSGHLD)
615     scroll_up_lines( SCROLL_LINES - 1, 0 );
616 }
page_down(int doexpire)617 static void page_down( int doexpire )
618 {
619 #if defined(OPTION_MSGHLD)
620     if (doexpire)
621         expire_kept_msgs(0);
622 #else
623     UNREFERENCED(doexpire);
624 #endif // defined(OPTION_MSGHLD)
625     scroll_down_lines( SCROLL_LINES - 1, 0 );
626 }
627 
scroll_to_top_line(int doexpire)628 static void scroll_to_top_line( int doexpire )
629 {
630 #if defined(OPTION_MSGHLD)
631     if (doexpire)
632         expire_kept_msgs(0);
633 #else
634     UNREFERENCED(doexpire);
635 #endif // defined(OPTION_MSGHLD)
636     topmsg = oldest_msg();
637 #if defined(OPTION_MSGHLD)
638     while (keptmsgs)
639         unkeep( keptmsgs );
640 #endif // defined(OPTION_MSGHLD)
641 }
642 
scroll_to_bottom_line(int doexpire)643 static void scroll_to_bottom_line( int doexpire )
644 {
645 #if defined(OPTION_MSGHLD)
646     if (doexpire)
647         expire_kept_msgs(0);
648 #else
649     UNREFERENCED(doexpire);
650 #endif // defined(OPTION_MSGHLD)
651     while (topmsg != newest_msg())
652         scroll_down_lines( 1, 0 );
653 }
654 
scroll_to_bottom_screen(int doexpire)655 static void scroll_to_bottom_screen( int doexpire )
656 {
657 #if defined(OPTION_MSGHLD)
658     if (doexpire)
659         expire_kept_msgs(0);
660 #else
661     UNREFERENCED(doexpire);
662 #endif // defined(OPTION_MSGHLD)
663     scroll_to_bottom_line( 0 );
664     page_up( 0 );
665 }
666 
do_panel_command(void * cmd)667 static void do_panel_command( void* cmd )
668 {
669     if (!is_currline_visible())
670         scroll_to_bottom_screen( 1 );
671     if (cmd != (void*)cmdline)
672         strlcpy( cmdline, cmd, sizeof(cmdline) );
673     panel_command( cmdline );
674     cmdline[0] = '\0';
675     cmdlen = 0;
676     cmdoff = 0;
677     ADJ_CMDCOL();
678 }
679 
do_prev_history()680 static void do_prev_history()
681 {
682     if (history_prev() != -1)
683     {
684         strcpy(cmdline, historyCmdLine);
685         cmdlen = strlen(cmdline);
686         cmdoff = cmdlen < cmdcols ? cmdlen : 0;
687         ADJ_CMDCOL();
688     }
689 }
690 
do_next_history()691 static void do_next_history()
692 {
693     if (history_next() != -1)
694     {
695         strcpy(cmdline, historyCmdLine);
696         cmdlen = strlen(cmdline);
697         cmdoff = cmdlen < cmdcols ? cmdlen : 0;
698         ADJ_CMDCOL();
699     }
700 }
701 
clr_screen()702 static void clr_screen ()
703 {
704     clear_screen (confp);
705 }
706 
get_dim(int * y,int * x)707 static void get_dim (int *y, int *x)
708 {
709     get_console_dim( confp, y, x);
710     if (*y > PANEL_MAX_ROWS)
711         *y = PANEL_MAX_ROWS;
712     if (*x > PANEL_MAX_COLS)
713         *x = PANEL_MAX_COLS;
714 #if defined(WIN32) && !defined( _MSVC_ )
715    /* If running from a cygwin command prompt we do
716      * better with one less row.
717      */
718     if (!cons_term || strcmp(cons_term, "xterm"))
719         (*y)--;
720 #endif // defined(WIN32) && !defined( _MSVC_ )
721 }
722 
723 #if defined(OPTION_EXTCURS)
get_keepnum_by_row(int row)724 static int get_keepnum_by_row( int row )
725 {
726     // PROGRAMMING NOTE: right now all of our kept messages are
727     // always placed at the very top of the screen (starting on
728     // line 1), but should we at some point in the future decide
729     // to use the very top line of the screen for something else
730     // (such as a title or status line for example), then all we
731     // need to do is modify the below variable and the code then
732     // adjusts itself automatically. (I try to avoid hard-coded
733     // constants whenever possible). -- Fish
734 
735    static int keep_beg_row = 1;  // screen 1-relative line# of first kept msg
736 
737     if (0
738         || row <  keep_beg_row
739         || row > (keep_beg_row + numkept - 1)
740     )
741         return -1;
742 
743     return (row - keep_beg_row);
744 }
745 #endif /*defined(OPTION_EXTCURS)*/
746 
set_color(short fg,short bg)747 static void set_color (short fg, short bg)
748 {
749     set_screen_color (confp, fg, bg);
750 }
751 
set_pos(short y,short x)752 static void set_pos (short y, short x)
753 {
754     cur_cons_row = y;
755     cur_cons_col = x;
756     y = y < 1 ? 1 : y > cons_rows ? cons_rows : y;
757     x = x < 1 ? 1 : x > cons_cols ? cons_cols : x;
758     set_screen_pos (confp, y, x);
759 }
760 
is_cursor_on_cmdline()761 static int is_cursor_on_cmdline()
762 {
763 #if defined(OPTION_EXTCURS)
764     get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
765     cursor_on_cmdline =
766     (1
767         && cur_cons_row == CMDLINE_ROW
768         && cur_cons_col >= CMDLINE_COL
769         && cur_cons_col <= CMDLINE_COL + cmdcols
770     );
771 #else // !defined(OPTION_EXTCURS)
772     cursor_on_cmdline = 1;
773 #endif // defined(OPTION_EXTCURS)
774     return cursor_on_cmdline;
775 }
776 
cursor_cmdline_home()777 static void cursor_cmdline_home()
778 {
779     cmdoff = 0;
780     ADJ_CMDCOL();
781     set_pos( CMDLINE_ROW, CMDLINE_COL );
782 }
783 
cursor_cmdline_end()784 static void cursor_cmdline_end()
785 {
786     cmdoff = cmdlen;
787     ADJ_CMDCOL();
788     set_pos( CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol );
789 }
790 
save_command_line()791 static void save_command_line()
792 {
793     memcpy( saved_cmdline, cmdline, sizeof(saved_cmdline) );
794     saved_cmdlen = cmdlen;
795     saved_cmdoff = cmdoff;
796     saved_cons_row = cur_cons_row;
797     saved_cons_col = cur_cons_col;
798 }
799 
restore_command_line()800 static void restore_command_line()
801 {
802     memcpy( cmdline, saved_cmdline, sizeof(cmdline) );
803     cmdlen = saved_cmdlen;
804     cmdoff = saved_cmdoff;
805     cur_cons_row = saved_cons_row;
806     cur_cons_col = saved_cons_col;
807 }
808 
draw_text(char * text)809 static void draw_text (char *text)
810 {
811     int   len;
812     char *short_text;
813 
814     if (cur_cons_row < 1 || cur_cons_row > cons_rows
815      || cur_cons_col < 1 || cur_cons_col > cons_cols)
816         return;
817     len = strlen(text);
818     if ((cur_cons_col + len - 1) <= cons_cols)
819         fprintf (confp, "%s", text);
820     else
821     {
822         len = cons_cols - cur_cons_col + 1;
823         if ((short_text = strdup(text)) == NULL)
824             return;
825         short_text[len] = '\0';
826         fprintf (confp, "%s", short_text);
827         free (short_text);
828     }
829     cur_cons_col += len;
830 }
831 
write_text(char * text,int size)832 static void write_text (char *text, int size)
833 {
834     if (cur_cons_row < 1 || cur_cons_row > cons_rows
835      || cur_cons_col < 1 || cur_cons_col > cons_cols)
836         return;
837     if (cons_cols - cur_cons_col + 1 < size)
838         size = cons_cols - cur_cons_col + 1;
839     fwrite (text, size, 1, confp);
840     cur_cons_col += size;
841 }
842 
draw_char(int c)843 static void draw_char (int c)
844 {
845     if (cur_cons_row < 1 || cur_cons_row > cons_rows
846      || cur_cons_col < 1 || cur_cons_col > cons_cols)
847         return;
848     fputc (c, confp);
849     cur_cons_col++;
850 }
851 
draw_fw(U32 fw)852 static void draw_fw (U32 fw)
853 {
854     char buf[9];
855     sprintf (buf, "%8.8X", fw);
856     draw_text (buf);
857 }
858 
draw_dw(U64 dw)859 static void draw_dw (U64 dw)
860 {
861     char buf[17];
862     sprintf (buf, "%16.16"I64_FMT"X", dw);
863     draw_text (buf);
864 }
865 
fill_text(char c,short x)866 static void fill_text (char c, short x)
867 {
868     char buf[PANEL_MAX_COLS+1];
869     int  len;
870 
871     if (x > PANEL_MAX_COLS) x = PANEL_MAX_COLS;
872     len = x + 1 - cur_cons_col;
873     if (len <= 0) return;
874     memset (buf, c, len);
875     buf[len] = '\0';
876     draw_text (buf);
877 }
878 
draw_button(short bg,short fg,short hfg,char * left,char * mid,char * right)879 static void draw_button (short bg, short fg, short hfg, char *left, char *mid, char *right)
880 {
881     set_color (fg, bg);
882     draw_text (left);
883     set_color (hfg, bg);
884     draw_text (mid);
885     set_color (fg, bg);
886     draw_text (right);
887 }
888 
set_console_title()889 static void set_console_title ()
890 {
891     if (!sysblk.pantitle) return;
892 
893   #if defined( _MSVC_ )
894     w32_set_console_title(sysblk.pantitle);
895   #else /*!defined(_MSVC_) */
896     /* For Unix systems we set the window title by sending a special
897        escape sequence (depends on terminal type) to the console.
898        See http://www.faqs.org/docs/Linux-mini/Xterm-Title.html */
899     if (!cons_term) return;
900     if (strcmp(cons_term,"xterm")==0
901      || strcmp(cons_term,"rxvt")==0
902      || strcmp(cons_term,"dtterm")==0
903      || strcmp(cons_term,"screen")==0)
904     {
905         fprintf(confp,"%c]0;%s%c",'\033',sysblk.pantitle,'\007');
906     }
907   #endif /*!defined(_MSVC_) */
908 }
909 
910 /*=NP================================================================*/
911 /*  Initialize the NP data                                           */
912 /*===================================================================*/
913 
NP_init()914 static void NP_init()
915 {
916     NPdataentry = 0;
917     strcpy(NPprompt1, "");
918     strcpy(NPprompt2, "");
919 }
920 
921 /*=NP================================================================*/
922 /*  This draws the initial screen template                           */
923 /*===================================================================*/
924 
NP_screen_redraw(REGS * regs)925 static void NP_screen_redraw (REGS *regs)
926 {
927     int  i, line;
928     char buf[1024];
929 
930     /* Force all data to be redrawn */
931     NPcpunum_valid   = NPcpupct_valid   = NPpsw_valid  =
932     NPpswstate_valid = NPregs_valid     = NPaddr_valid =
933     NPdata_valid     =
934     NPdevices_valid  = NPcpugraph_valid = 0;
935 #if defined(OPTION_MIPS_COUNTING)
936     NPmips_valid     = NPsios_valid     = 0;
937 #endif /*defined(OPTION_MIPS_COUNTING)*/
938 
939 #if defined(_FEATURE_SIE)
940     if(regs->sie_active)
941         regs = regs->guestregs;
942 #endif /*defined(_FEATURE_SIE)*/
943 
944     /*
945      * Draw the static parts of the NP screen
946      */
947     set_color (COLOR_LIGHT_GREY, COLOR_BLACK );
948     clr_screen ();
949 
950     /* Line 1 - title line */
951     set_color (COLOR_WHITE, COLOR_BLUE );
952     set_pos   (1, 1);
953     draw_text ("  Hercules  CPU    :    %");
954     fill_text (' ', 30);
955     draw_text ((char *)get_arch_mode_string(NULL));
956     fill_text (' ', 38);
957     set_color (COLOR_LIGHT_GREY, COLOR_BLUE );
958     draw_text ("| ");
959     set_color (COLOR_WHITE, COLOR_BLUE );
960 
961     /* Center "Peripherals" on the right-hand-side */
962     if (cons_cols > 52)
963         fill_text (' ', 40 + (cons_cols - 52) / 2);
964     draw_text ("Peripherals");
965     fill_text (' ', (short)cons_cols);
966 
967     /* Line 2 - peripheral headings */
968     set_pos (2, 41);
969     set_color (COLOR_WHITE, COLOR_BLACK);
970     draw_char ('U');
971     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
972     draw_text(" Addr Modl Type Assig");
973     set_color (COLOR_WHITE, COLOR_BLACK);
974     draw_char ('n');
975     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
976     draw_text("ment");
977 
978     /* 4th line - PSW */
979     NPpswmode = (regs->arch_mode == ARCH_900);
980     NPpswzhost =
981 #if defined(_FEATURE_SIE)
982                  !NPpswmode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900;
983 #else
984                  0;
985 #endif /*defined(_FEATURE_SIE)*/
986     set_pos (4, NPpswmode || NPpswzhost ? 19 : 10);
987     draw_text ("PSW");
988 
989     /* Lines 6 .. 13 : register area */
990     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
991     NPregmode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1));
992     NPregzhost =
993 #if defined(_FEATURE_SIE)
994                  (regs->arch_mode != ARCH_900
995                && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900
996                && (NPregdisp == 0 || NPregdisp == 1));
997 #else
998                  0;
999 #endif /*defined(_FEATURE_SIE)*/
1000     if (NPregmode == 1 || NPregzhost)
1001     {
1002         for (i = 0; i < 8; i++)
1003         {
1004             set_pos (i+6, 1);
1005             draw_text (NPregnum64[i*2]);
1006             set_pos (i+6, 20);
1007             draw_text (NPregnum64[i*2+1]);
1008         }
1009     }
1010     else
1011     {
1012         for (i = 0; i < 4; i++)
1013         {
1014             set_pos (i*2+7,9);
1015             draw_text (NPregnum[i*4]);
1016             set_pos (i*2+7,18);
1017             draw_text (NPregnum[i*4+1]);
1018             set_pos (i*2+7,27);
1019             draw_text (NPregnum[i*4+2]);
1020             set_pos (i*2+7,36);
1021             draw_text (NPregnum[i*4+3]);
1022         }
1023     }
1024 
1025     /* Line 14 : register selection */
1026     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1027     set_pos (14, 6);
1028     draw_text ("GPR");
1029     set_pos (14, 14);
1030     draw_text ("CR");
1031     set_pos (14, 22);
1032     draw_text ("AR");
1033     set_pos (14, 30);
1034     draw_text ("FPR");
1035 
1036     /* Line 16 .. 17 : Address and data */
1037     set_pos (16, 2);
1038     draw_text ("ADD");
1039     set_color (COLOR_WHITE, COLOR_BLACK);
1040     draw_char ('R');
1041     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1042     draw_text ("ESS:");
1043     set_pos (16, 22);
1044     set_color (COLOR_WHITE, COLOR_BLACK);
1045     draw_char ('D');
1046     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1047     draw_text ("ATA:");
1048 
1049     /* Line 18 : separator */
1050     set_pos (18, 1);
1051     fill_text ('-', 38);
1052 
1053     /* Lines 19 .. 23 : buttons */
1054 
1055     set_pos (19, 16);
1056     draw_button(COLOR_BLUE,  COLOR_LIGHT_GREY, COLOR_WHITE,  " ST", "O", " "  );
1057     set_pos (19, 24);
1058     draw_button(COLOR_BLUE,  COLOR_LIGHT_GREY, COLOR_WHITE,  " D",  "I", "S " );
1059     set_pos (19, 32);
1060     draw_button(COLOR_BLUE,  COLOR_LIGHT_GREY, COLOR_WHITE,  " RS", "T", " "  );
1061 
1062 #if defined(OPTION_MIPS_COUNTING)
1063     set_pos (20, 3);
1064     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1065     draw_text ("MIPS");
1066     set_pos (20, 9);
1067     draw_text ("SIO/s");
1068 #endif /*defined(OPTION_MIPS_COUNTING)*/
1069 
1070     set_pos (22, 2);
1071     draw_button(COLOR_GREEN, COLOR_LIGHT_GREY, COLOR_WHITE,  " ",   "S", "TR ");
1072     set_pos (22, 9);
1073     draw_button(COLOR_RED,   COLOR_LIGHT_GREY, COLOR_WHITE,  " ST", "P", " "  );
1074     set_pos (22, 16);
1075     draw_button(COLOR_BLUE,  COLOR_LIGHT_GREY, COLOR_WHITE,  " ",   "E", "XT ");
1076     set_pos (22, 24);
1077     draw_button(COLOR_BLUE,  COLOR_LIGHT_GREY, COLOR_WHITE,  " IP", "L", " "  );
1078     set_pos (22, 32);
1079     draw_button(COLOR_RED,   COLOR_LIGHT_GREY, COLOR_WHITE,  " P",  "W", "R " );
1080 
1081     set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1082 
1083     /* CPU busy graph */
1084     line = 24;
1085     NPcpugraph_ncpu = MIN(cons_rows - line - 2, HI_CPU);
1086     if (HI_CPU > 0)
1087     {
1088         NPcpugraph = 1;
1089         NPcpugraph_valid = 0;
1090         set_pos (line++, 1);
1091         fill_text ('-', 38);
1092         set_pos (line++, 1);
1093         draw_text ("CPU");
1094         for (i = 0; i < NPcpugraph_ncpu; i++)
1095         {
1096             sprintf (buf, "%02X  ", i);
1097             set_pos (line++, 1);
1098             draw_text (buf);
1099         }
1100     }
1101     else
1102         NPcpugraph = 0;
1103 
1104     /* Vertical separators */
1105     for (i = 2; i <= cons_rows; i++)
1106     {
1107         set_pos (i , 39);
1108         draw_char ('|');
1109     }
1110 
1111     /* Last line : horizontal separator */
1112     if (cons_rows >= 24)
1113     {
1114         set_pos (cons_rows, 1);
1115         fill_text ('-', 38);
1116         draw_char ('|');
1117         fill_text ('-', cons_cols);
1118     }
1119 
1120     /* positions the cursor */
1121     set_pos (cons_rows, cons_cols);
1122 }
1123 
1124 /*=NP================================================================*/
1125 /*  This refreshes the screen with new data every cycle              */
1126 /*===================================================================*/
1127 
NP_update(REGS * regs)1128 static void NP_update(REGS *regs)
1129 {
1130     int     i, n;
1131     int     mode, zhost;
1132     QWORD   curpsw;
1133     U32     addr, aaddr;
1134     DEVBLK *dev;
1135     int     online, busy, open;
1136     char   *devclass;
1137     char    devnam[128];
1138     char    buf[1024];
1139 
1140     if (NPhelpup == 1)
1141     {
1142         if (NPhelpdown == 1)
1143         {
1144              NP_init();
1145              NP_screen_redraw(regs);
1146              NPhelpup = 0;
1147              NPhelpdown = 0;
1148              NPhelppaint = 1;
1149         }
1150         else
1151         {
1152             if (NPhelppaint)
1153             {
1154                 set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1155                 clr_screen ();
1156                 for (i = 0; strcmp(NPhelp[i], ""); i++)
1157                 {
1158                     set_pos (i+1, 1);
1159                     draw_text (NPhelp[i]);
1160                 }
1161                 NPhelppaint = 0;
1162             }
1163             return;
1164         }
1165     }
1166 
1167 #if defined(_FEATURE_SIE)
1168     if(SIE_MODE(regs))
1169         regs = regs->hostregs;
1170 #endif /*defined(_FEATURE_SIE)*/
1171 
1172     /* line 1 : cpu number and percent busy */
1173     if (!NPcpunum_valid || NPcpunum != regs->cpuad)
1174     {
1175         set_color (COLOR_WHITE, COLOR_BLUE);
1176         set_pos (1, 16);
1177         sprintf (buf, "%4.4X:",regs->cpuad);
1178         draw_text (buf);
1179         NPcpunum_valid = 1;
1180         NPcpunum = regs->cpuad;
1181     }
1182 
1183 #if defined(OPTION_MIPS_COUNTING)
1184     if (!NPcpupct_valid || NPcpupct != regs->cpupct)
1185     {
1186         set_color (COLOR_WHITE, COLOR_BLUE);
1187         set_pos (1, 22);
1188         sprintf(buf, "%3d", regs->cpupct);
1189         draw_text (buf);
1190         NPcpupct_valid = 1;
1191         NPcpupct = regs->cpupct;
1192     }
1193 #else // !defined(OPTION_MIPS_COUNTING)
1194     if (!NPcpupct_valid)
1195     {
1196         set_color (COLOR_WHITE, COLOR_BLUE);
1197         set_pos (1, 21);
1198         draw_text ("     ");
1199         NPcpupct_valid = 1;
1200     }
1201 #endif /*defined(OPTION_MIPS_COUNTING)*/
1202 
1203 #if defined(_FEATURE_SIE)
1204     if(regs->sie_active)
1205         regs = regs->guestregs;
1206 #endif /*defined(_FEATURE_SIE)*/
1207 
1208     mode = (regs->arch_mode == ARCH_900);
1209     zhost =
1210 #if defined(_FEATURE_SIE)
1211             !mode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900;
1212 #else // !defined(_FEATURE_SIE)
1213             0;
1214 #endif // defined(_FEATURE_SIE)
1215 
1216     /* Redraw the psw template if the mode changed */
1217     if (NPpswmode != mode || NPpswzhost != zhost)
1218     {
1219         NPpswmode = mode;
1220         NPpswzhost = zhost;
1221         NPpsw_valid = NPpswstate_valid = 0;
1222         set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1223         set_pos (3, 1);
1224         fill_text (' ',38);
1225         set_pos (4, 1);
1226         fill_text (' ', 38);
1227         set_pos (4, NPpswmode || NPpswzhost ? 19 : 10);
1228         draw_text ("PSW");
1229     }
1230 
1231     /* Display the psw */
1232     memset (curpsw, 0, sizeof(QWORD));
1233     copy_psw (regs, curpsw);
1234     if (!NPpsw_valid || memcmp(NPpsw, curpsw, sizeof(QWORD)))
1235     {
1236         set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1237         set_pos (3, 3);
1238         if (mode)
1239         {
1240             draw_dw (fetch_dw(curpsw));
1241             set_pos (3, 22);
1242             draw_dw (fetch_dw(curpsw+8));
1243         }
1244         else if (zhost)
1245         {
1246             draw_fw (fetch_fw(curpsw));
1247 //          draw_fw (0);
1248             draw_fw (fetch_fw(curpsw+4)); /* *JJ */
1249             set_pos (3, 22);
1250 //          draw_fw (fetch_fw(curpsw+4) & 0x80000000 ? 0x80000000 : 0);
1251 //          draw_fw (fetch_fw(curpsw+4) & 0x7fffffff);
1252             draw_text("----------------"); /* *JJ */
1253         }
1254         else
1255         {
1256             draw_fw (fetch_fw(curpsw));
1257             set_pos (3, 12);
1258             draw_fw (fetch_fw(curpsw+4));
1259         }
1260         NPpsw_valid = 1;
1261         memcpy (NPpsw, curpsw, sizeof(QWORD));
1262     }
1263 
1264     /* Display psw state */
1265     sprintf (buf, "%2d%c%c%c%c%c%c%c%c",
1266                   regs->psw.amode64                  ? 64  :
1267                   regs->psw.amode                    ? 31  : 24,
1268                   regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.',
1269                   sysblk.inststep                    ? 'T' : '.',
1270                   WAITSTATE (&regs->psw)             ? 'W' : '.',
1271                   regs->loadstate                    ? 'L' : '.',
1272                   regs->checkstop                    ? 'C' : '.',
1273                   PROBSTATE(&regs->psw)              ? 'P' : '.',
1274                   SIE_MODE(regs)                     ? 'S' : '.',
1275                   mode                               ? 'Z' : '.');
1276     if (!NPpswstate_valid || strcmp(NPpswstate, buf))
1277     {
1278         set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK );
1279         set_pos (mode || zhost ? 4 : 3, 28);
1280         draw_text (buf);
1281         NPpswstate_valid = 1;
1282         strcpy (NPpswstate, buf);
1283     }
1284 
1285     /* Redraw the register template if the regmode switched */
1286     mode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1));
1287     zhost =
1288 #if defined(_FEATURE_SIE)
1289             (regs->arch_mode != ARCH_900
1290           && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900
1291           && (NPregdisp == 0 || NPregdisp == 1));
1292 #else // !defined(_FEATURE_SIE)
1293                  0;
1294 #endif /*defined(_FEATURE_SIE)*/
1295     if (NPregmode != mode || NPregzhost != zhost)
1296     {
1297         NPregmode = mode;
1298         NPregzhost = zhost;
1299         NPregs_valid = 0;
1300         set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1301         if (NPregmode || NPregzhost)
1302         {
1303             /* 64 bit registers */
1304             for (i = 0; i < 8; i++)
1305             {
1306                 set_pos (i+6, 1);
1307                 fill_text (' ', 38);
1308                 set_pos (i+6, 1);
1309                 draw_text (NPregnum64[i*2]);
1310                 set_pos (i+6, 20);
1311                 draw_text (NPregnum64[i*2+1]);
1312             }
1313         }
1314         else
1315         {
1316             /* 32 bit registers */
1317             for (i = 0; i < 4; i++)
1318             {
1319                 set_pos (i*2+6,1);
1320                 fill_text (' ', 38);
1321                 set_pos (i*2+7,1);
1322                 fill_text (' ', 38);
1323                 set_pos (i*2+7,9);
1324                 draw_text (NPregnum[i*4]);
1325                 set_pos (i*2+7,18);
1326                 draw_text (NPregnum[i*4+1]);
1327                 set_pos (i*2+7,27);
1328                 draw_text (NPregnum[i*4+2]);
1329                 set_pos (i*2+7,36);
1330                 draw_text (NPregnum[i*4+3]);
1331             }
1332         }
1333     }
1334 
1335     /* Display register values */
1336     set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK );
1337     if (NPregmode)
1338     {
1339         /* 64 bit registers */
1340         for (i = 0; i < 16; i++)
1341         {
1342             switch (NPregdisp) {
1343             case 0:
1344                 if (!NPregs_valid || NPregs64[i] != regs->GR_G(i))
1345                 {
1346                     set_pos (6 + i/2, 3 + (i%2)*19);
1347                     draw_dw (regs->GR_G(i));
1348                     NPregs64[i] = regs->GR_G(i);
1349                 }
1350                 break;
1351             case 1:
1352                 if (!NPregs_valid || NPregs64[i] != regs->CR_G(i))
1353                 {
1354                     set_pos (6 + i/2, 3 + (i%2)*19);
1355                     draw_dw (regs->CR_G(i));
1356                     NPregs64[i] = regs->CR_G(i);
1357                 }
1358                 break;
1359             }
1360         }
1361     }
1362     else if (NPregzhost)
1363     {
1364         /* 32 bit registers on 64 bit template */
1365         for (i = 0; i < 16; i++)
1366         {
1367             switch (NPregdisp) {
1368             case 0:
1369                 if (!NPregs_valid || NPregs[i] != regs->GR_L(i))
1370                 {
1371                     set_pos (6 + i/2, 3 + (i%2)*19);
1372 //                  draw_fw (0);
1373                     draw_text("--------");
1374                     draw_fw (regs->GR_L(i));
1375                     NPregs[i] = regs->GR_L(i);
1376                 }
1377                 break;
1378             case 1:
1379                 if (!NPregs_valid || NPregs[i] != regs->CR_L(i))
1380                 {
1381                     set_pos (6 + i/2, 3 + (i%2)*19);
1382 //                  draw_fw (0);
1383                     draw_text("--------");
1384                     draw_fw (regs->CR_L(i));
1385                     NPregs[i] = regs->CR_L(i);
1386                 }
1387                 break;
1388             }
1389         }
1390     }
1391     else
1392     {
1393         /* 32 bit registers */
1394         addr = NPaddress;
1395         for (i = 0; i < 16; i++)
1396         {
1397             switch (NPregdisp) {
1398             default:
1399             case 0:
1400                 if (!NPregs_valid || NPregs[i] != regs->GR_L(i))
1401                 {
1402                     set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1403                     draw_fw (regs->GR_L(i));
1404                     NPregs[i] = regs->GR_L(i);
1405                 }
1406                 break;
1407             case 1:
1408                 if (!NPregs_valid || NPregs[i] != regs->CR_L(i))
1409                 {
1410                     set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1411                     draw_fw (regs->CR_L(i));
1412                     NPregs[i] = regs->CR_L(i);
1413                 }
1414                 break;
1415             case 2:
1416                 if (!NPregs_valid || NPregs[i] != regs->AR(i))
1417                 {
1418                     set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1419                     draw_fw (regs->AR(i));
1420                     NPregs[i] = regs->AR(i);
1421                 }
1422                 break;
1423             case 3:
1424                 if (!NPregs_valid || NPregs[i] != regs->fpr[i])
1425                 {
1426                     set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1427                     draw_fw (regs->fpr[i]);
1428                     NPregs[i] = regs->fpr[i];
1429                 }
1430                 break;
1431             case 4:
1432                 aaddr = APPLY_PREFIXING (addr, regs->PX);
1433                 addr += 4;
1434                 if (aaddr + 3 > regs->mainlim)
1435                     break;
1436                 if (!NPregs_valid || NPregs[i] != fetch_fw(regs->mainstor + aaddr))
1437                 {
1438                     set_pos (6 + (i/4)*2, 3 + (i%4)*9);
1439                     draw_fw (fetch_fw(regs->mainstor + aaddr));
1440                     NPregs[i] = fetch_fw(regs->mainstor + aaddr);
1441                 }
1442                 break;
1443             }
1444         }
1445     }
1446 
1447     /* Update register selection indicator */
1448     if (!NPregs_valid)
1449     {
1450         set_pos (14, 6);
1451         set_color (NPregdisp == 0 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1452         draw_char ('G');
1453 
1454         set_pos (14, 14);
1455         set_color (NPregdisp == 1 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1456         draw_char ('C');
1457 
1458         set_pos (14, 22);
1459         set_color (NPregdisp == 2 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1460         draw_char ('A');
1461 
1462         set_pos (14, 30);
1463         set_color (NPregdisp == 3 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK);
1464         draw_char ('F');
1465     }
1466 
1467     NPregs_valid = 1;
1468 
1469     /* Address & Data */
1470     if (!NPaddr_valid)
1471     {
1472         set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1473         set_pos (16, 12);
1474         draw_fw (NPaddress);
1475         NPaddr_valid = 1;
1476     }
1477     if (!NPdata_valid)
1478     {
1479         set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1480         set_pos (16, 30);
1481         draw_fw (NPdata);
1482         NPdata_valid = 1;
1483     }
1484 
1485     /* Rates */
1486 #ifdef OPTION_MIPS_COUNTING
1487     if (!NPmips_valid || sysblk.mipsrate != NPmips)
1488     {
1489         set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1490         set_pos (19, 1);
1491         sprintf(buf, "%3.1d.%2.2d",
1492             sysblk.mipsrate / 1000000, (sysblk.mipsrate % 1000000) / 10000);
1493         draw_text (buf);
1494         NPmips = sysblk.mipsrate;
1495         NPmips_valid = 1;
1496     }
1497     if (!NPsios_valid || NPsios != sysblk.siosrate)
1498     {
1499         set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1500         set_pos (19, 7);
1501         sprintf(buf, "%7d", sysblk.siosrate);
1502         draw_text (buf);
1503         NPsios = sysblk.siosrate;
1504         NPsios_valid = 1;
1505     }
1506 #endif /* OPTION_MIPS_COUNTING */
1507 
1508     /* Optional cpu graph */
1509     if (NPcpugraph)
1510     {
1511         for (i = 0; i < NPcpugraph_ncpu; i++)
1512         {
1513             if (!IS_CPU_ONLINE(i))
1514             {
1515                 if (!NPcpugraph_valid || NPcpugraphpct[i] != -2.0)
1516                 {
1517                     set_color (COLOR_RED, COLOR_BLACK);
1518                     set_pos (26+i, 4);
1519                     draw_text ("OFFLINE");
1520                     fill_text (' ', 38);
1521                     NPcpugraphpct[i] = -2.0;
1522                 }
1523             }
1524             else if (sysblk.regs[i]->cpustate != CPUSTATE_STARTED)
1525             {
1526                 if (!NPcpugraph_valid || NPcpugraphpct[i] != -1.0)
1527                 {
1528                     set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK);
1529                     set_pos (26+i, 4);
1530                     draw_text ("STOPPED");
1531                     fill_text (' ', 38);
1532                     NPcpugraphpct[i] = -1.0;
1533                 }
1534             }
1535             else if (!NPcpugraph_valid || NPcpugraphpct[i] != sysblk.regs[i]->cpupct)
1536             {
1537                 n = (34 * sysblk.regs[i]->cpupct) / 100;
1538                 if (n == 0 && sysblk.regs[i]->cpupct > 0)
1539                     n = 1;
1540                 else if (n > 34)
1541                     n = 34;
1542                 set_color (n > 17 ? COLOR_WHITE : COLOR_LIGHT_GREY, COLOR_BLACK);
1543                 set_pos (26+i, 4);
1544                 fill_text ('*', n+3);
1545                 fill_text (' ', 38);
1546                 NPcpugraphpct[i] = sysblk.regs[i]->cpupct;
1547             }
1548             set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1549         }
1550         NPcpugraph_valid = 1;
1551     }
1552 
1553     /* Process devices */
1554     for (i = 0, dev = sysblk.firstdev; dev != NULL; i++, dev = dev->nextdev)
1555     {
1556         if (i >= cons_rows - 3) break;
1557         if (!dev->allocated) continue;
1558 
1559         online = (dev->console && dev->connected) || strlen(dev->filename) > 0;
1560         busy   = dev->busy != 0 || IOPENDING(dev) != 0;
1561         open   = dev->fd > 2;
1562 
1563         /* device identifier */
1564         if (!NPdevices_valid || online != NPonline[i])
1565         {
1566             set_pos (i+3, 41);
1567             set_color (online ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK);
1568             draw_char (i < 26 ? 'A' + i : '.');
1569             NPonline[i] = online;
1570         }
1571 
1572         /* device number */
1573         if (!NPdevices_valid || dev->devnum != NPdevnum[i] || NPbusy[i] != busy)
1574         {
1575             set_pos (i+3, 43);
1576             set_color (busy ? COLOR_LIGHT_YELLOW : COLOR_LIGHT_GREY, COLOR_BLACK);
1577             sprintf (buf, "%4.4X", dev->devnum);
1578             draw_text (buf);
1579             NPdevnum[i] = dev->devnum;
1580             NPbusy[i] = busy;
1581         }
1582 
1583         /* device type */
1584         if (!NPdevices_valid || dev->devtype != NPdevtype[i] || open != NPopen[i])
1585         {
1586             set_pos (i+3, 48);
1587             set_color (open ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK);
1588             sprintf (buf, "%4.4X", dev->devtype);
1589             draw_text (buf);
1590             NPdevtype[i] = dev->devtype;
1591             NPopen[i] = open;
1592         }
1593 
1594         /* device class and name */
1595         (dev->hnd->query)(dev, &devclass, sizeof(devnam), devnam);
1596         if (!NPdevices_valid || strcmp(NPdevnam[i], devnam))
1597         {
1598             set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1599             set_pos (i+3, 53);
1600             sprintf (buf, "%-4.4s", devclass);
1601             draw_text (buf);
1602             /* Draw device name only if they're NOT assigning a new one */
1603             if (0
1604                 || NPdataentry != 1
1605                 || NPpending != 'n'
1606                 || NPasgn != i
1607             )
1608             {
1609                 set_pos (i+3, 58);
1610                 draw_text (devnam);
1611                 fill_text (' ', PANEL_MAX_COLS);
1612             }
1613         }
1614     }
1615 
1616     /* Complete the device state table */
1617     if (!NPdevices_valid)
1618     {
1619         NPlastdev = i > 26 ? 26 : i - 1;
1620         for ( ; i < NP_MAX_DEVICES; i++)
1621         {
1622             NPonline[i] = NPdevnum[i] = NPbusy[i] = NPdevtype[i] = NPopen[i] = 0;
1623             strcpy (NPdevnam[i], "");
1624         }
1625         NPdevices_valid = 1;
1626     }
1627 
1628     /* Prompt 1 */
1629     if (strcmp(NPprompt1, NPoldprompt1))
1630     {
1631         strcpy(NPoldprompt1, NPprompt1);
1632         if (strlen(NPprompt1) > 0)
1633         {
1634             set_color (COLOR_WHITE, COLOR_BLUE);
1635             set_pos (cons_rows, (40 - strlen(NPprompt1)) / 2);
1636             draw_text (NPprompt1);
1637         }
1638         else if (cons_rows >= 24)
1639         {
1640             set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1641             set_pos (cons_rows, 1);
1642             fill_text ('-', 38);
1643         }
1644     }
1645 
1646     /* Prompt 2 */
1647     if (strcmp(NPprompt2, NPoldprompt2))
1648     {
1649         strcpy(NPoldprompt2, NPprompt2);
1650         if (strlen(NPprompt2) > 0)
1651         {
1652             set_color (COLOR_WHITE, COLOR_BLUE);
1653             set_pos (cons_rows, 41);
1654             draw_text (NPprompt2);
1655         }
1656         else if (cons_rows >= 24)
1657         {
1658             set_color (COLOR_LIGHT_GREY, COLOR_BLACK);
1659             set_pos (cons_rows, 41);
1660             fill_text ('-', cons_cols);
1661         }
1662     }
1663 
1664     /* Data entry field */
1665     if (NPdataentry && redraw_cmd)
1666     {
1667         set_pos (NPcurrow, NPcurcol);
1668         if (NPcolorSwitch)
1669             set_color (NPcolorFore, NPcolorBack);
1670         fill_text (' ', NPcurcol + NPdatalen - 1);
1671         set_pos (NPcurrow, NPcurcol);
1672         PUTC_CMDLINE();
1673         redraw_cmd = 0;
1674     }
1675     else
1676         /* Position the cursor to the bottom right */
1677         set_pos(cons_rows, cons_cols);
1678 }
1679 
1680 /* ==============   End of the main NP block of code    =============*/
1681 
1682 static void panel_cleanup(void *unused);    // (forward reference)
1683 
1684 #ifdef OPTION_MIPS_COUNTING
1685 
1686 ///////////////////////////////////////////////////////////////////////
1687 // "maxrates" command support...
1688 
1689 #define  DEF_MAXRATES_RPT_INTVL   (  1440  )
1690 
1691 DLL_EXPORT U32    curr_high_mips_rate = 0;  // (high water mark for current interval)
1692 DLL_EXPORT U32    curr_high_sios_rate = 0;  // (high water mark for current interval)
1693 
1694 DLL_EXPORT U32    prev_high_mips_rate = 0;  // (saved high water mark for previous interval)
1695 DLL_EXPORT U32    prev_high_sios_rate = 0;  // (saved high water mark for previous interval)
1696 
1697 DLL_EXPORT time_t curr_int_start_time = 0;  // (start time of current interval)
1698 DLL_EXPORT time_t prev_int_start_time = 0;  // (start time of previous interval)
1699 
1700 DLL_EXPORT U32    maxrates_rpt_intvl  = DEF_MAXRATES_RPT_INTVL;
1701 
update_maxrates_hwm()1702 DLL_EXPORT void update_maxrates_hwm()       // (update high-water-mark values)
1703 {
1704     time_t  current_time = 0;
1705     U32     elapsed_secs = 0;
1706 
1707     if (curr_high_mips_rate < sysblk.mipsrate)
1708         curr_high_mips_rate = sysblk.mipsrate;
1709 
1710     if (curr_high_sios_rate < sysblk.siosrate)
1711         curr_high_sios_rate = sysblk.siosrate;
1712 
1713     // Save high water marks for current interval...
1714 
1715     time( &current_time );
1716 
1717     elapsed_secs = current_time - curr_int_start_time;
1718 
1719     if ( elapsed_secs >= ( maxrates_rpt_intvl * 60 ) )
1720     {
1721         prev_high_mips_rate = curr_high_mips_rate;
1722         prev_high_sios_rate = curr_high_sios_rate;
1723 
1724         curr_high_mips_rate = 0;
1725         curr_high_sios_rate = 0;
1726 
1727         prev_int_start_time = curr_int_start_time;
1728         curr_int_start_time = current_time;
1729     }
1730 }
1731 #endif // OPTION_MIPS_COUNTING
1732 ///////////////////////////////////////////////////////////////////////
1733 
copy_regs(int cpu)1734 REGS *copy_regs(int cpu)
1735 {
1736     REGS *regs;
1737 
1738     if (cpu < 0 || cpu >= MAX_CPU_ENGINES)
1739         cpu = 0;
1740 
1741     obtain_lock (&sysblk.cpulock[cpu]);
1742 
1743     if ((regs = sysblk.regs[cpu]) == NULL)
1744     {
1745         release_lock(&sysblk.cpulock[cpu]);
1746         return &sysblk.dummyregs;
1747     }
1748 
1749     memcpy (&copyregs, regs, sysblk.regs_copy_len);
1750 
1751     if (copyregs.hostregs == NULL)
1752     {
1753         release_lock(&sysblk.cpulock[cpu]);
1754         return &sysblk.dummyregs;
1755     }
1756 
1757 #if defined(_FEATURE_SIE)
1758     if (regs->sie_active)
1759     {
1760         memcpy (&copysieregs, regs->guestregs, sysblk.regs_copy_len);
1761         copyregs.guestregs = &copysieregs;
1762         copysieregs.hostregs = &copyregs;
1763         regs = &copysieregs;
1764     }
1765     else
1766 #endif // defined(_FEATURE_SIE)
1767         regs = &copyregs;
1768 
1769     SET_PSW_IA(regs);
1770 
1771     release_lock(&sysblk.cpulock[cpu]);
1772     return regs;
1773 }
1774 
format_int(uint64_t ic)1775 static char *format_int(uint64_t ic)
1776 {
1777     static    char obfr[32];  /* Enough for displaying 2^64-1 */
1778     char  grps[7][4]; /* 7 groups of 3 digits */
1779     int   maxg=0;
1780     int   i;
1781 
1782     strcpy(grps[0],"0");
1783     while(ic>0)
1784     {
1785         int grp;
1786         grp=ic%1000;
1787         ic/=1000;
1788         if(ic==0)
1789         {
1790             sprintf(grps[maxg],"%u",grp);
1791         }
1792         else
1793         {
1794             sprintf(grps[maxg],"%3.3u",grp);
1795         }
1796         maxg++;
1797     }
1798     if(maxg) maxg--;
1799     obfr[0]=0;
1800     for(i=maxg;i>=0;i--)
1801     {
1802         strcat(obfr,grps[i]);
1803         if(i)
1804         {
1805             strcat(obfr,",");
1806         }
1807     }
1808     return obfr;
1809 }
1810 
1811 
1812 /*-------------------------------------------------------------------*/
1813 /* Panel display thread                                              */
1814 /*                                                                   */
1815 /* This function runs on the main thread.  It receives messages      */
1816 /* from the log task and displays them on the screen.  It accepts    */
1817 /* panel commands from the keyboard and executes them.  It samples   */
1818 /* the PSW periodically and displays it on the screen status line.   */
1819 /*-------------------------------------------------------------------*/
1820 
1821 #if defined(OPTION_DYNAMIC_LOAD)
panel_display_r(void)1822 void panel_display_r (void)
1823 #else
1824 void panel_display (void)
1825 #endif // defined(OPTION_DYNAMIC_LOAD)
1826 {
1827 #ifndef _MSVC_
1828   int     rc;                           /* Return code               */
1829   int     maxfd;                        /* Highest file descriptor   */
1830   fd_set  readset;                      /* Select file descriptors   */
1831   struct  timeval tv;                   /* Select timeout structure  */
1832 #endif // _MSVC_
1833 int     i;                              /* Array subscripts          */
1834 int     len;                            /* Length                    */
1835 REGS   *regs;                           /* -> CPU register context   */
1836 QWORD   curpsw;                         /* Current PSW               */
1837 QWORD   prvpsw;                         /* Previous PSW              */
1838 BYTE    prvstate = 0xFF;                /* Previous stopped state    */
1839 U64     prvicount = 0;                  /* Previous instruction count*/
1840 #if defined(OPTION_MIPS_COUNTING)
1841 U64     prvtcount = 0;                  /* Previous total count      */
1842 #endif /*defined(OPTION_MIPS_COUNTING)*/
1843 int     prvcpupct = 0;                  /* Previous cpu percentage   */
1844 #if defined(OPTION_SHARED_DEVICES)
1845 U32     prvscount = 0;                  /* Previous shrdcount        */
1846 #endif // defined(OPTION_SHARED_DEVICES)
1847 char    readbuf[MSG_SIZE];              /* Message read buffer       */
1848 int     readoff = 0;                    /* Number of bytes in readbuf*/
1849 BYTE    c;                              /* Character work area       */
1850 size_t  kbbufsize = CMD_SIZE;           /* Size of keyboard buffer   */
1851 char   *kbbuf = NULL;                   /* Keyboard input buffer     */
1852 int     kblen;                          /* Number of chars in kbbuf  */
1853 U32     aaddr;                          /* Absolute address for STO  */
1854 char    buf[1024];                      /* Buffer workarea           */
1855 
1856     SET_THREAD_NAME("panel_display");
1857 
1858     /* Display thread started message on control panel */
1859     logmsg (_("HHCPN001I Control panel thread started: "
1860             "tid="TIDPAT", pid=%d\n"),
1861             thread_id(), getpid());
1862 
1863     /* Notify logger_thread we're in control */
1864     sysblk.panel_init = 1;
1865 
1866     hdl_adsc("panel_cleanup",panel_cleanup, NULL);
1867     history_init();
1868 
1869     /* Set up the input file descriptors */
1870     confp = stderr;
1871     keybfd = STDIN_FILENO;
1872 
1873     /* Initialize screen dimensions */
1874     cons_term = getenv ("TERM");
1875     get_dim (&cons_rows, &cons_cols);
1876 
1877     /* Clear the command-line buffer */
1878     memset (cmdline, 0, sizeof(cmdline));
1879     cmdcols = cons_cols - CMDLINE_COL;
1880 
1881     /* Obtain storage for the keyboard buffer */
1882     if (!(kbbuf = malloc (kbbufsize)))
1883     {
1884         logmsg(_("HHCPN002S Cannot obtain keyboard buffer: %s\n"),
1885                 strerror(errno));
1886         return;
1887     }
1888 
1889     /* Obtain storage for the circular message buffer */
1890     msgbuf = malloc (MAX_MSGS * sizeof(PANMSG));
1891     if (msgbuf == NULL)
1892     {
1893         fprintf (stderr,
1894                 _("HHCPN003S Cannot obtain message buffer: %s\n"),
1895                 strerror(errno));
1896         return;
1897     }
1898 
1899     /* Initialize circular message buffer */
1900     for (curmsg = msgbuf, i=0; i < MAX_MSGS; curmsg++, i++)
1901     {
1902         curmsg->next = curmsg + 1;
1903         curmsg->prev = curmsg - 1;
1904         curmsg->msgnum = i;
1905         memset(curmsg->msg,SPACE,MSG_SIZE);
1906 #if defined(OPTION_MSGCLR)
1907         curmsg->bg = COLOR_DEFAULT_FG;
1908         curmsg->fg = COLOR_DEFAULT_BG;
1909 #if defined(OPTION_MSGHLD)
1910         curmsg->keep = 0;
1911         memset( &curmsg->expiration, 0, sizeof(curmsg->expiration));
1912 #endif // defined(OPTION_MSGHLD)
1913 #endif // defined(OPTION_MSGCLR)
1914     }
1915 
1916     /* Complete the circle */
1917     msgbuf->prev = msgbuf + MAX_MSGS - 1;
1918     msgbuf->prev->next = msgbuf;
1919 
1920     /* Indicate "first-time" state */
1921     curmsg = topmsg = NULL;
1922     wrapped = 0;
1923     numkept = 0;
1924 #if defined(OPTION_MSGHLD)
1925     keptmsgs = lastkept = NULL;
1926 #endif // defined(OPTION_MSGHLD)
1927 
1928     /* Set screen output stream to NON-buffered */
1929     setvbuf (confp, NULL, _IONBF, 0);
1930 
1931     /* Put the terminal into cbreak mode */
1932     set_or_reset_console_mode( keybfd, 1 );
1933 
1934     /* Set console title */
1935     set_console_title();
1936 
1937     /* Clear the screen */
1938     set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
1939     clr_screen ();
1940     redraw_msgs = redraw_cmd = redraw_status = 1;
1941 
1942     /* Process messages and commands */
1943     while ( 1 )
1944     {
1945 #if defined(OPTION_MIPS_COUNTING)
1946         update_maxrates_hwm(); // (update high-water-mark values)
1947 #endif // defined(OPTION_MIPS_COUNTING)
1948 
1949 #if defined( _MSVC_ )
1950         /* Wait for keyboard input */
1951 #define WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS  (20)
1952         for (i=sysblk.panrate/WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS; i && !kbhit(); i--)
1953             Sleep(WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS);
1954 
1955         ADJ_SCREEN_SIZE();
1956 
1957         /* If keyboard input has [finally] arrived, then process it */
1958         if ( kbhit() )
1959         {
1960             /* Read character(s) from the keyboard */
1961             kbbuf[0] = getch();
1962             kbbuf[kblen=1] = '\0';
1963             translate_keystroke( kbbuf, &kblen );
1964 
1965 #else // !defined( _MSVC_ )
1966 
1967         /* Set the file descriptors for select */
1968         FD_ZERO (&readset);
1969         FD_SET (keybfd, &readset);
1970         maxfd = keybfd;
1971 
1972         /* Wait for a message to arrive, a key to be pressed,
1973            or the inactivity interval to expire */
1974         tv.tv_sec = sysblk.panrate / 1000;
1975         tv.tv_usec = (sysblk.panrate * 1000) % 1000000;
1976         rc = select (maxfd + 1, &readset, NULL, NULL, &tv);
1977         if (rc < 0 )
1978         {
1979             if (errno == EINTR) continue;
1980             fprintf (stderr,
1981                     _("HHCPN004E select: %s\n"),
1982                     strerror(errno));
1983             break;
1984         }
1985 
1986         ADJ_SCREEN_SIZE();
1987 
1988         /* If keyboard input has arrived then process it */
1989         if (FD_ISSET(keybfd, &readset))
1990         {
1991             /* Read character(s) from the keyboard */
1992             kblen = read (keybfd, kbbuf, kbbufsize-1);
1993 
1994             if (kblen < 0)
1995             {
1996                 fprintf (stderr,
1997                         _("HHCPN005E keyboard read: %s\n"),
1998                         strerror(errno));
1999                 break;
2000             }
2001 
2002             kbbuf[kblen] = '\0';
2003 
2004 #endif // defined( _MSVC_ )
2005 
2006             /* =NP= : Intercept NP commands & process */
2007             if (NPDup == 1)
2008             {
2009                 if (NPdevsel == 1)
2010                 {
2011                     NPdevsel = 0;
2012                     NPdevice = kbbuf[0];  /* save the device selected */
2013                     kbbuf[0] = NPsel2;    /* setup for 2nd part of rtn */
2014                 }
2015                 if (NPdataentry == 0 && kblen == 1)
2016                 {   /* We are in command mode */
2017                     if (NPhelpup == 1)
2018                     {
2019                         if (kbbuf[0] == 0x1b)
2020                             NPhelpdown = 1;
2021                         kbbuf[0] = '\0';
2022                         redraw_status = 1;
2023                     }
2024                     cmdline[0] = '\0';
2025                     cmdlen = 0;
2026                     cmdoff = 0;
2027                     ADJ_CMDCOL();
2028                     switch(kbbuf[0]) {
2029                         case 0x1B:                  /* ESC */
2030                             NPDup = 0;
2031                             restore_command_line();
2032                             ADJ_CMDCOL();
2033                             redraw_msgs = redraw_cmd = redraw_status = 1;
2034                             npquiet = 0; // (forced for one paint cycle)
2035                             break;
2036                         case '?':
2037                             NPhelpup = 1;
2038                             redraw_status = 1;
2039                             break;
2040                         case 'S':                   /* START */
2041                         case 's':
2042                             do_panel_command("herc startall");
2043                             break;
2044                         case 'P':                   /* STOP */
2045                         case 'p':
2046                             do_panel_command("herc stopall");
2047                             break;
2048                         case 'O':                   /* Store */
2049                         case 'o':
2050                             regs = copy_regs(sysblk.pcpu);
2051                             aaddr = APPLY_PREFIXING (NPaddress, regs->PX);
2052                             if (aaddr > regs->mainlim)
2053                                 break;
2054                             store_fw (regs->mainstor + aaddr, NPdata);
2055                             redraw_status = 1;
2056                             break;
2057                         case 'I':                   /* Display */
2058                         case 'i':
2059                             NPregdisp = 4;
2060                             NPregs_valid = 0;
2061                             redraw_status = 1;
2062                             break;
2063                         case 'g':                   /* display GPR */
2064                         case 'G':
2065                             NPregdisp = 0;
2066                             NPregs_valid = 0;
2067                             redraw_status = 1;
2068                             break;
2069                         case 'a':                   /* Display AR */
2070                         case 'A':
2071                             NPregdisp = 2;
2072                             NPregs_valid = 0;
2073                             redraw_status = 1;
2074                             break;
2075                         case 'c':
2076                         case 'C':                   /* Case CR */
2077                             NPregdisp = 1;
2078                             NPregs_valid = 0;
2079                             redraw_status = 1;
2080                             break;
2081                         case 'f':                   /* Case FPR */
2082                         case 'F':
2083                             NPregdisp = 3;
2084                             NPregs_valid = 0;
2085                             redraw_status = 1;
2086                             break;
2087                         case 'r':                   /* Enter address */
2088                         case 'R':
2089                             NPdataentry = 1;
2090                             redraw_cmd = 1;
2091                             NPpending = 'r';
2092                             NPcurrow = 16;
2093                             NPcurcol = 12;
2094                             NPdatalen = 8;
2095                             NPcolorSwitch = 1;
2096                             NPcolorFore = COLOR_WHITE;
2097                             NPcolorBack = COLOR_BLUE;
2098                             strcpy(NPentered, "");
2099                             strcpy(NPprompt1, "Enter Address");
2100                             redraw_status = 1;
2101                             break;
2102                         case 'd':                   /* Enter data */
2103                         case 'D':
2104                             NPdataentry = 1;
2105                             redraw_cmd = 1;
2106                             NPpending = 'd';
2107                             NPcurrow = 16;
2108                             NPcurcol = 30;
2109                             NPdatalen = 8;
2110                             NPcolorSwitch = 1;
2111                             NPcolorFore = COLOR_WHITE;
2112                             NPcolorBack = COLOR_BLUE;
2113                             strcpy(NPentered, "");
2114                             strcpy(NPprompt1, "Enter Data Value");
2115                             redraw_status = 1;
2116                             break;
2117                         case 'l':                   /* IPL */
2118                         case 'L':
2119                             NPdevsel = 1;
2120                             NPsel2 = 1;
2121                             strcpy(NPprompt2, "Select Device for IPL");
2122                             redraw_status = 1;
2123                             break;
2124                         case 1:                     /* IPL - 2nd part */
2125                             i = toupper(NPdevice) - 'A';
2126                             if (i < 0 || i > NPlastdev) {
2127                                 strcpy(NPprompt2, "");
2128                                 redraw_status = 1;
2129                                 break;
2130                             }
2131                             sprintf (cmdline, "herc ipl %4.4x", NPdevnum[i]);
2132                             do_panel_command(cmdline);
2133                             strcpy(NPprompt2, "");
2134                             redraw_status = 1;
2135                             break;
2136                         case 'u':                   /* Device interrupt */
2137                         case 'U':
2138                             NPdevsel = 1;
2139                             NPsel2 = 2;
2140                             strcpy(NPprompt2, "Select Device for Interrupt");
2141                             redraw_status = 1;
2142                             break;
2143                         case 2:                     /* Device int: part 2 */
2144                             i = toupper(NPdevice) - 'A';
2145                             if (i < 0 || i > NPlastdev) {
2146                                 strcpy(NPprompt2, "");
2147                                 redraw_status = 1;
2148                                 break;
2149                             }
2150                             sprintf (cmdline, "herc i %4.4x", NPdevnum[i]);
2151                             do_panel_command(cmdline);
2152                             strcpy(NPprompt2, "");
2153                             redraw_status = 1;
2154                             break;
2155                         case 'n':                   /* Device Assignment */
2156                         case 'N':
2157                             NPdevsel = 1;
2158                             NPsel2 = 3;
2159                             strcpy(NPprompt2, "Select Device to Reassign");
2160                             redraw_status = 1;
2161                             break;
2162                         case 3:                     /* Device asgn: part 2 */
2163                             i = toupper(NPdevice) - 'A';
2164                             if (i < 0 || i > NPlastdev) {
2165                                 strcpy(NPprompt2, "");
2166                                 redraw_status = 1;
2167                                 break;
2168                             }
2169                             NPdataentry = 1;
2170                             redraw_cmd = 1;
2171                             NPpending = 'n';
2172                             NPasgn = i;
2173                             NPcurrow = 3 + i;
2174                             NPcurcol = 58;
2175                             NPdatalen = cons_cols - 57;
2176                             NPcolorSwitch = 1;
2177                             NPcolorFore = COLOR_DEFAULT_LIGHT;
2178                             NPcolorBack = COLOR_BLUE;
2179                             strcpy(NPentered, "");
2180                             strcpy(NPprompt2, "New Name, or [enter] to Reload");
2181                             redraw_status = 1;
2182                             break;
2183                         case 'W':                   /* POWER */
2184                         case 'w':
2185                             NPdevsel = 1;
2186                             NPsel2 = 4;
2187                             strcpy(NPprompt1, "Confirm Powerdown Y or N");
2188                             redraw_status = 1;
2189                             break;
2190                         case 4:                     /* POWER - 2nd part */
2191                             if (NPdevice == 'y' || NPdevice == 'Y')
2192                                 do_panel_command("herc quit");
2193                             strcpy(NPprompt1, "");
2194                             redraw_status = 1;
2195                             break;
2196                         case 'T':                   /* Restart */
2197                         case 't':
2198                             NPdevsel = 1;
2199                             NPsel2 = 5;
2200                             strcpy(NPprompt1, "Confirm Restart Y or N");
2201                             redraw_status = 1;
2202                             break;
2203                         case 5:                    /* Restart - part 2 */
2204                             if (NPdevice == 'y' || NPdevice == 'Y')
2205                                 do_panel_command("herc restart");
2206                             strcpy(NPprompt1, "");
2207                             redraw_status = 1;
2208                             break;
2209                         case 'E':                   /* Ext int */
2210                         case 'e':
2211                             NPdevsel = 1;
2212                             NPsel2 = 6;
2213                             strcpy(NPprompt1, "Confirm External Interrupt Y or N");
2214                             redraw_status = 1;
2215                             break;
2216                         case 6:                    /* External - part 2 */
2217                             if (NPdevice == 'y' || NPdevice == 'Y')
2218                                 do_panel_command("herc ext");
2219                             strcpy(NPprompt1, "");
2220                             redraw_status = 1;
2221                             break;
2222                         default:
2223                             break;
2224                     }
2225                     NPcmd = 1;
2226                 } else {  /* We are in data entry mode */
2227                     if (kbbuf[0] == 0x1B) {
2228                         /* Switch back to command mode */
2229                         NPdataentry = 0;
2230                         NPaddr_valid = 0;
2231                         NPdata_valid = 0;
2232                         strcpy(NPprompt1, "");
2233                         strcpy(NPprompt2, "");
2234                         NPcmd = 1;
2235                     }
2236                     else
2237                         NPcmd = 0;
2238                 }
2239                 if (NPcmd == 1)
2240                     kblen = 0;                  /* don't process as command */
2241             }
2242             /* =NP END= */
2243 
2244             /* Process characters in the keyboard buffer */
2245             for (i = 0; i < kblen; )
2246             {
2247                 /* Test for HOME */
2248                 if (strcmp(kbbuf+i, KBD_HOME) == 0) {
2249                     if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) {
2250                         cursor_cmdline_home();
2251                         redraw_cmd = 1;
2252                     } else {
2253                         scroll_to_top_line( 1 );
2254                         redraw_msgs = 1;
2255                     }
2256                     break;
2257                 }
2258 
2259                 /* Test for END */
2260                 if (strcmp(kbbuf+i, KBD_END) == 0) {
2261                     if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) {
2262                         cursor_cmdline_end();
2263                         redraw_cmd = 1;
2264                     } else {
2265                         scroll_to_bottom_screen( 1 );
2266                         redraw_msgs = 1;
2267                     }
2268                     break;
2269                 }
2270 
2271                 /* Test for CTRL+HOME */
2272                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_HOME) == 0) {
2273                     scroll_to_top_line( 1 );
2274                     redraw_msgs = 1;
2275                     break;
2276                 }
2277 
2278                 /* Test for CTRL+END */
2279                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_END) == 0) {
2280                     scroll_to_bottom_line( 1 );
2281                     redraw_msgs = 1;
2282                     break;
2283                 }
2284 
2285                 /* Process UPARROW */
2286                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_UP_ARROW) == 0)
2287                 {
2288                     do_prev_history();
2289                     redraw_cmd = 1;
2290                     break;
2291                 }
2292 
2293                 /* Process DOWNARROW */
2294                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_DOWN_ARROW) == 0)
2295                 {
2296                     do_next_history();
2297                     redraw_cmd = 1;
2298                     break;
2299                 }
2300 
2301 #if defined(OPTION_EXTCURS)
2302                 /* Process ALT+UPARROW */
2303                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_UP_ARROW) == 0) {
2304                     get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2305                     if (cur_cons_row <= 1)
2306                         cur_cons_row = cons_rows + 1;
2307                     set_pos( --cur_cons_row, cur_cons_col );
2308                     break;
2309                 }
2310 
2311                 /* Process ALT+DOWNARROW */
2312                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_DOWN_ARROW) == 0) {
2313                     get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2314                     if (cur_cons_row >= cons_rows)
2315                         cur_cons_row = 1 - 1;
2316                     set_pos( ++cur_cons_row, cur_cons_col );
2317                     break;
2318                 }
2319 #endif // defined(OPTION_EXTCURS)
2320 
2321                 /* Test for PAGEUP */
2322                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_UP) == 0) {
2323                     page_up( 1 );
2324                     redraw_msgs = 1;
2325                     break;
2326                 }
2327 
2328                 /* Test for PAGEDOWN */
2329                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_DOWN) == 0) {
2330                     page_down( 1 );
2331                     redraw_msgs = 1;
2332                     break;
2333                 }
2334 
2335                 /* Test for CTRL+UPARROW */
2336                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_UP_ARROW) == 0) {
2337                     scroll_up_lines(1,1);
2338                     redraw_msgs = 1;
2339                     break;
2340                 }
2341 
2342                 /* Test for CTRL+DOWNARROW */
2343                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_DOWN_ARROW) == 0) {
2344                     scroll_down_lines(1,1);
2345                     redraw_msgs = 1;
2346                     break;
2347                 }
2348 
2349                 /* Process BACKSPACE */
2350                 if (kbbuf[i] == '\b' || kbbuf[i] == '\x7F') {
2351                     if (NPDup == 0 && !is_cursor_on_cmdline())
2352                         beep();
2353                     else {
2354                         if (cmdoff > 0) {
2355                             int j;
2356                             for (j = cmdoff-1; j<cmdlen; j++)
2357                                 cmdline[j] = cmdline[j+1];
2358                             cmdoff--;
2359                             cmdlen--;
2360                             ADJ_CMDCOL();
2361                         }
2362                         i++;
2363                         redraw_cmd = 1;
2364                     }
2365                     break;
2366                 }
2367 
2368                 /* Process DELETE */
2369                 if (strcmp(kbbuf+i, KBD_DELETE) == 0) {
2370                     if (NPDup == 0 && !is_cursor_on_cmdline())
2371                         beep();
2372                     else {
2373                         if (cmdoff < cmdlen) {
2374                             int j;
2375                             for (j = cmdoff; j<cmdlen; j++)
2376                                 cmdline[j] = cmdline[j+1];
2377                             cmdlen--;
2378                         }
2379                         i++;
2380                         redraw_cmd = 1;
2381                     }
2382                     break;
2383                 }
2384 
2385                 /* Process LEFTARROW */
2386                 if (strcmp(kbbuf+i, KBD_LEFT_ARROW) == 0) {
2387                     if (cmdoff > 0) cmdoff--;
2388                     ADJ_CMDCOL();
2389                     i++;
2390                     redraw_cmd = 1;
2391                     break;
2392                 }
2393 
2394                 /* Process RIGHTARROW */
2395                 if (strcmp(kbbuf+i, KBD_RIGHT_ARROW) == 0) {
2396                     if (cmdoff < cmdlen) cmdoff++;
2397                     ADJ_CMDCOL();
2398                     i++;
2399                     redraw_cmd = 1;
2400                     break;
2401                 }
2402 
2403 #if defined(OPTION_EXTCURS)
2404                 /* Process ALT+LEFTARROW */
2405                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_LEFT_ARROW) == 0) {
2406                     get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2407                     if (cur_cons_col <= 1)
2408                     {
2409                         cur_cons_row--;
2410                         cur_cons_col = cons_cols + 1;
2411                     }
2412                     if (cur_cons_row < 1)
2413                         cur_cons_row = cons_rows;
2414                     set_pos( cur_cons_row, --cur_cons_col );
2415                     break;
2416                 }
2417 
2418                 /* Process ALT+RIGHTARROW */
2419                 if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_RIGHT_ARROW) == 0) {
2420                     get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col );
2421                     if (cur_cons_col >= cons_cols)
2422                     {
2423                         cur_cons_row++;
2424                         cur_cons_col = 0;
2425                     }
2426                     if (cur_cons_row > cons_rows)
2427                         cur_cons_row = 1;
2428                     set_pos( cur_cons_row, ++cur_cons_col );
2429                     break;
2430                 }
2431 #endif // defined(OPTION_EXTCURS)
2432 
2433                 /* Process INSERT */
2434                 if (strcmp(kbbuf+i, KBD_INSERT) == 0 ) {
2435                     cmdins = !cmdins;
2436                     set_console_cursor_shape( confp, cmdins );
2437                     i++;
2438                     break;
2439                 }
2440 
2441                 /* Process ESCAPE */
2442                 if (kbbuf[i] == '\x1B') {
2443                     /* If data on cmdline, erase it */
2444                     if ((NPDup == 1 || is_cursor_on_cmdline()) && cmdlen) {
2445                         cmdline[0] = '\0';
2446                         cmdlen = 0;
2447                         cmdoff = 0;
2448                         ADJ_CMDCOL();
2449                         redraw_cmd = 1;
2450                     } else {
2451                         /* =NP= : Switch to new panel display */
2452                         save_command_line();
2453                         NP_init();
2454                         NPDup = 1;
2455                         /* =END= */
2456                     }
2457                     break;
2458                 }
2459 
2460                 /* Process TAB */
2461                 if (kbbuf[i] == '\t' || kbbuf[i] == '\x7F') {
2462                     if (NPDup == 1 || !is_cursor_on_cmdline()) {
2463                         cursor_cmdline_home();
2464                         redraw_cmd = 1;
2465                     } else {
2466                         tab_pressed(cmdline, &cmdoff);
2467                         cmdlen = strlen(cmdline);
2468                         ADJ_CMDCOL();
2469                         i++;
2470                         redraw_cmd = 1;
2471                     }
2472                     break;
2473                 }
2474 
2475 #if defined(OPTION_EXTCURS)
2476                 /* ENTER key special handling */
2477                 if (NPDup == 0 && kbbuf[i] == '\n')
2478                 {
2479                     /* Get cursor pos and check if on cmdline */
2480                     if (!is_cursor_on_cmdline())
2481                     {
2482                         int keepnum = get_keepnum_by_row( cur_cons_row );
2483                         if (keepnum >= 0)
2484                         {
2485 #if defined(OPTION_MSGHLD)
2486                             /* ENTER pressed on kept msg; remove msg */
2487                             unkeep_by_keepnum( keepnum, 1 );
2488 #endif // defined(OPTION_MSGHLD)
2489                             redraw_msgs = 1;
2490                             break;
2491                         }
2492                         /* ENTER pressed NOT on cmdline */
2493                         beep();
2494                         break;
2495                     }
2496                         /* ENTER pressed on cmdline; fall through
2497                            for normal ENTER keypress handling... */
2498                 }
2499 #endif // defined(OPTION_EXTCURS)
2500 
2501                 /* Process the command when the ENTER key is pressed */
2502                 if (kbbuf[i] == '\n') {
2503                     if (cmdlen == 0 && NPDup == 0 && !sysblk.inststep &&
2504                         sysblk.cmdtgt == 0) {
2505                         history_show();
2506                     } else {
2507                         cmdline[cmdlen] = '\0';
2508                         /* =NP= create_thread replaced with: */
2509                         if (NPDup == 0) {
2510                             if ('#' == cmdline[0] || '*' == cmdline[0]) {
2511                                 if (!is_currline_visible())
2512                                     scroll_to_bottom_screen( 1 );
2513                                 history_requested = 0;
2514                                 do_panel_command(cmdline);
2515                                 redraw_cmd = 1;
2516                                 cmdlen = 0;
2517                                 cmdoff = 0;
2518                                 ADJ_CMDCOL();
2519                                 redraw_cmd = 1;
2520                             } else {
2521                                 history_requested = 0;
2522                                 do_panel_command(cmdline);
2523                                 redraw_cmd = 1;
2524                                 if (history_requested == 1) {
2525                                     strcpy(cmdline, historyCmdLine);
2526                                     cmdlen = strlen(cmdline);
2527                                     cmdoff = cmdlen;
2528                                     ADJ_CMDCOL();
2529                                     NPDup = 0;
2530                                     NPDinit = 1;
2531                                 }
2532                             }
2533                         } else {
2534                             NPdataentry = 0;
2535                             NPcurrow = cons_rows;
2536                             NPcurcol = cons_cols;
2537                             NPcolorSwitch = 0;
2538                             switch (NPpending) {
2539                                 case 'r':
2540                                     sscanf(cmdline, "%x", &NPaddress);
2541                                     NPaddr_valid = 0;
2542                                     strcpy(NPprompt1, "");
2543                                     break;
2544                                 case 'd':
2545                                     sscanf(cmdline, "%x", &NPdata);
2546                                     NPdata_valid = 0;
2547                                     strcpy(NPprompt1, "");
2548                                     break;
2549                                 case 'n':
2550                                     if (strlen(cmdline) < 1) {
2551                                         strcpy(cmdline, NPdevnam[NPasgn]);
2552                                     }
2553                                     strcpy(NPdevnam[NPasgn], "");
2554                                     sprintf (NPentered, "herc devinit %4.4x %s",
2555                                              NPdevnum[NPasgn], cmdline);
2556                                     do_panel_command(NPentered);
2557                                     strcpy(NPprompt2, "");
2558                                     break;
2559                                 default:
2560                                     break;
2561                             }
2562                             redraw_status = 1;
2563                             cmdline[0] = '\0';
2564                             cmdlen = 0;
2565                             cmdoff = 0;
2566                             ADJ_CMDCOL();
2567                         }
2568                         /* =END= */
2569                         redraw_cmd = 1;
2570                     }
2571                     break;
2572                 } /* end if (kbbuf[i] == '\n') */
2573 
2574                 /* Ignore non-printable characters */
2575                 if (!isprint(kbbuf[i])) {
2576                     beep();
2577                     i++;
2578                     continue;
2579                 }
2580 
2581                 /* Ignore all other keystrokes not on cmdline */
2582                 if (NPDup == 0 && !is_cursor_on_cmdline()) {
2583                     beep();
2584                     break;
2585                 }
2586 
2587                 /* Append the character to the command buffer */
2588                 ASSERT(cmdlen <= CMD_SIZE-1 && cmdoff <= cmdlen);
2589                 if (0
2590                     || (cmdoff >= CMD_SIZE-1)
2591                     || (cmdins && cmdlen >= CMD_SIZE-1)
2592                 )
2593                 {
2594                     /* (no more room!) */
2595                     beep();
2596                 }
2597                 else /* (there's still room) */
2598                 {
2599                     ASSERT(cmdlen < CMD_SIZE-1 || (!cmdins && cmdoff < cmdlen));
2600                     if (cmdoff >= cmdlen)
2601                     {
2602                         /* Append to end of buffer */
2603                         ASSERT(!(cmdoff > cmdlen)); // (sanity check)
2604                         cmdline[cmdoff++] = kbbuf[i];
2605                         cmdline[cmdoff] = '\0';
2606                         cmdlen++;
2607                     }
2608                     else
2609                     {
2610                         ASSERT(cmdoff < cmdlen);
2611                         if (cmdins)
2612                         {
2613                             /* Insert: make room by sliding all
2614                                following chars right one position */
2615                             int j;
2616                             for (j=cmdlen-1; j>=cmdoff; j--)
2617                                 cmdline[j+1] = cmdline[j];
2618                             cmdline[cmdoff++] = kbbuf[i];
2619                             cmdlen++;
2620                         }
2621                         else
2622                         {
2623                             /* Overlay: replace current position */
2624                             cmdline[cmdoff++] = kbbuf[i];
2625                         }
2626                     }
2627                     ADJ_CMDCOL();
2628                     redraw_cmd = 1;
2629                 }
2630                 i++;
2631             } /* end for(i) */
2632         } /* end if keystroke */
2633 
2634 FinishShutdown:
2635 
2636         // If we finished processing all of the message data
2637         // the last time we were here, then get some more...
2638 
2639         if ( lmsndx >= lmscnt )  // (all previous data processed?)
2640         {
2641             lmscnt = log_read( &lmsbuf, &lmsnum, LOG_NOBLOCK );
2642             lmsndx = 0;
2643         }
2644         else if ( lmsndx >= lmsmax )
2645         {
2646             lmsbuf += lmsndx;   // pick up where we left off at...
2647             lmscnt -= lmsndx;   // pick up where we left off at...
2648             lmsndx = 0;
2649         }
2650 
2651         // Process all message data or until limit reached...
2652 
2653         // (limiting the amount of data we process a console message flood
2654         // from preventing keyboard from being read since we need to break
2655         // out of the below message data processing loop to loop back up
2656         // to read the keyboard again...)
2657 
2658         /* Read message bytes until newline... */
2659         while ( lmsndx < lmscnt && lmsndx < lmsmax )
2660         {
2661             /* Initialize the read buffer */
2662             if (!readoff || readoff >= MSG_SIZE) {
2663                 memset (readbuf, SPACE, MSG_SIZE);
2664                 readoff = 0;
2665             }
2666 
2667             /* Read message bytes and copy into read buffer
2668                until we either encounter a newline character
2669                or our buffer is completely filled with data. */
2670             while ( lmsndx < lmscnt && lmsndx < lmsmax )
2671             {
2672                 /* Read a byte from the message pipe */
2673                 c = *(lmsbuf + lmsndx); lmsndx++;
2674 
2675                 /* Break to process received message
2676                    whenever a newline is encountered */
2677                 if (c == '\n' || c == '\r') {
2678                     readoff = 0;    /* (for next time) */
2679                     break;
2680                 }
2681 
2682                 /* Handle tab character */
2683                 if (c == '\t') {
2684                     readoff += 8;
2685                     readoff &= 0xFFFFFFF8;
2686                     /* Messages longer than one screen line will
2687                        be continued on the very next screen line */
2688                     if (readoff >= MSG_SIZE)
2689                         break;
2690                     else continue;
2691                 }
2692 
2693                 /* Eliminate non-displayable characters */
2694                 if (!isgraph(c)) c = SPACE;
2695 
2696                 /* Stuff byte into message processing buffer */
2697                 readbuf[readoff++] = c;
2698 
2699                 /* Messages longer than one screen line will
2700                    be continued on the very next screen line */
2701                 if (readoff >= MSG_SIZE)
2702                     break;
2703             } /* end while ( lmsndx < lmscnt && lmsndx < lmsmax ) */
2704 
2705             /* If we have a message to be displayed (or a complete
2706                part of one), then copy it to the circular buffer. */
2707             if (!readoff || readoff >= MSG_SIZE) {
2708 
2709                 /* First-time here? */
2710                 if (curmsg == NULL) {
2711                     curmsg = topmsg = msgbuf;
2712                 } else {
2713                     /* Perform autoscroll if needed */
2714                     if (is_currline_visible()) {
2715                         while (lines_remaining() < 1)
2716                             scroll_down_lines(1,1);
2717                         /* Set the display update indicator */
2718                         redraw_msgs = 1;
2719                     }
2720 
2721                     /* Go on to next available msg buffer */
2722                     curmsg = curmsg->next;
2723 
2724                     /* Updated wrapped indicator */
2725                     if (curmsg == msgbuf)
2726                         wrapped = 1;
2727                 }
2728 
2729                 /* Copy message into next available PANMSG slot */
2730                 memcpy( curmsg->msg, readbuf, MSG_SIZE );
2731 
2732 #if defined(OPTION_MSGCLR)
2733                 /* Colorize and/or keep new message if needed */
2734                 colormsg(curmsg);
2735 #endif // defined(OPTION_MSGCLR)
2736 
2737             } /* end if (!readoff || readoff >= MSG_SIZE) */
2738         } /* end Read message bytes until newline... */
2739 
2740         /* Don't read or otherwise process any input
2741            once system shutdown has been initiated
2742         */
2743         if ( sysblk.shutdown )
2744         {
2745             if ( sysblk.shutfini ) break;
2746             /* wait for system to finish shutting down */
2747             usleep(10000);
2748             lmsmax = INT_MAX;
2749             goto FinishShutdown;
2750         }
2751 
2752         /* =NP= : Reinit traditional panel if NP is down */
2753         if (NPDup == 0 && NPDinit == 1) {
2754             redraw_msgs = redraw_status = redraw_cmd = 1;
2755             set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2756             clr_screen ();
2757         }
2758         /* =END= */
2759 
2760         /* Obtain the PSW for target CPU */
2761         regs = copy_regs(sysblk.pcpu);
2762         memset (curpsw, 0x00, sizeof(curpsw));
2763         copy_psw (regs, curpsw);
2764 
2765         /* Set the display update indicator if the PSW has changed
2766            or if the instruction counter has changed, or if
2767            the CPU stopped state has changed */
2768         if (memcmp(curpsw, prvpsw, sizeof(curpsw)) != 0
2769          || prvicount != INSTCOUNT(regs)
2770          || prvcpupct != regs->cpupct
2771 #if defined(OPTION_SHARED_DEVICES)
2772          || prvscount != sysblk.shrdcount
2773 #endif // defined(OPTION_SHARED_DEVICES)
2774          || prvstate != regs->cpustate
2775 #if defined(OPTION_MIPS_COUNTING)
2776          || (NPDup && NPcpugraph && prvtcount != sysblk.instcount)
2777 #endif /*defined(OPTION_MIPS_COUNTING)*/
2778            )
2779         {
2780             redraw_status = 1;
2781             memcpy (prvpsw, curpsw, sizeof(prvpsw));
2782             prvicount = INSTCOUNT(regs);
2783             prvcpupct = regs->cpupct;
2784             prvstate  = regs->cpustate;
2785 #if defined(OPTION_SHARED_DEVICES)
2786             prvscount = sysblk.shrdcount;
2787 #endif // defined(OPTION_SHARED_DEVICES)
2788 #if defined(OPTION_MIPS_COUNTING)
2789             prvtcount = sysblk.instcount;
2790 #endif /*defined(OPTION_MIPS_COUNTING)*/
2791         }
2792 
2793         /* =NP= : Display the screen - traditional or NP */
2794         /*        Note: this is the only code block modified rather */
2795         /*        than inserted.  It makes the block of 3 ifs in the */
2796         /*        original code dependent on NPDup == 0, and inserts */
2797         /*        the NP display as an else after those ifs */
2798 
2799         if (NPDup == 0) {
2800             /* Rewrite the screen if display update indicators are set */
2801             if (redraw_msgs && !npquiet)
2802             {
2803                 /* Display messages in scrolling area */
2804                 PANMSG* p;
2805 
2806                 /* Save cursor location */
2807                 saved_cons_row = cur_cons_row;
2808                 saved_cons_col = cur_cons_col;
2809 
2810 #if defined(OPTION_MSGHLD)
2811                 /* Unkeep kept messages if needed */
2812                 expire_kept_msgs(0);
2813 #endif // defined(OPTION_MSGHLD)
2814                 i = 0;
2815 #if defined(OPTION_MSGHLD)
2816                 /* Draw kept messages first */
2817                 for (p=keptmsgs; i < (SCROLL_LINES + numkept) && p; i++, p = p->next)
2818                 {
2819                     set_pos (i+1, 1);
2820 #if defined(OPTION_MSGCLR)
2821                     set_color (p->fg, p->bg);
2822 #else // !defined(OPTION_MSGCLR)
2823                     set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2824 #endif // defined(OPTION_MSGCLR)
2825                     write_text (p->msg, MSG_SIZE);
2826                 }
2827 #endif // defined(OPTION_MSGHLD)
2828 
2829                 /* Then draw current screen */
2830                 for (p=topmsg; i < (SCROLL_LINES + numkept) && (p != curmsg->next || p == topmsg); i++, p = p->next)
2831                 {
2832                     set_pos (i+1, 1);
2833 #if defined(OPTION_MSGCLR)
2834                     set_color (p->fg, p->bg);
2835 #else // !defined(OPTION_MSGCLR)
2836                     set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2837 #endif // defined(OPTION_MSGCLR)
2838                     write_text (p->msg, MSG_SIZE);
2839                 }
2840 
2841                 /* Pad remainder of screen with blank lines */
2842                 for (; i < (SCROLL_LINES + numkept); i++)
2843                 {
2844                     set_pos (i+1, 1);
2845                     set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2846                     erase_to_eol( confp );
2847                 }
2848 
2849                 /* Display the scroll indicators */
2850                 if (topmsg != oldest_msg())
2851                 {
2852                     /* More messages precede top line */
2853                     set_pos (1, cons_cols);
2854                     set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG);
2855                     draw_text ("+");
2856                 }
2857                 if (!is_currline_visible())
2858                 {
2859                     /* More messages follow bottom line */
2860                     set_pos (cons_rows-2, cons_cols);
2861                     set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG);
2862                     draw_text ("V");
2863                 }
2864 
2865                 /* restore cursor location */
2866                 cur_cons_row = saved_cons_row;
2867                 cur_cons_col = saved_cons_col;
2868             } /* end if(redraw_msgs) */
2869 
2870             if (redraw_cmd)
2871             {
2872                 /* Save cursor location */
2873                 saved_cons_row = cur_cons_row;
2874                 saved_cons_col = cur_cons_col;
2875 
2876                 /* Display the command line */
2877                 set_pos (CMDLINE_ROW, 1);
2878                 set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG);
2879 
2880 #if defined(OPTION_CMDTGT)
2881                 switch(sysblk.cmdtgt)
2882                 {
2883                   case 0: // cmdtgt herc
2884                   {
2885                     draw_text(CMD_PREFIX_STR);
2886                     break;
2887                   }
2888                   case 1: // cmdtgt scp
2889                   {
2890                     draw_text(CMD_PREFIX_STR1);
2891                     break;
2892                   }
2893                   case 2: // cmdtgt pscp
2894                   {
2895                     draw_text(CMD_PREFIX_STR2);
2896                     break;
2897                   }
2898                 }
2899 #else // !defined(OPTION_CMDTGT)
2900                 draw_text (CMD_PREFIX_STR);
2901 #endif // defined(OPTION_CMDTGT)
2902 
2903                 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2904                 PUTC_CMDLINE ();
2905                 fill_text (' ',cons_cols);
2906 
2907                 /* restore cursor location */
2908                 cur_cons_row = saved_cons_row;
2909                 cur_cons_col = saved_cons_col;
2910             } /* end if(redraw_cmd) */
2911 
2912             if (redraw_status && !npquiet)
2913             {
2914                 /* Save cursor location */
2915                 saved_cons_row = cur_cons_row;
2916                 saved_cons_col = cur_cons_col;
2917 
2918                 memset (buf, ' ', cons_cols);
2919                 len = sprintf (buf, "CPU%4.4X ", sysblk.pcpu);
2920                 if (IS_CPU_ONLINE(sysblk.pcpu))
2921                 {
2922                     char ibuf[64];
2923                     len += sprintf(buf+len, "PSW=%8.8X%8.8X ",
2924                                    fetch_fw(curpsw), fetch_fw(curpsw+4));
2925                     if (regs->arch_mode == ARCH_900)
2926                         len += sprintf (buf+len, "%16.16"I64_FMT"X ",
2927                                         fetch_dw (curpsw+8));
2928 #if defined(_FEATURE_SIE)
2929                     else
2930             if( SIE_MODE(regs) )
2931             {
2932                             for(i = 0;i < 16;i++)
2933                                 buf[len++] = '-';
2934                             buf[len++] = ' ';
2935             }
2936 #endif /*defined(_FEATURE_SIE)*/
2937                     len += sprintf (buf+len, "%2d%c%c%c%c%c%c%c%c",
2938                            regs->psw.amode64                  ? 64 :
2939                            regs->psw.amode                    ? 31 : 24,
2940                            regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.',
2941                            sysblk.inststep                    ? 'T' : '.',
2942                            WAITSTATE(&regs->psw)              ? 'W' : '.',
2943                            regs->loadstate                    ? 'L' : '.',
2944                            regs->checkstop                    ? 'C' : '.',
2945                            PROBSTATE(&regs->psw)              ? 'P' : '.',
2946                            SIE_MODE(regs)                     ? 'S' : '.',
2947                            regs->arch_mode == ARCH_900        ? 'Z' : '.');
2948                     buf[len++] = ' ';
2949                     sprintf (ibuf, "instcount=%s", format_int(INSTCOUNT(regs)));
2950                     if (len + (int)strlen(ibuf) < cons_cols)
2951                         len = cons_cols - strlen(ibuf);
2952                     strcpy (buf + len, ibuf);
2953                 }
2954                 else
2955                 {
2956                     len += sprintf (buf+len,"%s", "Offline");
2957                     buf[len++] = ' ';
2958                 }
2959                 buf[cons_cols] = '\0';
2960                 set_pos (cons_rows, 1);
2961                 set_color (COLOR_LIGHT_YELLOW, COLOR_RED);
2962                 draw_text (buf);
2963 
2964                 /* restore cursor location */
2965                 cur_cons_row = saved_cons_row;
2966                 cur_cons_col = saved_cons_col;
2967             } /* end if(redraw_status) */
2968 
2969             /* Flush screen buffer and reset display update indicators */
2970             if (redraw_msgs || redraw_cmd || redraw_status)
2971             {
2972                 set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
2973                 if (NPDup == 0 && NPDinit == 1)
2974                 {
2975                     NPDinit = 0;
2976                     restore_command_line();
2977                     set_pos (cur_cons_row, cur_cons_col);
2978                 }
2979                 else if (redraw_cmd)
2980                     set_pos (CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol);
2981                 else
2982                     set_pos (cur_cons_row, cur_cons_col);
2983                 fflush (confp);
2984                 redraw_msgs = redraw_cmd = redraw_status = 0;
2985             }
2986 
2987         } else { /* (NPDup == 1) */
2988 
2989             if (redraw_status || (NPDinit == 0 && NPDup == 1)
2990                    || (redraw_cmd && NPdataentry == 1)) {
2991                 if (NPDinit == 0) {
2992                     NPDinit = 1;
2993                     NP_screen_redraw(regs);
2994                     NP_update(regs);
2995                     fflush (confp);
2996                 }
2997             }
2998             /* Update New Panel every panrate interval */
2999             if (!npquiet) {
3000                 NP_update(regs);
3001                 fflush (confp);
3002             }
3003             redraw_msgs = redraw_cmd = redraw_status = 0;
3004         }
3005 
3006     /* =END= */
3007 
3008         /* Force full screen repaint if needed */
3009         if (!sysblk.npquiet && npquiet)
3010             redraw_msgs = redraw_cmd = redraw_status = 1;
3011         npquiet = sysblk.npquiet;
3012 
3013     } /* end while */
3014 
3015     ASSERT( sysblk.shutdown );  // (why else would we be here?!)
3016 
3017 } /* end function panel_display */
3018 
3019 static void panel_cleanup(void *unused)
3020 {
3021 int i;
3022 PANMSG* p;
3023 
3024     UNREFERENCED(unused);
3025 
3026     log_wakeup(NULL);
3027 
3028     set_screen_color( stderr, COLOR_DEFAULT_FG, COLOR_DEFAULT_BG );
3029     clear_screen( stderr );
3030 
3031     /* Scroll to last full screen's worth of messages */
3032     scroll_to_bottom_screen( 1 );
3033 
3034     /* Display messages in scrolling area */
3035     for (i=0, p = topmsg; i < SCROLL_LINES && p != curmsg->next; i++, p = p->next)
3036     {
3037         set_pos (i+1, 1);
3038 #if defined(OPTION_MSGCLR)
3039         set_color (p->fg, p->bg);
3040 #else // !defined(OPTION_MSGCLR)
3041         set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG);
3042 #endif // defined(OPTION_MSGCLR)
3043         write_text (p->msg, MSG_SIZE);
3044     }
3045 
3046     /* Restore the terminal mode */
3047     set_or_reset_console_mode( keybfd, 0 );
3048 
3049     /* Position to next line */
3050     fwrite("\n",1,1,stderr);
3051 
3052     /* Read and display any msgs still remaining in the system log */
3053     while((lmscnt = log_read(&lmsbuf, &lmsnum, LOG_NOBLOCK)))
3054         fwrite(lmsbuf,lmscnt,1,stderr);
3055 
3056     fflush(stderr);
3057 }
3058