/* PANEL.C (c) Copyright Roger Bowler, 1999-2012 */ /* (c) Copyright TurboHercules, SAS 2010-2011 */ /* Hercules Control Panel Commands */ /* */ /* Released under "The Q Public License Version 1" */ /* (http://www.hercules-390.org/herclic.html) as modifications to */ /* Hercules. */ /* z/Architecture support - (c) Copyright Jan Jaeger, 1999-2012 */ /* Modified for New Panel Display =NP= */ /*-------------------------------------------------------------------*/ /* This module is the control panel for the ESA/390 emulator. */ /* It provides a command interface into hercules, and it displays */ /* messages that are issued by various hercules components. */ /*-------------------------------------------------------------------*/ /*-------------------------------------------------------------------*/ /* Additional credits: */ /* breakpoint command contributed by Dan Horak */ /* devinit command contributed by Jay Maynard */ /* New Panel Display contributed by Dutch Owen */ /* HMC system console commands contributed by Jan Jaeger */ /* Set/reset bad frame indicator command by Jan Jaeger */ /* attach/detach/define commands by Jan Jaeger */ /* Panel refresh rate triva by Reed H. Petty */ /* 64-bit address support by Roger Bowler */ /* Display subchannel command by Nobumichi Kozawa */ /* External GUI logic contributed by "Fish" (David B. Trout) */ /* Socket Devices originally designed by Malcolm Beattie; */ /* actual implementation by "Fish" (David B. Trout). */ /*-------------------------------------------------------------------*/ #include "hstdinc.h" #define _PANEL_C_ #define _HENGINE_DLL_ #include "hercules.h" #include "devtype.h" #include "opcode.h" #include "history.h" // #include "inline.h" #include "fillfnam.h" #include "hconsole.h" #define DISPLAY_INSTRUCTION_OPERANDS #define PANEL_MAX_ROWS (256) #define PANEL_MAX_COLS (256) int redraw_msgs; /* 1=Redraw message area */ int redraw_cmd; /* 1=Redraw command line */ int redraw_status; /* 1=Redraw status line */ /*=NP================================================================*/ /* Global data for new panel display */ /* (Note: all NPD mods are identified by the string =NP= */ /*===================================================================*/ static int NPDup = 0; /* 1 = new panel is up */ static int NPDinit = 0; /* 1 = new panel initialized */ static int NPhelpup = 0; /* 1 = help panel showing */ static int NPhelppaint = 1; /* 1 = help pnl s/b painted */ static int NPhelpdown = 0; /* 1 = help pnl coming down */ static int NPregdisp = 0; /* which regs are displayed: */ /* 0=gpr, 1=cr, 2=ar, 3=fpr */ static int NPcmd = 0; /* 1 = NP in command mode */ static int NPdataentry = 0; /* 1 = NP in data-entry mode */ static int NPdevsel = 0; /* 1 = device being selected */ static char NPpending; /* pending data entry cmd */ static char NPentered[256]; /* Data which was entered */ static char NPprompt1[40]; /* Left bottom screen prompt */ static char NPoldprompt1[40]; /* Left bottom screen prompt */ static char NPprompt2[40]; /* Right bottom screen prompt*/ static char NPoldprompt2[40]; /* Right bottom screen prompt*/ static char NPsel2; /* dev sel part 2 cmd letter */ static char NPdevice; /* Which device is selected */ static int NPasgn; /* Index to dev being init'ed*/ static int NPlastdev; /* Number of devices */ static int NPcpugraph_ncpu; /* Number of CPUs to display */ static char *NPregnum[] = {" 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7", " 8"," 9","10","11","12","13","14","15" }; static char *NPregnum64[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" }; /* Boolean fields; redraw the corresponding data field if false */ static int NPcpunum_valid, NPcpupct_valid, NPpsw_valid, NPpswstate_valid, NPregs_valid, NPaddr_valid, NPdata_valid, #ifdef OPTION_MIPS_COUNTING NPmips_valid, NPsios_valid, #endif // OPTION_MIPS_COUNTING NPdevices_valid, NPcpugraph_valid; /* Current CPU states */ //static U16 NPcpunum; //static int NPcpupct; static int NPpswmode; static int NPpswzhost; static QWORD NPpsw; static char NPpswstate[16]; static int NPregmode; static int NPregzhost; static U64 NPregs64[16]; static U32 NPregs[16]; static U32 NPaddress; static U32 NPdata; #ifdef OPTION_MIPS_COUNTING static U32 NPmips; static U32 NPsios; #else static U64 NPinstcount; #endif // OPTION_MIPS_COUNTING static int NPcpugraph; static int NPcpugraphpct[MAX_CPU_ENGINES]; /* Current device states */ #define NP_MAX_DEVICES (PANEL_MAX_ROWS - 3) static int NPonline[NP_MAX_DEVICES]; static U16 NPdevnum[NP_MAX_DEVICES]; static int NPbusy[NP_MAX_DEVICES]; static U16 NPdevtype[NP_MAX_DEVICES]; static int NPopen[NP_MAX_DEVICES]; static char NPdevnam[NP_MAX_DEVICES][128]; static short NPcurrow, NPcurcol; static int NPcolorSwitch; static short NPcolorFore; static short NPcolorBack; static int NPdatalen; static char *NPhelp[] = { /* 1 2 3 4 5 6 7 8 */ /* Line ....+....0....+....0....+....0....+....0....+....0....+....0....+....0....+....0 */ /* 1 */ "All commands consist of one character keypresses. The various commands are", /* 2 */ "highlighted onscreen by bright white versus the gray of other lettering.", /* 3 */ "Disabled buttons, commands and areas are not shown when operating without", /* 4 */ "defined CPUs (device server only mode).", /* 5 */ " ", /* 6 */ "Press the escape key to terminate the control panel and go to command mode.", /* 7 */ " ", /* 8 */ "Display Controls: G - General purpose regs C - Control regs", /* 9 */ " A - Access registers F - Floating Point regs", /* 10 */ " I - Display main memory at ADDRESS", /* 11 */ "CPU controls: L - IPL S - Start CPU", /* 12 */ " E - External interrupt P - Stop CPU", /* 13 */ " W - Exit Hercules T - Restart interrupt", /* 14 */ "Storage update: R - Enter ADDRESS to be updated", /* 15 */ " D - Enter DATA to be updated at ADDRESS", /* 16 */ " O - place DATA value at ADDRESS", /* 17 */ " ", /* 18 */ "Peripherals: N - enter a new name for the device file assignment", /* 19 */ " U - send an I/O attention interrupt", /* 20 */ " ", /* 21 */ "In the display of the first 26 devices, a green device letter means the device", /* 22 */ "is online, a highlighted device address means the device is busy, and a green", /* 23 */ "model number means the attached file is open to the device.", /* 24 */ " ", /* 25 */ " Press Escape to return to control panel operations", "" }; /////////////////////////////////////////////////////////////////////// #define MSG_SIZE PANEL_MAX_COLS /* Size of one message */ #define MAX_MSGS 2048 /* Number of slots in buffer */ //#define MAX_MSGS 300 /* (for testing scrolling) */ #define MSG_LINES (cons_rows - 2) /* #lines in message area */ #define SCROLL_LINES (MSG_LINES - numkept) /* #of scrollable lines */ #define CMD_SIZE 256 /* cmdline buffer size */ #define DEV_LINE 3 /* Line to start devices */ #define PSW_LINE 2 /* Line to place PSW */ #define REGS_LINE 5 /* Line to place REGS */ #define ADDR_LINE 15 /* Line to place Addr/data */ #define BUTTONS_LINE 17 /* Line to place Buttons */ #define CPU_GRAPH_LINE 20 /* Line to start CPU Graph */ /////////////////////////////////////////////////////////////////////// static int cons_rows = 0; /* console height in lines */ static int cons_cols = 0; /* console width in chars */ static short cur_cons_row = 0; /* current console row */ static short cur_cons_col = 0; /* current console column */ static char *cons_term = NULL; /* TERM env value */ static char cmdins = 1; /* 1==insert mode, 0==overlay*/ static char cmdline[CMD_SIZE+1]; /* Command line buffer */ static int cmdlen = 0; /* cmdline data len in bytes */ static int cmdoff = 0; /* cmdline buffer cursor pos */ static int cursor_on_cmdline = 1; /* bool: cursor on cmdline */ static char saved_cmdline[CMD_SIZE+1]; /* Saved command */ static int saved_cmdlen = 0; /* Saved cmdline data len */ static int saved_cmdoff = 0; /* Saved cmdline buffer pos */ static short saved_cons_row = 0; /* Saved console row */ static short saved_cons_col = 0; /* Saved console column */ static int cmdcols = 0; /* visible cmdline width cols*/ static int cmdcol = 0; /* cols cmdline scrolled righ*/ static FILE *confp = NULL; /* Console file pointer */ /////////////////////////////////////////////////////////////////////// #define CMD_PREFIX_HERC "herc =====> " /* Keep same len as below! */ #ifdef OPTION_CMDTGT #define CMD_PREFIX_SCP "scp ======> " /* Keep same len as above! */ #define CMD_PREFIX_PSCP "pscp =====> " /* Keep same len as above! */ #endif // OPTION_CMDTGT #define CMD_PREFIX_LEN (strlen(CMD_PREFIX_HERC)) #define CMDLINE_ROW ((short)(cons_rows-1)) #define CMDLINE_COL ((short)(CMD_PREFIX_LEN+1)) /////////////////////////////////////////////////////////////////////// #define ADJ_SCREEN_SIZE() \ do { \ int rows, cols; \ get_dim (&rows, &cols); \ if (rows != cons_rows || cols != cons_cols) { \ cons_rows = rows; \ cons_cols = cols; \ cmdcols = cons_cols - CMDLINE_COL; \ redraw_msgs = redraw_cmd = redraw_status = 1; \ NPDinit = 0; \ clr_screen(); \ } \ } while (0) #define ADJ_CMDCOL() /* (called after modifying cmdoff) */ \ do { \ if (cmdoff-cmdcol > cmdcols) { /* past right edge of screen */ \ cmdcol = cmdoff-cmdcols; \ } else if (cmdoff < cmdcol) { /* past left edge of screen */ \ cmdcol = cmdoff; \ } \ } while (0) #define PUTC_CMDLINE() \ do { \ ASSERT(cmdcol <= cmdlen); \ for (i=0; cmdcol+i < cmdlen && i < cmdcols; i++) \ draw_char (cmdline[cmdcol+i]); \ } while (0) /////////////////////////////////////////////////////////////////////// typedef struct _PANMSG /* Panel message control block structure */ { struct _PANMSG* next; /* --> next entry in chain */ struct _PANMSG* prev; /* --> prev entry in chain */ int msgnum; /* msgbuf 0-relative entry# */ char msg[MSG_SIZE]; /* text of panel message */ #if defined(OPTION_MSGCLR) short fg; /* text color */ short bg; /* screen background color */ #if defined(OPTION_MSGHLD) int keep:1; /* sticky flag */ struct timeval expiration; /* when to unstick if sticky */ #endif // defined(OPTION_MSGHLD) #endif // defined(OPTION_MSGCLR) } PANMSG; /* Panel message control block structure */ static PANMSG* msgbuf = NULL; /* Circular message buffer */ static PANMSG* topmsg = NULL; /* message at top of screen */ static PANMSG* curmsg = NULL; /* newest message */ static int wrapped = 0; /* wrapped-around flag */ static int numkept = 0; /* count of kept messages */ static int npquiet = 0; /* screen updating flag */ /////////////////////////////////////////////////////////////////////// static char *lmsbuf = NULL; /* xxx */ static int lmsndx = 0; /* xxx */ static int lmsnum = -1; /* xxx */ static int lmscnt = -1; /* xxx */ static int lmsmax = LOG_DEFSIZE/2; /* xxx */ static int keybfd = -1; /* Keyboard file descriptor */ static REGS copyregs, copysieregs; /* Copied regs */ /////////////////////////////////////////////////////////////////////// #if defined(OPTION_MSGCLR) /* -- Message coloring build option -- */ #if defined(OPTION_MSGHLD) /* -- Sticky messages build option -- */ #define KEEP_TIMEOUT_SECS 120 /* #seconds kept msgs expire */ static PANMSG* keptmsgs; /* start of keep chain */ static PANMSG* lastkept; /* last entry in keep chain */ /*-------------------------------------------------------------------*/ /* Remove and Free a keep chain entry from the keep chain */ /*-------------------------------------------------------------------*/ static void unkeep( PANMSG* pk ) { if (pk->prev) pk->prev->next = pk->next; if (pk->next) pk->next->prev = pk->prev; if (pk == keptmsgs) keptmsgs = pk->next; if (pk == lastkept) lastkept = pk->prev; free( pk ); numkept--; } /*-------------------------------------------------------------------*/ /* Allocate and Add a new kept message to the keep chain */ /*-------------------------------------------------------------------*/ static void keep( PANMSG* p ) { PANMSG* pk; ASSERT( p->keep ); pk = malloc( sizeof(PANMSG) ); memcpy( pk, p, sizeof(PANMSG) ); if (!keptmsgs) keptmsgs = pk; pk->next = NULL; pk->prev = lastkept; if (lastkept) lastkept->next = pk; lastkept = pk; numkept++; /* Must ensure we always have at least 2 scrollable lines */ while (SCROLL_LINES < 2) { /* Permanently unkeep oldest kept message */ msgbuf[keptmsgs->msgnum].keep = 0; unkeep( keptmsgs ); } } /*-------------------------------------------------------------------*/ /* Remove a kept message from the kept chain */ /*-------------------------------------------------------------------*/ static void unkeep_by_keepnum( int keepnum, int perm ) { PANMSG* pk; int i; /* Validate call */ if (!numkept || keepnum < 0 || keepnum > numkept-1) { ASSERT(FALSE); // bad 'keepnum' passed! return; } /* Chase keep chain to find kept message to be unkept */ for (i=0, pk=keptmsgs; pk && i != keepnum; pk = pk->next, i++); /* If kept message found, unkeep it */ if (pk) { if (perm) { msgbuf[pk->msgnum].keep = 0; #if defined(_DEBUG) || defined(DEBUG) msgbuf[pk->msgnum].fg = COLOR_YELLOW; #endif // defined(_DEBUG) || defined(DEBUG) } unkeep(pk); } } #endif // defined(OPTION_MSGHLD) #endif // defined(OPTION_MSGCLR) #if defined(OPTION_MSGHLD) /*-------------------------------------------------------------------*/ /* unkeep messages once expired */ /*-------------------------------------------------------------------*/ void expire_kept_msgs(int unconditional) { struct timeval now; PANMSG *pk = keptmsgs; int i; gettimeofday(&now, NULL); while (pk) { for (i=0, pk=keptmsgs; pk; i++, pk = pk->next) { if (unconditional || now.tv_sec >= pk->expiration.tv_sec) { unkeep_by_keepnum(i,1); // remove message from chain break; // start over again from the beginning } } } } #endif // defined(OPTION_MSGHLD) #if defined(OPTION_MSGCLR) /* -- Message coloring build option -- */ /*-------------------------------------------------------------------*/ /* Get the color name from a string */ /*-------------------------------------------------------------------*/ #define CHECKCOLOR(s, cs, c, cc) if(!strncasecmp(s, cs, sizeof(cs) - 1)) { *c = cc; return(sizeof(cs) - 1); } int get_color(char *string, short *color) { CHECKCOLOR(string, "black", color, COLOR_BLACK) else CHECKCOLOR(string, "cyan", color, COLOR_CYAN) else CHECKCOLOR(string, "blue", color, COLOR_BLUE) else CHECKCOLOR(string, "darkgrey", color, COLOR_DARK_GREY) else CHECKCOLOR(string, "green", color, COLOR_GREEN) else CHECKCOLOR(string, "lightblue", color, COLOR_LIGHT_BLUE) else CHECKCOLOR(string, "lightcyan", color, COLOR_LIGHT_CYAN) else CHECKCOLOR(string, "lightgreen", color, COLOR_LIGHT_GREEN) else CHECKCOLOR(string, "lightgrey", color, COLOR_LIGHT_GREY) else CHECKCOLOR(string, "lightmagenta", color, COLOR_LIGHT_MAGENTA) else CHECKCOLOR(string, "lightred", color, COLOR_LIGHT_RED) else CHECKCOLOR(string, "lightyellow", color, COLOR_LIGHT_YELLOW) else CHECKCOLOR(string, "magenta", color, COLOR_MAGENTA) else CHECKCOLOR(string, "red", color, COLOR_RED) else CHECKCOLOR(string, "white", color, COLOR_WHITE) else CHECKCOLOR(string, "yellow", color, COLOR_YELLOW) else return(0); } /*-------------------------------------------------------------------*/ /* Read, process and remove the "" colorizing message prefix */ /* Syntax: */ /* */ /* Mandatory prefix "" */ /* Valid tokens: */ /* color(fg, bg) specifies the message's color */ /* keep keeps message on screen until removed */ /* nokeep default - does not keep message */ /*-------------------------------------------------------------------*/ static void colormsg(PANMSG *p) { int i = 0; // current message text index int len; // length of color-name token int k = FALSE; // keep | nokeep ( no error is given, 1st prevails ) if(!strncasecmp(p->msg, "" panel command(s) i += 4; while(p->msg[i] == ',') { i += 1; // skip , if(!strncasecmp(&p->msg[i], "color(", 6)) { // inspect color command i += 6; // skip color( len = get_color(&p->msg[i], &p->fg); if(!len) break; // no valid color found i += len; // skip colorname if(p->msg[i] != ',') break; // no , i++; // skip , len = get_color(&p->msg[i], &p->bg); if(!len) break; // no valid color found i += len; // skip colorname if(p->msg[i] != ')') break; // no ) i++; // skip ) } else if(!strncasecmp(&p->msg[i], "keep", 4)) { #if defined(OPTION_MSGHLD) if ( !k ) { p->keep = 1; gettimeofday(&p->expiration, NULL); p->expiration.tv_sec += sysblk.keep_timeout_secs; } #endif // defined(OPTION_MSGHLD) i += 4; // skip keep k = TRUE; } else if(!strncasecmp(&p->msg[i], "nokeep", 6)) { #if defined(OPTION_MSGHLD) if ( !k ) { p->keep = 0; p->expiration.tv_sec = 0; p->expiration.tv_usec = 0; } #endif i += 6; // skip nokeep k = TRUE; } else break; // rubbish } if(p->msg[i] == '>') { // Remove "" string from message i += 1; memmove(p->msg, &p->msg[i], MSG_SIZE - i); memset(&p->msg[MSG_SIZE - i], SPACE, i); return; } } /* rubbish or no panel command */ p->fg = COLOR_DEFAULT_FG; p->bg = COLOR_DEFAULT_BG; #if defined(OPTION_MSGHLD) p->keep = 0; #endif // defined(OPTION_MSGHLD) } #endif // defined(OPTION_MSGCLR) /*-------------------------------------------------------------------*/ /* Screen manipulation primitives */ /*-------------------------------------------------------------------*/ static void beep() { console_beep( confp ); } static PANMSG* oldest_msg() { return (wrapped) ? curmsg->next : msgbuf; } static PANMSG* newest_msg() { return curmsg; } static int lines_scrolled() { /* return # of lines 'up' from current line that we're scrolled. */ if (topmsg->msgnum <= curmsg->msgnum) return curmsg->msgnum - topmsg->msgnum; return MAX_MSGS - (topmsg->msgnum - curmsg->msgnum); } static int visible_lines() { return (lines_scrolled() + 1); } static int is_currline_visible() { return (visible_lines() <= SCROLL_LINES); } static int lines_remaining() { return (SCROLL_LINES - visible_lines()); } static void scroll_up_lines( int numlines, int doexpire ) { int i; #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) for (i=0; i < numlines && topmsg != oldest_msg(); i++) { topmsg = topmsg->prev; // If new topmsg is simply the last entry in the keep chain // then we didn't really backup a line (all we did was move // our topmsg ptr), so if that's the case then we need to // continue backing up until we reach a non-kept message. // Only then is the screen actually scrolled up one line. #if defined(OPTION_MSGHLD) while (1 && topmsg->keep && lastkept && lastkept->msgnum == topmsg->msgnum ) { unkeep( lastkept ); if (topmsg == oldest_msg()) break; topmsg = topmsg->prev; } #endif } } static void scroll_down_lines( int numlines, int doexpire ) { int i; #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) for (i=0; i < numlines && topmsg != newest_msg(); i++) { // If the topmsg should be kept and is not already in our // keep chain, then adding it to our keep chain before // setting topmsg to the next entry does not really scroll // the screen any (all it does is move the topmsg ptr), // so if that's the case then we need to keep doing that // until we eventually find the next non-kept message. // Only then is the screen really scrolled down one line. #if defined(OPTION_MSGHLD) while (1 && topmsg->keep && (!lastkept || topmsg->msgnum != lastkept->msgnum) ) { keep( topmsg ); topmsg = topmsg->next; if (topmsg == newest_msg()) break; } #endif if (topmsg != newest_msg()) topmsg = topmsg->next; } } static void page_up( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) scroll_up_lines( SCROLL_LINES - 1, 0 ); } static void page_down( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) scroll_down_lines( SCROLL_LINES - 1, 0 ); } static void scroll_to_top_line( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) topmsg = oldest_msg(); #if defined(OPTION_MSGHLD) while (keptmsgs) unkeep( keptmsgs ); #endif } static void scroll_to_bottom_line( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) while (topmsg != newest_msg()) scroll_down_lines( 1, 0 ); } static void scroll_to_bottom_screen( int doexpire ) { #if defined(OPTION_MSGHLD) if (doexpire) expire_kept_msgs(0); #else UNREFERENCED(doexpire); #endif // defined(OPTION_MSGHLD) scroll_to_bottom_line( 0 ); page_up( 0 ); } static void do_panel_command( void* cmd ) { char *cmdsep; if (!is_currline_visible()) scroll_to_bottom_screen( 1 ); if (cmd != (void*)cmdline) strlcpy( cmdline, cmd, sizeof(cmdline) ); if ( sysblk.cmdsep != NULL && strlen(sysblk.cmdsep) == 1 && strstr(cmdline, sysblk.cmdsep) != NULL ) { char *command; char *strtok_str = NULL; command = strdup(cmdline); cmdsep = strtok_r(cmdline, sysblk.cmdsep, &strtok_str); while ( cmdsep != NULL ) { panel_command( cmdsep ); cmdsep = strtok_r(NULL, sysblk.cmdsep, &strtok_str); } history_add( command ); free(command); } else panel_command( cmdline ); cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); } static void do_prev_history() { if (history_prev() != -1) { strlcpy(cmdline, historyCmdLine, sizeof(cmdline) ); cmdlen = (int)strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); } } static void do_next_history() { if (history_next() != -1) { strlcpy(cmdline, historyCmdLine, sizeof(cmdline) ); cmdlen = (int)strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); } } static void clr_screen () { clear_screen (confp); } static void get_dim (int *y, int *x) { get_console_dim( confp, y, x); if (*y > PANEL_MAX_ROWS) *y = PANEL_MAX_ROWS; if (*x > PANEL_MAX_COLS) *x = PANEL_MAX_COLS; #if defined(WIN32) && !defined( _MSVC_ ) /* If running from a cygwin command prompt we do * better with one less row. */ if (!cons_term || strcmp(cons_term, "xterm")) (*y)--; #endif // defined(WIN32) && !defined( _MSVC_ ) } #if defined(OPTION_EXTCURS) static int get_keepnum_by_row( int row ) { // PROGRAMMING NOTE: right now all of our kept messages are // always placed at the very top of the screen (starting on // line 1), but should we at some point in the future decide // to use the very top line of the screen for something else // (such as a title or status line for example), then all we // need to do is modify the below variable and the code then // adjusts itself automatically. (I try to avoid hard-coded // constants whenever possible). -- Fish static int keep_beg_row = 1; // screen 1-relative line# of first kept msg if (0 || row < keep_beg_row || row > (keep_beg_row + numkept - 1) ) return -1; return (row - keep_beg_row); } #endif /*defined(OPTION_EXTCURS)*/ static void set_color (short fg, short bg) { set_screen_color (confp, fg, bg); } static void set_pos (short y, short x) { cur_cons_row = y; cur_cons_col = x; y = y < 1 ? 1 : y > cons_rows ? cons_rows : y; x = x < 1 ? 1 : x > cons_cols ? cons_cols : x; set_screen_pos (confp, y, x); } static int is_cursor_on_cmdline() { #if defined(OPTION_EXTCURS) get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); cursor_on_cmdline = (1 && cur_cons_row == CMDLINE_ROW && cur_cons_col >= CMDLINE_COL && cur_cons_col <= CMDLINE_COL + cmdcols ); #else // !defined(OPTION_EXTCURS) cursor_on_cmdline = 1; #endif // defined(OPTION_EXTCURS) return cursor_on_cmdline; } static void cursor_cmdline_home() { cmdoff = 0; ADJ_CMDCOL(); set_pos( CMDLINE_ROW, CMDLINE_COL ); } static void cursor_cmdline_end() { cmdoff = cmdlen; ADJ_CMDCOL(); set_pos( CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol ); } static void save_command_line() { memcpy( saved_cmdline, cmdline, sizeof(saved_cmdline) ); saved_cmdlen = cmdlen; saved_cmdoff = cmdoff; saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; } static void restore_command_line() { memcpy( cmdline, saved_cmdline, sizeof(cmdline) ); cmdlen = saved_cmdlen; cmdoff = saved_cmdoff; cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } static void draw_text (char *text) { int len; char *short_text; if (cur_cons_row < 1 || cur_cons_row > cons_rows || cur_cons_col < 1 || cur_cons_col > cons_cols) return; len = (int)strlen(text); if ((cur_cons_col + len - 1) <= cons_cols) fprintf (confp, "%s", text); else { len = cons_cols - cur_cons_col + 1; if ((short_text = strdup(text)) == NULL) return; short_text[len] = '\0'; fprintf (confp, "%s", short_text); free (short_text); } cur_cons_col += len; } static void write_text (char *text, int size) { if (cur_cons_row < 1 || cur_cons_row > cons_rows || cur_cons_col < 1 || cur_cons_col > cons_cols) return; if (cons_cols - cur_cons_col + 1 < size) size = cons_cols - cur_cons_col + 1; fwrite (text, size, 1, confp); cur_cons_col += size; } static void draw_char (int c) { if (cur_cons_row < 1 || cur_cons_row > cons_rows || cur_cons_col < 1 || cur_cons_col > cons_cols) return; fputc (c, confp); cur_cons_col++; } static void draw_fw (U32 fw) { char buf[9]; snprintf (buf, sizeof(buf), "%8.8X", fw); draw_text (buf); } static void draw_dw (U64 dw) { char buf[17]; snprintf (buf, sizeof(buf), "%16.16"I64_FMT"X", dw); draw_text (buf); } static void fill_text (char c, short x) { char buf[PANEL_MAX_COLS+1]; int len; if (x > PANEL_MAX_COLS) x = PANEL_MAX_COLS; len = x + 1 - cur_cons_col; if (len <= 0) return; memset( buf, c, len ); buf[len] = '\0'; draw_text (buf); } static void draw_button (short bg, short fg, short hfg, char *left, char *mid, char *right) { set_color (fg, bg); draw_text (left); set_color (hfg, bg); draw_text (mid); set_color (fg, bg); draw_text (right); } void set_console_title ( char *status ) { char title[256]; if ( sysblk.daemon_mode ) return; redraw_status = 1; if ( !sysblk.pantitle && ( !status || strlen(status) == 0 ) ) return; if ( !sysblk.pantitle ) { char msgbuf[256]; char sysname[16] = { 0 }; char sysplex[16] = { 0 }; char systype[16] = { 0 }; char lparnam[16] = { 0 }; memset( msgbuf, 0, sizeof(msgbuf) ); strlcat(systype,str_systype(),sizeof(systype)); strlcat(sysname,str_sysname(),sizeof(sysname)); strlcat(sysplex,str_sysplex(),sizeof(sysplex)); strlcat(lparnam,str_lparname(),sizeof(lparnam)); if ( strlen(lparnam)+strlen(systype)+strlen(sysname)+strlen(sysplex) > 0 ) { if ( strlen(lparnam) > 0 ) { strlcat(msgbuf, lparnam, sizeof(msgbuf)); if ( strlen(systype)+strlen(sysname)+strlen(sysplex) > 0 ) strlcat(msgbuf, " - ", sizeof(msgbuf)); } if ( strlen(systype) > 0 ) { strlcat(msgbuf, systype, sizeof(msgbuf)); if ( strlen(sysname)+strlen(sysplex) > 0 ) strlcat(msgbuf, " * ", sizeof(msgbuf)); } if ( strlen(sysname) > 0 ) { strlcat(msgbuf, sysname, sizeof(msgbuf)); if ( strlen(sysplex) > 0 ) strlcat(msgbuf, " * ", sizeof(msgbuf)); } if ( strlen(sysplex) > 0 ) { strlcat(msgbuf, sysplex, sizeof(msgbuf)); } MSGBUF( title, "%s - System Status: %s", msgbuf, status ); } else { MSGBUF( title, "System Status: %s", status ); } } else { if ( !status || strlen(status) == 0 ) MSGBUF( title, "%s", sysblk.pantitle ); else MSGBUF( title, "%s - System Status: %s", sysblk.pantitle, status ); } #if defined( _MSVC_ ) w32_set_console_title( title ); #else /*!defined(_MSVC_) */ /* For Unix systems we set the window title by sending a special escape sequence (depends on terminal type) to the console. See http://www.faqs.org/docs/Linux-mini/Xterm-Title.html */ if (!cons_term) return; if (strcmp(cons_term,"xterm")==0 || strcmp(cons_term,"rxvt")==0 || strcmp(cons_term,"dtterm")==0 || strcmp(cons_term,"screen")==0) { fprintf( confp, "%c]0;%s%c", '\033', title, '\007' ); } #endif /*!defined(_MSVC_) */ } /*=NP================================================================*/ /* Initialize the NP data */ /*===================================================================*/ static void NP_init() { NPdataentry = 0; strlcpy(NPprompt1, "", sizeof(NPprompt1)); strlcpy(NPprompt2, "", sizeof(NPprompt2)); } /*=NP================================================================*/ /* This draws the initial screen template */ /*===================================================================*/ static void NP_screen_redraw (REGS *regs) { int i, line; char buf[1024]; /* Force all data to be redrawn */ NPcpunum_valid = NPcpupct_valid = NPpsw_valid = NPpswstate_valid = NPregs_valid = NPaddr_valid = NPdata_valid = NPdevices_valid = NPcpugraph_valid = 0; #if defined(OPTION_MIPS_COUNTING) NPmips_valid = NPsios_valid = 0; #endif /*defined(OPTION_MIPS_COUNTING)*/ #if defined(_FEATURE_SIE) if(regs->sie_active) regs = regs->guestregs; #endif /*defined(_FEATURE_SIE)*/ /* * Draw the static parts of the NP screen */ set_color (COLOR_LIGHT_GREY, COLOR_BLACK ); clr_screen (); /* Line 1 - title line */ set_color (COLOR_WHITE, COLOR_BLUE ); set_pos (1, 1); draw_text (" Hercules"); if (sysblk.hicpu) { fill_text (' ', 16); draw_text ("CPU: %"); fill_text (' ', 30); draw_text ((char *)get_arch_mode_string(NULL)); } set_color (COLOR_LIGHT_GREY, COLOR_BLUE); fill_text (' ', 38); draw_text ("| "); set_color (COLOR_WHITE, COLOR_BLUE); #if defined(OPTION_SHARED_DEVICES) /* Center "Peripherals" on the right-hand-side */ i = 40 + snprintf(buf, sizeof(buf), "Peripherals [Shared Port %u]", sysblk.shrdport); if ((cons_cols < i) || !sysblk.shrdport) i = 52, buf[11] = 0; /* Truncate string */ if (cons_cols > i) /* Center string */ fill_text (' ', 40 + ((cons_cols - i) / 2)); draw_text (buf); fill_text (' ', (short)cons_cols); #endif // defined(OPTION_SHARED_DEVICES) /* Line 2 - peripheral headings */ set_pos (2, 41); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('U'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text(" Addr Modl Type Assig"); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('n'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text("ment"); if (sysblk.hicpu) { /* PSW_LINE = PSW */ NPpswmode = (regs->arch_mode == ARCH_900); NPpswzhost = #if defined(_FEATURE_SIE) !NPpswmode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900; #else 0; #endif /*defined(_FEATURE_SIE)*/ set_pos (PSW_LINE+1, NPpswmode || NPpswzhost ? 19 : 10); draw_text ("PSW"); /* Register area */ set_color (COLOR_LIGHT_GREY, COLOR_BLACK); NPregmode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); NPregzhost = #if defined(_FEATURE_SIE) (regs->arch_mode != ARCH_900 && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); #else 0; #endif /*defined(_FEATURE_SIE)*/ if (NPregmode == 1 || NPregzhost) { for (i = 0; i < 8; i++) { set_pos (REGS_LINE+i, 1); draw_text (NPregnum64[i*2]); set_pos (REGS_LINE+i, 20); draw_text (NPregnum64[i*2+1]); } } else { for (i = 0; i < 4; i++) { set_pos (i*2+(REGS_LINE+1),9); draw_text (NPregnum[i*4]); set_pos (i*2+(REGS_LINE+1),18); draw_text (NPregnum[i*4+1]); set_pos (i*2+(REGS_LINE+1),27); draw_text (NPregnum[i*4+2]); set_pos (i*2+(REGS_LINE+1),36); draw_text (NPregnum[i*4+3]); } } /* Register selection */ set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos ((REGS_LINE+8), 6); draw_text ("GPR"); set_pos ((REGS_LINE+8), 14); draw_text ("CR"); set_pos ((REGS_LINE+8), 22); draw_text ("AR"); set_pos ((REGS_LINE+8), 30); draw_text ("FPR"); /* Address and data */ set_pos (ADDR_LINE, 2); draw_text ("ADD"); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('R'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text ("ESS:"); set_pos (ADDR_LINE, 22); set_color (COLOR_WHITE, COLOR_BLACK); draw_char ('D'); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text ("ATA:"); } else { set_pos (8, 12); set_color (COLOR_LIGHT_RED, COLOR_BLACK); draw_text ("No CPUs defined"); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); } /* separator */ set_pos (ADDR_LINE+1, 1); fill_text ('-', 38); /* Buttons */ if (sysblk.hicpu) { set_pos (BUTTONS_LINE, 16); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " ST", "O", " " ); set_pos (BUTTONS_LINE, 24); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " D", "I", "S " ); set_pos (BUTTONS_LINE, 32); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " RS", "T", " " ); } #if defined(OPTION_MIPS_COUNTING) if (sysblk.hicpu) { set_pos ((BUTTONS_LINE+1), 3); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); draw_text ("MIPS"); } if (0 || sysblk.hicpu #if defined(OPTION_SHARED_DEVICES) || sysblk.shrdport #endif // defined(OPTION_SHARED_DEVICES) ) { set_pos ((BUTTONS_LINE+1), 10); draw_text ("IO/s"); } #endif /*defined(OPTION_MIPS_COUNTING)*/ if (sysblk.hicpu) { set_pos ((BUTTONS_LINE+2), 2); draw_button(COLOR_GREEN, COLOR_LIGHT_GREY, COLOR_WHITE, " ", "S", "TR "); set_pos ((BUTTONS_LINE+2), 9); draw_button(COLOR_RED, COLOR_LIGHT_GREY, COLOR_WHITE, " ST", "P", " " ); set_pos ((BUTTONS_LINE+2), 16); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " ", "E", "XT "); set_pos ((BUTTONS_LINE+2), 24); draw_button(COLOR_BLUE, COLOR_LIGHT_GREY, COLOR_WHITE, " IP", "L", " " ); } set_pos ((BUTTONS_LINE+2), 32); draw_button(COLOR_RED, COLOR_LIGHT_GREY, COLOR_WHITE, " P", "W", "R " ); set_color (COLOR_LIGHT_GREY, COLOR_BLACK); /* CPU busy graph */ line = CPU_GRAPH_LINE; // this is where the dashes start NPcpugraph_ncpu = MIN(cons_rows - line - 1, sysblk.hicpu); set_pos (line++, 1); fill_text ('-', 38); if (sysblk.hicpu) { NPcpugraph = 1; NPcpugraph_valid = 0; for (i = 0; i < NPcpugraph_ncpu; i++) { snprintf (buf, sizeof(buf), "%s%02X ", PTYPSTR(i), i); set_pos (line++, 1); draw_text (buf); } } else NPcpugraph = 0; /* Vertical separators */ for (i = 2; i <= cons_rows; i++) { set_pos (i , 39); draw_char ('|'); } /* Last line : horizontal separator */ if (cons_rows >= 24) { set_pos (cons_rows, 1); fill_text ('-', 38); draw_char ('|'); fill_text ('-', cons_cols); } /* positions the cursor */ set_pos (cons_rows, cons_cols); } static char *format_int(uint64_t ic) { static char obfr[32]; /* Enough for displaying 2^64-1 */ char grps[7][4]; /* 7 groups of 3 digits */ int maxg=0; int i; strlcpy(grps[0],"0",sizeof(grps[0]) ); while(ic>0) { int grp; grp=ic%1000; ic/=1000; if(ic==0) { snprintf(grps[maxg],sizeof(grps[maxg]),"%u",grp); grps[maxg][sizeof(grps[maxg])-1] = '\0'; } else { snprintf(grps[maxg],sizeof(grps[maxg]),"%3.3u",grp); grps[maxg][sizeof(grps[maxg])-1] = '\0'; } maxg++; } if(maxg) maxg--; obfr[0]=0; for(i=maxg;i>=0;i--) { strlcat(obfr,grps[i],sizeof(obfr)); if(i) { strlcat(obfr,",",sizeof(obfr)); } } return obfr; } /*=NP================================================================*/ /* This refreshes the screen with new data every cycle */ /*===================================================================*/ static void NP_update(REGS *regs) { int i, n; int mode, zhost; int cpupct_total; QWORD curpsw; U32 addr, aaddr; DEVBLK *dev; int online, busy, open; char *devclass; char devnam[MAX_PATH]; char buf[1024]; if (NPhelpup == 1) { if (NPhelpdown == 1) { NP_init(); NP_screen_redraw(regs); NPhelpup = 0; NPhelpdown = 0; NPhelppaint = 1; } else { if (NPhelppaint) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); clr_screen (); for (i = 0; *NPhelp[i]; i++) { set_pos (i+1, 1); draw_text (NPhelp[i]); } NPhelppaint = 0; } return; } } #if defined(_FEATURE_SIE) if(SIE_MODE(regs)) regs = regs->hostregs; #endif /*defined(_FEATURE_SIE)*/ #if defined(OPTION_MIPS_COUNTING) /* percent CPU busy */ if (sysblk.hicpu) { cpupct_total = 0; n = 0; for ( i = 0; i < sysblk.maxcpu; i++ ) if ( IS_CPU_ONLINE(i) ) if ( sysblk.regs[i]->cpustate == CPUSTATE_STARTED ) { n++; cpupct_total += sysblk.regs[i]->cpupct; } set_color (COLOR_WHITE, COLOR_BLUE); set_pos (1, 22); snprintf(buf, sizeof(buf), "%3d", (n > 0 ? cpupct_total/n : 0)); draw_text (buf); } #else // !defined(OPTION_MIPS_COUNTING) if (!NPcpupct_valid) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (1, 21); draw_text (" "); NPcpupct_valid = 1; } #endif /*defined(OPTION_MIPS_COUNTING)*/ if (sysblk.hicpu) { #if defined(_FEATURE_SIE) if(regs->sie_active) regs = regs->guestregs; #endif /*defined(_FEATURE_SIE)*/ mode = (regs->arch_mode == ARCH_900); zhost = #if defined(_FEATURE_SIE) !mode && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900; #else // !defined(_FEATURE_SIE) 0; #endif // defined(_FEATURE_SIE) /* Redraw the psw template if the mode changed */ if (NPpswmode != mode || NPpswzhost != zhost) { NPpswmode = mode; NPpswzhost = zhost; NPpsw_valid = NPpswstate_valid = 0; set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (PSW_LINE, 1); fill_text (' ',38); set_pos (PSW_LINE+1, 1); fill_text (' ', 38); set_pos (PSW_LINE+1, NPpswmode || NPpswzhost ? 19 : 10); draw_text ("PSW"); } /* Display the psw */ memset(curpsw, 0, sizeof(QWORD)); copy_psw (regs, curpsw); if (!NPpsw_valid || memcmp(NPpsw, curpsw, sizeof(QWORD))) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (PSW_LINE, 3); if (mode) { draw_dw (fetch_dw(curpsw)); set_pos (PSW_LINE, 22); draw_dw (fetch_dw(curpsw+8)); } else if (zhost) { draw_fw (fetch_fw(curpsw)); // draw_fw (0); draw_fw (fetch_fw(curpsw+4)); /* *JJ */ set_pos (PSW_LINE, 22); // draw_fw (fetch_fw(curpsw+4) & 0x80000000 ? 0x80000000 : 0); // draw_fw (fetch_fw(curpsw+4) & 0x7fffffff); draw_text("----------------"); /* *JJ */ } else { draw_fw (fetch_fw(curpsw)); set_pos (PSW_LINE, 12); draw_fw (fetch_fw(curpsw+4)); } NPpsw_valid = 1; memcpy (NPpsw, curpsw, sizeof(QWORD)); } /* Display psw state */ snprintf (buf, sizeof(buf), "%2d%c%c%c%c%c%c%c%c", regs->psw.amode64 ? 64 : regs->psw.amode ? 31 : 24, regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.', sysblk.inststep ? 'T' : '.', WAITSTATE (®s->psw) ? 'W' : '.', regs->loadstate ? 'L' : '.', regs->checkstop ? 'C' : '.', PROBSTATE(®s->psw) ? 'P' : '.', SIE_MODE(regs) ? 'S' : '.', mode ? 'Z' : '.'); if (!NPpswstate_valid || strcmp(NPpswstate, buf)) { set_color( COLOR_LIGHT_YELLOW, COLOR_BLACK ); set_pos( mode || zhost ? (PSW_LINE+1) : PSW_LINE, 28 ); draw_text( buf ); NPpswstate_valid = 1; strlcpy( NPpswstate, buf, sizeof(NPpswstate) ); } /* Redraw the register template if the regmode switched */ mode = (regs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); zhost = #if defined(_FEATURE_SIE) (regs->arch_mode != ARCH_900 && SIE_MODE(regs) && regs->hostregs->arch_mode == ARCH_900 && (NPregdisp == 0 || NPregdisp == 1)); #else // !defined(_FEATURE_SIE) 0; #endif /*defined(_FEATURE_SIE)*/ if (NPregmode != mode || NPregzhost != zhost) { NPregmode = mode; NPregzhost = zhost; NPregs_valid = 0; set_color (COLOR_LIGHT_GREY, COLOR_BLACK); if (NPregmode || NPregzhost) { /* 64 bit registers */ for (i = 0; i < 8; i++) { set_pos (REGS_LINE+i, 1); fill_text (' ', 38); set_pos (REGS_LINE+i, 1); draw_text (NPregnum64[i*2]); set_pos (REGS_LINE+i, 20); draw_text (NPregnum64[i*2+1]); } } else { /* 32 bit registers */ for (i = 0; i < 4; i++) { set_pos (i*2+REGS_LINE,1); fill_text (' ', 38); set_pos (i*2+(REGS_LINE+1),1); fill_text (' ', 38); set_pos (i*2+(REGS_LINE+1),9); draw_text (NPregnum[i*4]); set_pos (i*2+(REGS_LINE+1),18); draw_text (NPregnum[i*4+1]); set_pos (i*2+(REGS_LINE+1),27); draw_text (NPregnum[i*4+2]); set_pos (i*2+(REGS_LINE+1),36); draw_text (NPregnum[i*4+3]); } } } /* Display register values */ set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK ); if (NPregmode) { /* 64 bit registers */ for (i = 0; i < 16; i++) { switch (NPregdisp) { case 0: if (!NPregs_valid || NPregs64[i] != regs->GR_G(i)) { set_pos (REGS_LINE + i/2, 3 + (i%2)*19); draw_dw (regs->GR_G(i)); NPregs64[i] = regs->GR_G(i); } break; case 1: if (!NPregs_valid || NPregs64[i] != regs->CR_G(i)) { set_pos (REGS_LINE + i/2, 3 + (i%2)*19); draw_dw (regs->CR_G(i)); NPregs64[i] = regs->CR_G(i); } break; } } } else if (NPregzhost) { /* 32 bit registers on 64 bit template */ for (i = 0; i < 16; i++) { switch (NPregdisp) { case 0: if (!NPregs_valid || NPregs[i] != regs->GR_L(i)) { set_pos (REGS_LINE + i/2, 3 + (i%2)*19); // draw_fw (0); draw_text("--------"); draw_fw (regs->GR_L(i)); NPregs[i] = regs->GR_L(i); } break; case 1: if (!NPregs_valid || NPregs[i] != regs->CR_L(i)) { set_pos (REGS_LINE + i/2, 3 + (i%2)*19); // draw_fw (0); draw_text("--------"); draw_fw (regs->CR_L(i)); NPregs[i] = regs->CR_L(i); } break; } } } else { /* 32 bit registers */ addr = NPaddress; for (i = 0; i < 16; i++) { switch (NPregdisp) { default: case 0: if (!NPregs_valid || NPregs[i] != regs->GR_L(i)) { set_pos (REGS_LINE + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->GR_L(i)); NPregs[i] = regs->GR_L(i); } break; case 1: if (!NPregs_valid || NPregs[i] != regs->CR_L(i)) { set_pos (REGS_LINE + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->CR_L(i)); NPregs[i] = regs->CR_L(i); } break; case 2: if (!NPregs_valid || NPregs[i] != regs->AR(i)) { set_pos (REGS_LINE + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->AR(i)); NPregs[i] = regs->AR(i); } break; case 3: if (!NPregs_valid || NPregs[i] != regs->fpr[i]) { set_pos (REGS_LINE + (i/4)*2, 3 + (i%4)*9); draw_fw (regs->fpr[i]); NPregs[i] = regs->fpr[i]; } break; case 4: aaddr = APPLY_PREFIXING (addr, regs->PX); addr += 4; if (aaddr + 3 > regs->mainlim) break; if (!NPregs_valid || NPregs[i] != fetch_fw(regs->mainstor + aaddr)) { set_pos (REGS_LINE + (i/4)*2, 3 + (i%4)*9); draw_fw (fetch_fw(regs->mainstor + aaddr)); NPregs[i] = fetch_fw(regs->mainstor + aaddr); } break; } } } /* Update register selection indicator */ if (!NPregs_valid) { set_pos ((REGS_LINE+8), 6); set_color (NPregdisp == 0 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('G'); set_pos ((REGS_LINE+8), 14); set_color (NPregdisp == 1 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('C'); set_pos ((REGS_LINE+8), 22); set_color (NPregdisp == 2 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('A'); set_pos ((REGS_LINE+8), 30); set_color (NPregdisp == 3 ? COLOR_LIGHT_YELLOW : COLOR_WHITE, COLOR_BLACK); draw_char ('F'); } NPregs_valid = 1; /* Address & Data */ if (!NPaddr_valid) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (ADDR_LINE, 12); draw_fw (NPaddress); NPaddr_valid = 1; } if (!NPdata_valid) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (ADDR_LINE, 30); draw_fw (NPdata); NPdata_valid = 1; } } /* Rates */ #ifdef OPTION_MIPS_COUNTING if ((!NPmips_valid || sysblk.mipsrate != NPmips) && sysblk.hicpu) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (BUTTONS_LINE, 1); if((sysblk.mipsrate / 1000000) > 999) snprintf(buf, sizeof(buf), "%2d,%03d", sysblk.mipsrate / 1000000000, sysblk.mipsrate % 1000000000 / 1000000); else if((sysblk.mipsrate / 1000000) > 99) snprintf(buf, sizeof(buf), "%4d.%01d", sysblk.mipsrate / 1000000, sysblk.mipsrate % 1000000 / 100000); else if((sysblk.mipsrate / 1000000) > 9) snprintf(buf, sizeof(buf), "%3d.%02d", sysblk.mipsrate / 1000000, sysblk.mipsrate % 1000000 / 10000); else snprintf(buf, sizeof(buf), "%2d.%03d", sysblk.mipsrate / 1000000, sysblk.mipsrate % 1000000 / 1000); draw_text (buf); NPmips = sysblk.mipsrate; NPmips_valid = 1; } if (0 || (sysblk.hicpu && (!NPsios_valid || NPsios != sysblk.siosrate)) #if defined(OPTION_SHARED_DEVICES) || sysblk.shrdport #endif // defined(OPTION_SHARED_DEVICES) ) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (BUTTONS_LINE, 8); snprintf(buf, sizeof(buf), "%6.6s", format_int(sysblk.siosrate)); draw_text (buf); NPsios = sysblk.siosrate; NPsios_valid = 1; } #endif /* OPTION_MIPS_COUNTING */ /* Optional cpu graph */ if (NPcpugraph) { for (i = 0; i < NPcpugraph_ncpu; i++) { if (!IS_CPU_ONLINE(i)) { if (!NPcpugraph_valid || NPcpugraphpct[i] != -2.0) { set_color (COLOR_RED, COLOR_BLACK); set_pos (CPU_GRAPH_LINE+1+i, 6); draw_text ("OFFLINE"); fill_text (' ', 38); NPcpugraphpct[i] = -2.0; } } else if (sysblk.regs[i]->cpustate != CPUSTATE_STARTED) { if (!NPcpugraph_valid || NPcpugraphpct[i] != -1.0) { set_color (COLOR_LIGHT_YELLOW, COLOR_BLACK); set_pos (CPU_GRAPH_LINE+1+i, 6); draw_text ("STOPPED"); fill_text (' ', 38); NPcpugraphpct[i] = -1.0; } } else if (!NPcpugraph_valid || NPcpugraphpct[i] != sysblk.regs[i]->cpupct) { n = (34 * sysblk.regs[i]->cpupct) / 100; if (n == 0 && sysblk.regs[i]->cpupct > 0) n = 1; else if (n > 34) n = 34; set_color (n > 17 ? COLOR_WHITE : COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (CPU_GRAPH_LINE+1+i, 6); fill_text ('*', n+3); fill_text (' ', 38); NPcpugraphpct[i] = sysblk.regs[i]->cpupct; } if(sysblk.capvalue) { if(sysblk.ptyp[i] == SCCB_PTYP_CP) { if(sysblk.ptyp[i] == SCCB_PTYP_CP && sysblk.caplocked[i]) set_color(COLOR_LIGHT_RED, COLOR_BLACK); else set_color(COLOR_LIGHT_GREY, COLOR_BLACK); set_pos(CPU_GRAPH_LINE + i + 1, 1); snprintf(buf, sizeof(buf), "%s%02X", PTYPSTR(i), i); draw_text(buf); } } set_color (COLOR_LIGHT_GREY, COLOR_BLACK); } NPcpugraph_valid = 1; } /* Process devices */ for (i = 0, dev = sysblk.firstdev; dev != NULL; i++, dev = dev->nextdev) { if (i >= cons_rows - 3) break; if (!dev->allocated) continue; online = (dev->console && dev->connected) || strlen(dev->filename) > 0; busy = dev->busy != 0 || IOPENDING(dev) != 0; open = dev->fd > 2; /* device identifier */ if (!NPdevices_valid || online != NPonline[i]) { set_pos (DEV_LINE+i, 41); set_color (online ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK); draw_char (i < 26 ? 'A' + i : '.'); NPonline[i] = online; } /* device number */ if (!NPdevices_valid || dev->devnum != NPdevnum[i] || NPbusy[i] != busy) { set_pos (DEV_LINE+i, 43); set_color (busy ? COLOR_LIGHT_YELLOW : COLOR_LIGHT_GREY, COLOR_BLACK); snprintf (buf, sizeof(buf), "%4.4X", dev->devnum); draw_text (buf); NPdevnum[i] = dev->devnum; NPbusy[i] = busy; } /* device type */ if (!NPdevices_valid || dev->devtype != NPdevtype[i] || open != NPopen[i]) { set_pos (DEV_LINE+i, 48); set_color (open ? COLOR_LIGHT_GREEN : COLOR_LIGHT_GREY, COLOR_BLACK); snprintf (buf, sizeof(buf), "%4.4X", dev->devtype); draw_text (buf); NPdevtype[i] = dev->devtype; NPopen[i] = open; } /* device class and name */ (dev->hnd->query)(dev, &devclass, sizeof(devnam), devnam); if (!NPdevices_valid || strcmp(NPdevnam[i], devnam)) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (DEV_LINE+i, 53); snprintf (buf, sizeof(buf), "%-4.4s", devclass); draw_text (buf); /* Draw device name only if they're NOT assigning a new one */ if (0 || NPdataentry != 1 || NPpending != 'n' || NPasgn != i ) { /* locate first nonprintable and truncate */ int l, p; l = (int)strlen(devnam); for ( p = 0; p < l; p++ ) { if ( !isprint(devnam[p]) ) { devnam[p] = '\0'; break; } } set_pos (DEV_LINE+i, 58); draw_text (devnam); fill_text (' ', PANEL_MAX_COLS); } } } /* Complete the device state table */ if (!NPdevices_valid) { NPlastdev = i > 26 ? 26 : i - 1; for ( ; i < NP_MAX_DEVICES; i++) { NPonline[i] = NPdevnum[i] = NPbusy[i] = NPdevtype[i] = NPopen[i] = 0; strlcpy( NPdevnam[i], "", sizeof(NPdevnam[i]) ); } NPdevices_valid = 1; } /* Prompt 1 */ if (strcmp(NPprompt1, NPoldprompt1)) { strlcpy(NPoldprompt1, NPprompt1, sizeof(NPoldprompt1) ); if (strlen(NPprompt1) > 0) { set_color (COLOR_WHITE, COLOR_BLUE); set_pos (cons_rows, (40 - (short)strlen(NPprompt1)) / 2); draw_text (NPprompt1); } else if (cons_rows >= 24) { set_color (COLOR_LIGHT_GREY, COLOR_BLACK); set_pos (cons_rows, 1); fill_text ('-', 38); } } /* Prompt 2 */ if (strcmp(NPprompt2, NPoldprompt2)) { strlcpy(NPoldprompt2, NPprompt2, sizeof(NPoldprompt2) ); if (strlen(NPprompt2) > 0) { set_color(COLOR_WHITE, COLOR_BLUE); set_pos(cons_rows, 41); draw_text(NPprompt2); } else if (cons_rows >= 24) { set_color( COLOR_LIGHT_GREY, COLOR_BLACK ); set_pos( cons_rows, 41) ; fill_text( '-', cons_cols ); } } /* Data entry field */ if (NPdataentry && redraw_cmd) { set_pos (NPcurrow, NPcurcol); if (NPcolorSwitch) set_color (NPcolorFore, NPcolorBack); fill_text (' ', NPcurcol + NPdatalen - 1); set_pos (NPcurrow, NPcurcol); PUTC_CMDLINE(); redraw_cmd = 0; } else /* Position the cursor to the bottom right */ set_pos(cons_rows, cons_cols); } /* ============== End of the main NP block of code =============*/ static void panel_cleanup(void *unused); // (forward reference) #ifdef OPTION_MIPS_COUNTING /////////////////////////////////////////////////////////////////////// // "maxrates" command support... #define DEF_MAXRATES_RPT_INTVL ( 1440 ) DLL_EXPORT U32 curr_high_mips_rate = 0; // (high water mark for current interval) DLL_EXPORT U32 curr_high_sios_rate = 0; // (high water mark for current interval) DLL_EXPORT U32 prev_high_mips_rate = 0; // (saved high water mark for previous interval) DLL_EXPORT U32 prev_high_sios_rate = 0; // (saved high water mark for previous interval) DLL_EXPORT time_t curr_int_start_time = 0; // (start time of current interval) DLL_EXPORT time_t prev_int_start_time = 0; // (start time of previous interval) DLL_EXPORT U32 maxrates_rpt_intvl = DEF_MAXRATES_RPT_INTVL; DLL_EXPORT void update_maxrates_hwm() // (update high-water-mark values) { time_t current_time = 0; U32 elapsed_secs = 0; if (curr_high_mips_rate < sysblk.mipsrate) curr_high_mips_rate = sysblk.mipsrate; if (curr_high_sios_rate < sysblk.siosrate) curr_high_sios_rate = sysblk.siosrate; // Save high water marks for current interval... time( ¤t_time ); elapsed_secs = current_time - curr_int_start_time; if ( elapsed_secs >= ( maxrates_rpt_intvl * 60 ) ) { if (sysblk.panel_init) { panel_command( #if defined(OPTION_CMDTGT) "herc " #endif "maxrates"); } prev_high_mips_rate = curr_high_mips_rate; prev_high_sios_rate = curr_high_sios_rate; curr_high_mips_rate = 0; curr_high_sios_rate = 0; prev_int_start_time = curr_int_start_time; curr_int_start_time = current_time; } } #endif // OPTION_MIPS_COUNTING /////////////////////////////////////////////////////////////////////// REGS *copy_regs(int cpu) { REGS *regs; if (cpu < 0 || cpu >= sysblk.maxcpu) cpu = 0; obtain_lock (&sysblk.cpulock[cpu]); if ((regs = sysblk.regs[cpu]) == NULL) { release_lock(&sysblk.cpulock[cpu]); return &sysblk.dummyregs; } memcpy (©regs, regs, sysblk.regs_copy_len); if (copyregs.hostregs == NULL) { release_lock(&sysblk.cpulock[cpu]); return &sysblk.dummyregs; } #if defined(_FEATURE_SIE) if (regs->sie_active) { memcpy (©sieregs, regs->guestregs, sysblk.regs_copy_len); copyregs.guestregs = ©sieregs; copysieregs.hostregs = ©regs; regs = ©sieregs; } else #endif // defined(_FEATURE_SIE) regs = ©regs; SET_PSW_IA(regs); release_lock(&sysblk.cpulock[cpu]); return regs; } /*-------------------------------------------------------------------*/ /* Panel display thread */ /* */ /* This function runs on the main thread. It receives messages */ /* from the log task and displays them on the screen. It accepts */ /* panel commands from the keyboard and executes them. It samples */ /* the PSW periodically and displays it on the screen status line. */ /*-------------------------------------------------------------------*/ #if defined(OPTION_DYNAMIC_LOAD) void panel_display_r (void) #else void panel_display (void) #endif // defined(OPTION_DYNAMIC_LOAD) { #ifndef _MSVC_ int rc; /* Return code */ int maxfd; /* Highest file descriptor */ fd_set readset; /* Select file descriptors */ struct timeval tv; /* Select timeout structure */ #endif // _MSVC_ int i; /* Array subscripts */ int len; /* Length */ REGS *regs; /* -> CPU register context */ QWORD curpsw; /* Current PSW */ QWORD prvpsw; /* Previous PSW */ BYTE prvstate = 0xFF; /* Previous stopped state */ U64 prvicount = 0; /* Previous instruction count */ #if defined(OPTION_MIPS_COUNTING) U64 prvtcount = 0; /* Previous total count */ U64 totalcount = 0; /* sum of all instruction cnt */ U32 numcpu = 0; /* Online CPU count */ #endif /*defined(OPTION_MIPS_COUNTING)*/ int prvcpupct = 0; /* Previous cpu percentage */ #if defined(OPTION_SHARED_DEVICES) U32 prvscount = 0; /* Previous shrdcount */ #endif // defined(OPTION_SHARED_DEVICES) int prvpcpu = 0; /* Previous pcpu */ int prvparch = 0; /* Previous primary arch. */ char readbuf[MSG_SIZE]; /* Message read buffer */ int readoff = 0; /* Number of bytes in readbuf */ BYTE c; /* Character work area */ size_t kbbufsize = CMD_SIZE; /* Size of keyboard buffer */ char *kbbuf = NULL; /* Keyboard input buffer */ int kblen; /* Number of chars in kbbuf */ U32 aaddr; /* Absolute address for STO */ char buf[1024]; /* Buffer workarea */ SET_THREAD_NAME("panel_display"); set_thread_priority(0,0); /* (don't actually change priority) */ /* Display thread started message on control panel */ WRMSG (HHC00100, "I", thread_id(), get_thread_priority(0), "Control panel"); hdl_adsc("panel_cleanup",panel_cleanup, NULL); history_init(); #if defined( ENABLE_BUILTIN_SYMBOLS ) /* Set Some Function Key Defaults */ { set_symbol("PF01", "SUBST IMMED " #if defined(OPTION_CMDTGT) "herc " #endif "help &0"); set_symbol("PF11", "IMMED " #if defined(OPTION_CMDTGT) "herc " #endif "devlist TAPE"); set_symbol("PF10", "SUBST DELAY " #if defined(OPTION_CMDTGT) "herc " #endif "devinit &*"); } #endif /* #if defined( ENABLE_BUILTIN_SYMBOLS ) */ /* Set up the input file descriptors */ confp = stderr; keybfd = STDIN_FILENO; /* Initialize screen dimensions */ cons_term = getenv ("TERM"); get_dim (&cons_rows, &cons_cols); /* Clear the command-line buffer */ memset(cmdline, 0, sizeof(cmdline)); cmdcols = cons_cols - CMDLINE_COL; /* Obtain storage for the keyboard buffer */ if (!(kbbuf = malloc (kbbufsize))) { char buf[40]; MSGBUF(buf, "malloc(%d)", (int)kbbufsize); WRMSG(HHC00075, "E", buf, strerror(errno)); return; } /* Obtain storage for the circular message buffer */ msgbuf = malloc (MAX_MSGS * sizeof(PANMSG)); if (msgbuf == NULL) { char buf[40]; MSGBUF(buf, "malloc(%d)", (int)(MAX_MSGS * (int)sizeof(PANMSG))); fprintf (stderr, MSG(HHC00075, "E", buf, strerror(errno))); return; } /* Initialize circular message buffer */ for (curmsg = msgbuf, i=0; i < MAX_MSGS; curmsg++, i++) { curmsg->next = curmsg + 1; curmsg->prev = curmsg - 1; curmsg->msgnum = i; memset(curmsg->msg,SPACE,MSG_SIZE); #if defined(OPTION_MSGCLR) curmsg->bg = COLOR_DEFAULT_FG; curmsg->fg = COLOR_DEFAULT_BG; #if defined(OPTION_MSGHLD) curmsg->keep = 0; memset( &curmsg->expiration, 0, sizeof(curmsg->expiration) ); #endif // defined(OPTION_MSGHLD) #endif // defined(OPTION_MSGCLR) } /* Complete the circle */ msgbuf->prev = msgbuf + MAX_MSGS - 1; msgbuf->prev->next = msgbuf; /* Indicate "first-time" state */ curmsg = topmsg = NULL; wrapped = 0; numkept = 0; #if defined(OPTION_MSGHLD) keptmsgs = lastkept = NULL; #endif // defined(OPTION_MSGHLD) /* Set screen output stream to NON-buffered */ setvbuf (confp, NULL, _IONBF, 0); /* Put the terminal into cbreak mode */ set_or_reset_console_mode( keybfd, 1 ); /* Set console title */ set_console_title(NULL); /* Clear the screen */ set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); clr_screen (); redraw_msgs = redraw_cmd = redraw_status = 1; /* Notify logger_thread we're in control */ sysblk.panel_init = 1; #ifdef OPTION_MIPS_COUNTING /* Initialize "maxrates" command reporting intervals */ if ( maxrates_rpt_intvl == 1440 ) { time_t current_time; struct tm *current_tm; time_t since_midnight = 0; current_time = time( NULL ); current_tm = localtime( ¤t_time ); since_midnight = (time_t)( ( ( current_tm->tm_hour * 60 ) + current_tm->tm_min ) * 60 + current_tm->tm_sec ); curr_int_start_time = current_time - since_midnight; } else curr_int_start_time = time( NULL ); prev_int_start_time = curr_int_start_time; #endif /* Process messages and commands */ while ( 1 ) { #if defined( _MSVC_ ) /* Wait for keyboard input */ #define WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS (20) for (i= #if defined(PANEL_REFRESH_RATE) sysblk.panrate #else 500 #endif /WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS; i && !kbhit(); i--) Sleep(WAIT_FOR_KEYBOARD_INPUT_SLEEP_MILLISECS); ADJ_SCREEN_SIZE(); /* If keyboard input has [finally] arrived, then process it */ if ( kbhit() ) { /* Read character(s) from the keyboard */ kbbuf[0] = getch(); kbbuf[kblen=1] = '\0'; translate_keystroke( kbbuf, &kblen ); #else // !defined( _MSVC_ ) /* Set the file descriptors for select */ FD_ZERO (&readset); FD_SET (keybfd, &readset); FD_SET (logger_syslogfd[LOG_READ], &readset); FD_SET (0, &readset); if(keybfd > logger_syslogfd[LOG_READ]) maxfd = keybfd; else maxfd = logger_syslogfd[LOG_READ]; /* Wait for a message to arrive, a key to be pressed, or the inactivity interval to expire */ tv.tv_sec = #if defined(PANEL_REFRESH_RATE) sysblk.panrate #else 500 #endif / 1000; tv.tv_usec = ( #if defined(PANEL_REFRESH_RATE) sysblk.panrate #else 500 #endif * 1000) % 1000000; rc = select (maxfd + 1, &readset, NULL, NULL, &tv); if (rc < 0 ) { if (errno == EINTR) continue; fprintf (stderr, MSG(HHC00014, "E", strerror(errno) ) ); break; } ADJ_SCREEN_SIZE(); /* If keyboard input has arrived then process it */ if (FD_ISSET(keybfd, &readset)) { /* Read character(s) from the keyboard */ kblen = read (keybfd, kbbuf, kbbufsize-1); if (kblen < 0) { fprintf (stderr, MSG(HHC00015, "E", strerror(errno) ) ); break; } kbbuf[kblen] = '\0'; #endif // defined( _MSVC_ ) /* =NP= : Intercept NP commands & process */ if (NPDup == 1) { if (NPdevsel == 1) { NPdevsel = 0; NPdevice = kbbuf[0]; /* save the device selected */ kbbuf[0] = NPsel2; /* setup for 2nd part of rtn */ } if (NPdataentry == 0 && kblen == 1) { /* We are in command mode */ if (NPhelpup == 1) { if (kbbuf[0] == 0x1b) NPhelpdown = 1; kbbuf[0] = '\0'; redraw_status = 1; } cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); switch(kbbuf[0]) { case 0x1B: /* ESC */ NPDup = 0; restore_command_line(); ADJ_CMDCOL(); redraw_msgs = redraw_cmd = redraw_status = 1; npquiet = 0; // (forced for one paint cycle) break; case '?': NPhelpup = 1; redraw_status = 1; break; case 'S': /* START */ case 's': if (!sysblk.hicpu) break; do_panel_command( #if defined(OPTION_CMDTGT) "herc " #endif "startall"); break; case 'P': /* STOP */ case 'p': if (!sysblk.hicpu) break; do_panel_command( #if defined(OPTION_CMDTGT) "herc " #endif "stopall"); break; case 'O': /* Store */ case 'o': if (!sysblk.hicpu) break; regs = copy_regs(sysblk.pcpu); aaddr = APPLY_PREFIXING (NPaddress, regs->PX); if (aaddr > regs->mainlim) break; store_fw (regs->mainstor + aaddr, NPdata); redraw_status = 1; break; case 'I': /* Display */ case 'i': if (!sysblk.hicpu) break; NPregdisp = 4; NPregs_valid = 0; redraw_status = 1; break; case 'g': /* display GPR */ case 'G': if (!sysblk.hicpu) break; NPregdisp = 0; NPregs_valid = 0; redraw_status = 1; break; case 'a': /* Display AR */ case 'A': if (!sysblk.hicpu) break; NPregdisp = 2; NPregs_valid = 0; redraw_status = 1; break; case 'c': case 'C': /* Case CR */ if (!sysblk.hicpu) break; NPregdisp = 1; NPregs_valid = 0; redraw_status = 1; break; case 'f': /* Case FPR */ case 'F': if (!sysblk.hicpu) break; NPregdisp = 3; NPregs_valid = 0; redraw_status = 1; break; case 'r': /* Enter address */ case 'R': if (!sysblk.hicpu) break; NPdataentry = 1; redraw_cmd = 1; NPpending = 'r'; NPcurrow = 16; NPcurcol = 12; NPdatalen = 8; NPcolorSwitch = 1; NPcolorFore = COLOR_WHITE; NPcolorBack = COLOR_BLUE; strlcpy(NPentered, "", sizeof(NPentered) ); strlcpy(NPprompt1, "Enter Address", sizeof(NPprompt1) ); redraw_status = 1; break; case 'd': /* Enter data */ case 'D': if (!sysblk.hicpu) break; NPdataentry = 1; redraw_cmd = 1; NPpending = 'd'; NPcurrow = 16; NPcurcol = 30; NPdatalen = 8; NPcolorSwitch = 1; NPcolorFore = COLOR_WHITE; NPcolorBack = COLOR_BLUE; strlcpy(NPentered, "", sizeof(NPentered) ); strlcpy(NPprompt1, "Enter Data Value", sizeof(NPprompt1) ); redraw_status = 1; break; case 'l': /* IPL */ case 'L': if (!sysblk.hicpu) break; NPdevsel = 1; NPsel2 = 1; strlcpy(NPprompt2, "Select Device for IPL", sizeof(NPprompt2) ); redraw_status = 1; break; case 1: /* IPL - 2nd part */ if (!sysblk.hicpu) break; i = toupper(NPdevice) - 'A'; if (i < 0 || i > NPlastdev) { memset(NPprompt2,0,sizeof(NPprompt2)); redraw_status = 1; break; } sprintf (cmdline, #if defined(OPTION_CMDTGT) "herc " #endif "ipl %4.4x", NPdevnum[i]); do_panel_command(cmdline); memset(NPprompt2,0,sizeof(NPprompt2)); redraw_status = 1; break; case 'u': /* Device interrupt */ case 'U': NPdevsel = 1; NPsel2 = 2; strlcpy(NPprompt2, "Select Device for Interrupt", sizeof(NPprompt2)); redraw_status = 1; break; case 2: /* Device int: part 2 */ if (!sysblk.hicpu) break; i = toupper(NPdevice) - 'A'; if (i < 0 || i > NPlastdev) { memset(NPprompt2,0,sizeof(NPprompt2)); redraw_status = 1; break; } #if defined(OPTION_CMDTGT) MSGBUF( cmdline, "herc i %4.4x", NPdevnum[i]); #else MSGBUF( cmdline, "i %4.4x", NPdevnum[i]); #endif do_panel_command(cmdline); memset(NPprompt2,0,sizeof(NPprompt2)); redraw_status = 1; break; case 'n': /* Device Assignment */ case 'N': NPdevsel = 1; NPsel2 = 3; strlcpy(NPprompt2, "Select Device to Reassign", sizeof(NPprompt2)); redraw_status = 1; break; case 3: /* Device asgn: part 2 */ i = toupper(NPdevice) - 'A'; if (i < 0 || i > NPlastdev) { memset(NPprompt2,0,sizeof(NPprompt2)); redraw_status = 1; break; } NPdataentry = 1; redraw_cmd = 1; NPpending = 'n'; NPasgn = i; NPcurrow = 3 + i; NPcurcol = 58; NPdatalen = cons_cols - 57; NPcolorSwitch = 1; NPcolorFore = COLOR_DEFAULT_LIGHT; NPcolorBack = COLOR_BLUE; memset(NPentered,0,sizeof(NPentered)); strlcpy(NPprompt2, "New Name, or [enter] to Reload", sizeof(NPprompt2) ); redraw_status = 1; break; case 'W': /* POWER */ case 'w': NPdevsel = 1; NPsel2 = 4; strlcpy(NPprompt1, "Confirm Powerdown Y or N", sizeof(NPprompt1) ); redraw_status = 1; break; case 4: /* POWER - 2nd part */ if (NPdevice == 'y' || NPdevice == 'Y') do_panel_command( #if defined(OPTION_CMDTGT) "herc " #endif "quit"); memset(NPprompt1, 0, sizeof(NPprompt1)); redraw_status = 1; break; case 'T': /* Restart */ case 't': if (!sysblk.hicpu) break; NPdevsel = 1; NPsel2 = 5; strlcpy(NPprompt1, "Confirm Restart Y or N", sizeof(NPprompt1) ); redraw_status = 1; break; case 5: /* Restart - part 2 */ if (!sysblk.hicpu) break; if (NPdevice == 'y' || NPdevice == 'Y') do_panel_command( #if defined(OPTION_CMDTGT) "herc " #endif "restart"); memset(NPprompt1, 0, sizeof(NPprompt1)); redraw_status = 1; break; case 'E': /* Ext int */ case 'e': if (!sysblk.hicpu) break; NPdevsel = 1; NPsel2 = 6; strlcpy(NPprompt1, "Confirm External Interrupt Y or N", sizeof(NPprompt1)); redraw_status = 1; break; case 6: /* External - part 2 */ if (!sysblk.hicpu) break; if (NPdevice == 'y' || NPdevice == 'Y') do_panel_command( #if defined(OPTION_CMDTGT) "herc " #endif "ext"); memset(NPprompt1, 0, sizeof(NPprompt1)); redraw_status = 1; break; default: break; } NPcmd = 1; } else { /* We are in data entry mode */ if (kbbuf[0] == 0x1B) { /* Switch back to command mode */ NPdataentry = 0; NPaddr_valid = 0; NPdata_valid = 0; memset(NPprompt1, 0,sizeof(NPprompt1)); memset(NPprompt2, 0, sizeof(NPprompt2)); NPcmd = 1; } else NPcmd = 0; } if (NPcmd == 1) kblen = 0; /* don't process as command */ } /* =NP END= */ /* Process characters in the keyboard buffer */ for (i = 0; i < kblen; ) { #if defined ( _MSVC_ ) /* Test for PF key Windows */ if ( strlen(kbbuf+i) == 4 && kbbuf[i] == '\x1b' && kbbuf[i+1] == ')' ) /* this is a PF Key */ { char szPF[6]; char msgbuf[32]; char *pf; char *psz_PF; int j; MSGBUF( szPF, "PF%s", kbbuf+2 ); szPF[4] = '\0'; #else // ! _MSVC_ if ( !strcmp(kbbuf+i, KBD_PF1) || !strcmp(kbbuf+i, KBD_PF1_a) || !strcmp(kbbuf+i, KBD_PF2) || !strcmp(kbbuf+i, KBD_PF2_a) || !strcmp(kbbuf+i, KBD_PF3) || !strcmp(kbbuf+i, KBD_PF3_a) || !strcmp(kbbuf+i, KBD_PF4) || !strcmp(kbbuf+i, KBD_PF4_a) || !strcmp(kbbuf+i, KBD_PF5) || !strcmp(kbbuf+i, KBD_PF6 ) || !strcmp(kbbuf+i, KBD_PF7) || !strcmp(kbbuf+i, KBD_PF8 ) || !strcmp(kbbuf+i, KBD_PF9) || !strcmp(kbbuf+i, KBD_PF10 ) || !strcmp(kbbuf+i, KBD_PF11)|| !strcmp(kbbuf+i, KBD_PF12 ) || !strcmp(kbbuf+i, KBD_PF13)|| !strcmp(kbbuf+i, KBD_PF14 ) || !strcmp(kbbuf+i, KBD_PF15)|| !strcmp(kbbuf+i, KBD_PF16 ) || !strcmp(kbbuf+i, KBD_PF17)|| !strcmp(kbbuf+i, KBD_PF18 ) || !strcmp(kbbuf+i, KBD_PF19)|| !strcmp(kbbuf+i, KBD_PF20 ) ) { char *szPF; char msgbuf[32]; char *pf; char *psz_PF; int j; if ( !strcmp(kbbuf+i, KBD_PF1) || !strcmp(kbbuf+i, KBD_PF1_a) ) szPF = "PF01"; else if ( !strcmp(kbbuf+i, KBD_PF2) || !strcmp(kbbuf+i, KBD_PF2_a) ) szPF = "PF02"; else if ( !strcmp(kbbuf+i, KBD_PF3) || !strcmp(kbbuf+i, KBD_PF3_a) ) szPF = "PF03"; else if ( !strcmp(kbbuf+i, KBD_PF4) || !strcmp(kbbuf+i, KBD_PF4_a) ) szPF = "PF04"; else if ( !strcmp(kbbuf+i, KBD_PF5) ) szPF = "PF05"; else if ( !strcmp(kbbuf+i, KBD_PF6) ) szPF = "PF06"; else if ( !strcmp(kbbuf+i, KBD_PF7) ) szPF = "PF07"; else if ( !strcmp(kbbuf+i, KBD_PF8) ) szPF = "PF08"; else if ( !strcmp(kbbuf+i, KBD_PF9) ) szPF = "PF09"; else if ( !strcmp(kbbuf+i, KBD_PF10) ) szPF = "PF10"; else if ( !strcmp(kbbuf+i, KBD_PF11) ) szPF = "PF11"; else if ( !strcmp(kbbuf+i, KBD_PF12) ) szPF = "PF12"; else if ( !strcmp(kbbuf+i, KBD_PF13) ) szPF = "PF13"; else if ( !strcmp(kbbuf+i, KBD_PF14) ) szPF = "PF14"; else if ( !strcmp(kbbuf+i, KBD_PF15) ) szPF = "PF15"; else if ( !strcmp(kbbuf+i, KBD_PF16) ) szPF = "PF16"; else if ( !strcmp(kbbuf+i, KBD_PF17) ) szPF = "PF17"; else if ( !strcmp(kbbuf+i, KBD_PF18) ) szPF = "PF18"; else if ( !strcmp(kbbuf+i, KBD_PF19) ) szPF = "PF19"; else if ( !strcmp(kbbuf+i, KBD_PF20) ) szPF = "PF20"; else szPF = NULL; #endif #if defined(ENABLE_BUILTIN_SYMBOLS) pf = (char*)get_symbol(szPF); #else pf = NULL; #endif if ( pf == NULL ) { #if defined(OPTION_CMDTGT) MSGBUF( msgbuf, "DELAY herc * %s UNDEFINED", szPF ); #else MSGBUF( msgbuf, "DELAY * %s UNDEFINED", szPF ); #endif pf = msgbuf; } psz_PF = strdup(pf); /* test for 1st of IMMED, DELAY or SUBST */ for ( j = 0; j < (int)strlen(psz_PF); j++ ) if ( psz_PF[j] != ' ' ) break; if ( !strncasecmp( psz_PF+j, "IMMED ", 6 ) ) { for ( j += 5; j < (int)strlen(psz_PF); j++ ) if ( psz_PF[j] != ' ' ) break; do_panel_command( psz_PF+j ); } else if ( !strncasecmp( psz_PF+j, "DELAY ", 6 ) ) { for ( j += 5; j < (int)strlen(psz_PF); j++ ) if ( psz_PF[j] != ' ' ) break; strcpy( cmdline, psz_PF+j ); cmdlen = (int)strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); } else if ( !strncasecmp( psz_PF+j, "SUBST ", 6 ) ) { int isdelay = TRUE; char *cmd_tok[11] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int ncmd_tok = 0; char *pt1; for ( j += 5; j < (int)strlen(psz_PF); j++ ) if ( psz_PF[j] != ' ' ) break; if ( !strncasecmp( psz_PF+j, "IMMED ", 6 ) ) { isdelay = FALSE; for ( j += 5; j < (int)strlen(psz_PF); j++ ) if ( psz_PF[j] != ' ' ) break; } else if ( !strncasecmp( psz_PF+j, "DELAY ", 6 ) ) { for ( j += 5; j < (int)strlen(psz_PF); j++ ) if ( psz_PF[j] != ' ' ) break; } if ( ( cmdlen = (int)strlen(cmdline) ) > 0 ) { char psz_cmdline[sizeof(cmdline)]; char *p = cmdline; while (*p && ncmd_tok < 10 ) { while (*p && isspace(*p)) p++; if (!*p) break; // find start of arg if (*p == '#') break; // stop on comments cmd_tok[ncmd_tok] = p; ++ncmd_tok; // count new arg while ( *p && !isspace(*p) && *p != '\"' && *p != '\'' ) p++; if (!*p) break; // find end of arg if (*p == '\"' || *p == '\'') { char delim = *p; do {} while (*++p && *p != delim); if (!*p) break; // find end of quoted string p++; if (!*p) break; // found end of args if ( *p != ' ') { strlcpy(psz_cmdline, p, sizeof(cmdline)); *p = ' '; // insert a space strcpy(p+1, psz_cmdline); psz_cmdline[0] = 0; } } *p++ = 0; // mark end of arg } ncmd_tok--; /* token 10 represents the rest of the line */ if ( ncmd_tok == 9 && strlen(p) > 0 ) cmd_tok[++ncmd_tok] = p; } { int ctok = -1; int odx = 0; int idx = 0; char psz_cmdline[(sizeof(cmdline) * 11)]; memset(psz_cmdline, 0, sizeof(psz_cmdline)); pt1 = psz_PF+j; for ( idx = 0; idx < (int)strlen(pt1); idx++ ) { if ( pt1[idx] != '&' ) { psz_cmdline[odx++] = pt1[idx]; } else { if ( pt1[idx+1] == '&' ) { idx++; psz_cmdline[odx++] = pt1[idx]; } else if ( pt1[idx+1] == '*' ) { idx++; if ( ctok < 9 ) { int first = TRUE; for( ctok++; ctok <= 10; ctok++ ) { if ( cmd_tok[ctok] != NULL ) { if ( first ) first = FALSE; else psz_cmdline[odx++] = ' '; // add one space strcpy( &psz_cmdline[odx], cmd_tok[ctok] ); odx += (int)strlen(cmd_tok[ctok]); } } } } else if ( !isdigit( pt1[idx+1] ) && ( pt1[idx+1] != '$' ) ) { psz_cmdline[odx++] = pt1[idx]; } else { idx++; if ( pt1[idx] == '$' ) ctok = 10; else { ctok = (int)pt1[idx] - '0'; if ( ctok < 0 || ctok > 9 ) ctok = 10; } if ( cmd_tok[ctok] != NULL && strlen( cmd_tok[ctok] ) > 0 ) { strncpy(&psz_cmdline[odx], cmd_tok[ctok], strlen( cmd_tok[ctok] ) ); odx += (int)strlen( cmd_tok[ctok] ); } else psz_cmdline[odx++] = ' '; } } if ( odx > (int)sizeof(cmdline) ) { WRMSG(HHC01608, "W", ((int)sizeof(cmdline) - 1) ); break; } } if ( isdelay ) { strncpy( cmdline, psz_cmdline, sizeof(cmdline) ); cmdline[sizeof(cmdline) - 1] = 0; cmdlen = (int)strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); } else do_panel_command( psz_cmdline ); } } else /* this is the same as IMMED */ { do_panel_command( psz_PF ); } free(psz_PF); redraw_cmd = 1; redraw_msgs = 1; break; } /* Test for HOME */ if (strcmp(kbbuf+i, KBD_HOME) == 0) { if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) { cursor_cmdline_home(); redraw_cmd = 1; } else { scroll_to_top_line( 1 ); redraw_msgs = 1; } break; } /* Test for END */ if (strcmp(kbbuf+i, KBD_END) == 0) { if (NPDup == 1 || !is_cursor_on_cmdline() || cmdlen) { cursor_cmdline_end(); redraw_cmd = 1; } else { scroll_to_bottom_screen( 1 ); redraw_msgs = 1; } break; } /* Test for CTRL+HOME */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_HOME) == 0) { scroll_to_top_line( 1 ); redraw_msgs = 1; break; } /* Test for CTRL+END */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_END) == 0) { scroll_to_bottom_line( 1 ); redraw_msgs = 1; break; } /* Process UPARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_UP_ARROW) == 0) { do_prev_history(); redraw_cmd = 1; break; } /* Process DOWNARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_DOWN_ARROW) == 0) { do_next_history(); redraw_cmd = 1; break; } #if defined(OPTION_EXTCURS) /* Process ALT+UPARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_UP_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_row <= 1) cur_cons_row = cons_rows + 1; set_pos( --cur_cons_row, cur_cons_col ); break; } /* Process ALT+DOWNARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_DOWN_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_row >= cons_rows) cur_cons_row = 1 - 1; set_pos( ++cur_cons_row, cur_cons_col ); break; } #endif // defined(OPTION_EXTCURS) /* Test for PAGEUP */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_UP) == 0) { page_up( 1 ); redraw_msgs = 1; break; } /* Test for PAGEDOWN */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_PAGE_DOWN) == 0) { page_down( 1 ); redraw_msgs = 1; break; } /* Test for CTRL+UPARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_UP_ARROW) == 0) { scroll_up_lines(1,1); redraw_msgs = 1; break; } /* Test for CTRL+DOWNARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_CTRL_DOWN_ARROW) == 0) { scroll_down_lines(1,1); redraw_msgs = 1; break; } /* Process BACKSPACE */ if (kbbuf[i] == '\b' || kbbuf[i] == '\x7F') { if (NPDup == 0 && !is_cursor_on_cmdline()) beep(); else { if (cmdoff > 0) { int j; for (j = cmdoff-1; j 0) cmdoff--; ADJ_CMDCOL(); i++; redraw_cmd = 1; break; } /* Process RIGHTARROW */ if (strcmp(kbbuf+i, KBD_RIGHT_ARROW) == 0) { if (cmdoff < cmdlen) cmdoff++; ADJ_CMDCOL(); i++; redraw_cmd = 1; break; } #if defined(OPTION_EXTCURS) /* Process ALT+LEFTARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_LEFT_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_col <= 1) { cur_cons_row--; cur_cons_col = cons_cols + 1; } if (cur_cons_row < 1) cur_cons_row = cons_rows; set_pos( cur_cons_row, --cur_cons_col ); break; } /* Process ALT+RIGHTARROW */ if (NPDup == 0 && strcmp(kbbuf+i, KBD_ALT_RIGHT_ARROW) == 0) { get_cursor_pos( keybfd, confp, &cur_cons_row, &cur_cons_col ); if (cur_cons_col >= cons_cols) { cur_cons_row++; cur_cons_col = 0; } if (cur_cons_row > cons_rows) cur_cons_row = 1; set_pos( cur_cons_row, ++cur_cons_col ); break; } #endif // defined(OPTION_EXTCURS) /* Process INSERT */ if (strcmp(kbbuf+i, KBD_INSERT) == 0 ) { cmdins = !cmdins; set_console_cursor_shape( confp, cmdins ); i++; break; } /* Process ESCAPE */ if (kbbuf[i] == '\x1B') { /* If data on cmdline, erase it */ if ((NPDup == 1 || is_cursor_on_cmdline()) && cmdlen) { cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); redraw_cmd = 1; } else { /* =NP= : Switch to new panel display */ save_command_line(); NP_init(); NPDup = 1; /* =END= */ } break; } /* Process TAB */ if (kbbuf[i] == '\t' || kbbuf[i] == '\x7F') { if (NPDup == 1 || !is_cursor_on_cmdline()) { cursor_cmdline_home(); redraw_cmd = 1; } else { tab_pressed(cmdline, sizeof(cmdline), &cmdoff); cmdlen = (int)strlen(cmdline); ADJ_CMDCOL(); i++; redraw_cmd = 1; } break; } #if defined(OPTION_EXTCURS) /* ENTER key special handling */ if (NPDup == 0 && kbbuf[i] == '\n') { /* Get cursor pos and check if on cmdline */ if (!is_cursor_on_cmdline()) { int keepnum = get_keepnum_by_row( cur_cons_row ); if (keepnum >= 0) { #if defined(OPTION_MSGHLD) /* ENTER pressed on kept msg; remove msg */ unkeep_by_keepnum( keepnum, 1 ); #endif redraw_msgs = 1; break; } /* ENTER pressed NOT on cmdline */ beep(); break; } /* ENTER pressed on cmdline; fall through for normal ENTER keypress handling... */ } #endif // defined(OPTION_EXTCURS) /* Process the command when the ENTER key is pressed */ if (kbbuf[i] == '\n') { if (1 && cmdlen == 0 && NPDup == 0 && !sysblk.inststep #if defined( OPTION_CMDTGT ) && sysblk.cmdtgt == CMDTGT_HERC #endif /* defined( OPTION_CMDTGT ) */ ) { history_show(); } else { cmdline[cmdlen] = '\0'; /* =NP= create_thread replaced with: */ if (NPDup == 0) { if ('#' == cmdline[0] || '*' == cmdline[0]) { if (!is_currline_visible()) scroll_to_bottom_screen( 1 ); history_requested = 0; do_panel_command(cmdline); redraw_cmd = 1; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); redraw_cmd = 1; } else { history_requested = 0; do_panel_command(cmdline); redraw_cmd = 1; if (history_requested == 1) { strcpy(cmdline, historyCmdLine); cmdlen = (int)strlen(cmdline); cmdoff = cmdlen < cmdcols ? cmdlen : 0; ADJ_CMDCOL(); redraw_cmd = 1; cursor_cmdline_end(); break; } } } else { NPdataentry = 0; NPcurrow = cons_rows; NPcurcol = cons_cols; NPcolorSwitch = 0; switch (NPpending) { case 'r': sscanf(cmdline, "%x", &NPaddress); NPaddr_valid = 0; strcpy(NPprompt1, ""); break; case 'd': sscanf(cmdline, "%x", &NPdata); NPdata_valid = 0; strcpy(NPprompt1, ""); break; case 'n': if (strlen(cmdline) < 1) { strcpy(cmdline, NPdevnam[NPasgn]); } strcpy(NPdevnam[NPasgn], ""); sprintf (NPentered, #if defined(OPTION_CMDTGT) "herc " #endif "devinit %4.4x %s", NPdevnum[NPasgn], cmdline); do_panel_command(NPentered); strcpy(NPprompt2, ""); break; default: break; } redraw_status = 1; cmdline[0] = '\0'; cmdlen = 0; cmdoff = 0; ADJ_CMDCOL(); } /* =END= */ redraw_cmd = 1; } break; } /* end if (kbbuf[i] == '\n') */ /* Ignore non-printable characters */ if (!isprint(kbbuf[i])) { beep(); i++; continue; } /* Ignore all other keystrokes not on cmdline */ if (NPDup == 0 && !is_cursor_on_cmdline()) { beep(); break; } /* Append the character to the command buffer */ ASSERT(cmdlen <= CMD_SIZE-1 && cmdoff <= cmdlen); if (0 || (cmdoff >= CMD_SIZE-1) || (cmdins && cmdlen >= CMD_SIZE-1) ) { /* (no more room!) */ beep(); } else /* (there's still room) */ { ASSERT(cmdlen < CMD_SIZE-1 || (!cmdins && cmdoff < cmdlen)); if (cmdoff >= cmdlen) { /* Append to end of buffer */ ASSERT(!(cmdoff > cmdlen)); // (sanity check) cmdline[cmdoff++] = kbbuf[i]; cmdline[cmdoff] = '\0'; cmdlen++; } else { ASSERT(cmdoff < cmdlen); if (cmdins) { /* Insert: make room by sliding all following chars right one position */ int j; for (j=cmdlen-1; j>=cmdoff; j--) cmdline[j+1] = cmdline[j]; cmdline[cmdoff++] = kbbuf[i]; cmdlen++; } else { /* Overlay: replace current position */ cmdline[cmdoff++] = kbbuf[i]; } } ADJ_CMDCOL(); redraw_cmd = 1; } i++; } /* end for(i) */ } /* end if keystroke */ FinishShutdown: // If we finished processing all of the message data // the last time we were here, then get some more... if ( lmsndx >= lmscnt ) // (all previous data processed?) { lmscnt = log_read( &lmsbuf, &lmsnum, LOG_NOBLOCK ); lmsndx = 0; } else if ( lmsndx >= lmsmax ) { lmsbuf += lmsndx; // pick up where we left off at... lmscnt -= lmsndx; // pick up where we left off at... lmsndx = 0; } // Process all message data or until limit reached... // (limiting the amount of data we process a console message flood // from preventing keyboard from being read since we need to break // out of the below message data processing loop to loop back up // to read the keyboard again...) /* Read message bytes until newline... */ while ( lmsndx < lmscnt && lmsndx < lmsmax ) { /* Initialize the read buffer */ if (!readoff || readoff >= MSG_SIZE) { memset (readbuf, SPACE, MSG_SIZE); readoff = 0; } /* Read message bytes and copy into read buffer until we either encounter a newline character or our buffer is completely filled with data. */ while ( lmsndx < lmscnt && lmsndx < lmsmax ) { /* Read a byte from the message pipe */ c = *(lmsbuf + lmsndx); lmsndx++; /* Break to process received message whenever a newline is encountered */ if (c == '\n' || c == '\r') { readoff = 0; /* (for next time) */ break; } /* Handle tab character */ if (c == '\t') { readoff += 8; readoff &= 0xFFFFFFF8; /* Messages longer than one screen line will be continued on the very next screen line */ if (readoff >= MSG_SIZE) break; else continue; } /* Eliminate non-displayable characters */ if (!isgraph(c)) c = SPACE; /* Stuff byte into message processing buffer */ readbuf[readoff++] = c; /* Messages longer than one screen line will be continued on the very next screen line */ if (readoff >= MSG_SIZE) break; } /* end while ( lmsndx < lmscnt && lmsndx < lmsmax ) */ /* If we have a message to be displayed (or a complete part of one), then copy it to the circular buffer. */ if (!readoff || readoff >= MSG_SIZE) { /* First-time here? */ if (curmsg == NULL) { curmsg = topmsg = msgbuf; } else { /* Perform autoscroll if needed */ if (is_currline_visible()) { while (lines_remaining() < 1) scroll_down_lines(1,1); /* Set the display update indicator */ redraw_msgs = 1; } /* Go on to next available msg buffer */ curmsg = curmsg->next; /* Updated wrapped indicator */ if (curmsg == msgbuf) wrapped = 1; } /* Copy message into next available PANMSG slot */ memcpy( curmsg->msg, readbuf, MSG_SIZE ); #if defined(OPTION_MSGCLR) /* Colorize and/or keep new message if needed */ colormsg(curmsg); #endif // defined(OPTION_MSGCLR) } /* end if (!readoff || readoff >= MSG_SIZE) */ } /* end Read message bytes until newline... */ /* Don't read or otherwise process any input once system shutdown has been initiated */ if ( sysblk.shutdown ) { if ( sysblk.shutfini ) break; /* wait for system to finish shutting down */ usleep(10000); lmsmax = INT_MAX; goto FinishShutdown; } /* =NP= : Reinit traditional panel if NP is down */ if (NPDup == 0 && NPDinit == 1) { redraw_msgs = redraw_status = redraw_cmd = 1; set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); clr_screen (); } /* =END= */ /* Obtain the PSW for target CPU */ regs = copy_regs(sysblk.pcpu); memset( curpsw, 0, sizeof(curpsw) ); copy_psw (regs, curpsw); totalcount = 0; numcpu = 0; for ( i = 0; i < sysblk.maxcpu; ++i ) if ( IS_CPU_ONLINE(i) ) ++numcpu, totalcount += INSTCOUNT(sysblk.regs[i]); /* Set the display update indicator if the PSW has changed or if the instruction counter has changed, or if the CPU stopped state has changed */ if (memcmp(curpsw, prvpsw, sizeof(curpsw)) != 0 || prvicount != totalcount || prvcpupct != regs->cpupct #if defined(OPTION_SHARED_DEVICES) || prvscount != sysblk.shrdcount #endif // defined(OPTION_SHARED_DEVICES) || prvstate != regs->cpustate #if defined(OPTION_MIPS_COUNTING) || (NPDup && NPcpugraph && prvtcount != sysblk.instcount) #endif /*defined(OPTION_MIPS_COUNTING)*/ ) { redraw_status = 1; memcpy (prvpsw, curpsw, sizeof(prvpsw)); prvicount = totalcount; prvcpupct = regs->cpupct; prvstate = regs->cpustate; #if defined(OPTION_SHARED_DEVICES) prvscount = sysblk.shrdcount; #endif // defined(OPTION_SHARED_DEVICES) #if defined(OPTION_MIPS_COUNTING) prvtcount = sysblk.instcount; #endif /*defined(OPTION_MIPS_COUNTING)*/ } /* =NP= : Display the screen - traditional or NP */ /* Note: this is the only code block modified rather */ /* than inserted. It makes the block of 3 ifs in the */ /* original code dependent on NPDup == 0, and inserts */ /* the NP display as an else after those ifs */ if (NPDup == 0) { /* Rewrite the screen if display update indicators are set */ if (redraw_msgs && !npquiet) { /* Display messages in scrolling area */ PANMSG* p; /* Save cursor location */ saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; #if defined(OPTION_MSGHLD) /* Unkeep kept messages if needed */ expire_kept_msgs(0); #endif // defined(OPTION_MSGHLD) i = 0; #if defined(OPTION_MSGHLD) /* Draw kept messages first */ for (p=keptmsgs; i < (SCROLL_LINES + numkept) && p; i++, p = p->next) { set_pos (i+1, 1); #if defined(OPTION_MSGCLR) set_color (p->fg, p->bg); #else // !defined(OPTION_MSGCLR) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); #endif // defined(OPTION_MSGCLR) write_text (p->msg, MSG_SIZE); } #endif // defined(OPTION_MSGHLD) /* Then draw current screen */ for (p=topmsg; i < (SCROLL_LINES + numkept) && (p != curmsg->next || p == topmsg); i++, p = p->next) { set_pos (i+1, 1); #if defined(OPTION_MSGCLR) set_color (p->fg, p->bg); #else // !defined(OPTION_MSGCLR) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); #endif // defined(OPTION_MSGCLR) write_text (p->msg, MSG_SIZE); } /* Pad remainder of screen with blank lines */ for (; i < (SCROLL_LINES + numkept); i++) { set_pos (i+1, 1); set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); erase_to_eol( confp ); } /* Display the scroll indicators */ if (topmsg != oldest_msg()) { /* More messages precede top line */ set_pos (1, cons_cols); set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG); draw_text ("+"); } if (!is_currline_visible()) { /* More messages follow bottom line */ set_pos (cons_rows-2, cons_cols); set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG); draw_text ("V"); } /* restore cursor location */ cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } /* end if(redraw_msgs) */ if (redraw_cmd) { /* Save cursor location */ saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; /* Display the command line */ set_pos (CMDLINE_ROW, 1); set_color (COLOR_DEFAULT_LIGHT, COLOR_DEFAULT_BG); #if defined( OPTION_CMDTGT ) switch (sysblk.cmdtgt) { case CMDTGT_HERC: draw_text( CMD_PREFIX_HERC ); break; case CMDTGT_SCP: draw_text( CMD_PREFIX_SCP ); break; case CMDTGT_PSCP: draw_text( CMD_PREFIX_PSCP ); break; } #else // !defined( OPTION_CMDTGT ) draw_text( CMD_PREFIX_HERC ); #endif // defined( OPTION_CMDTGT ) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); PUTC_CMDLINE (); fill_text (' ',cons_cols); /* restore cursor location */ cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } /* end if(redraw_cmd) */ /* Determine if redraw required for CPU or architecture * change. */ if ((sysblk.pcpu != prvpcpu && (regs = sysblk.regs[sysblk.pcpu]) != NULL) || ((regs = sysblk.regs[prvpcpu]) != NULL && regs->arch_mode != prvparch)) { redraw_status = 1; prvpcpu = sysblk.pcpu; prvparch = regs->arch_mode; } if (redraw_status && !npquiet) { char ibuf[64]; /* Rate buffer */ { int cnt_disabled = 0; int cnt_stopped = 0; int cnt_online = 0; char *state; for ( i = 0; i < sysblk.maxcpu; i++ ) { if ( IS_CPU_ONLINE(i) ) { cnt_online++; if ( sysblk.regs[i]->cpustate != CPUSTATE_STARTED ) cnt_stopped++; if ( WAITSTATE(&sysblk.regs[i]->psw) && IS_IC_DISABLED_WAIT_PSW( sysblk.regs[i] ) ) cnt_disabled++; } } state = "RED"; if ( cnt_online > cnt_stopped && cnt_disabled == 0 ) state = "AMBER"; if (0 || ( sysblk.hicpu && (cnt_stopped == 0 && cnt_disabled == 0)) #if defined(OPTION_SHARED_DEVICES) || (!sysblk.hicpu && (sysblk.shrdport)) #endif // defined(OPTION_SHARED_DEVICES) ) state = "GREEN"; set_console_title(state); } /* Save cursor location */ saved_cons_row = cur_cons_row; saved_cons_col = cur_cons_col; memset (buf, ' ', cons_cols); len = sprintf ( buf, "%s%02X ", PTYPSTR(sysblk.pcpu), sysblk.pcpu ) ; if (IS_CPU_ONLINE(sysblk.pcpu)) { len += sprintf(buf+len, "PSW=%8.8X%8.8X ", fetch_fw(curpsw), fetch_fw(curpsw+4)); if (regs->arch_mode == ARCH_900) len += sprintf (buf+len, "%16.16"I64_FMT"X ", fetch_dw (curpsw+8)); #if defined(_FEATURE_SIE) else if( SIE_MODE(regs) ) { for(i = 0;i < 16;i++) buf[len++] = '-'; buf[len++] = ' '; } #endif /*defined(_FEATURE_SIE)*/ len += sprintf (buf+len, "%2d%c%c%c%c%c%c%c%c", regs->psw.amode64 ? 64 : regs->psw.amode ? 31 : 24, regs->cpustate == CPUSTATE_STOPPED ? 'M' : '.', sysblk.inststep ? 'T' : '.', WAITSTATE(®s->psw) ? 'W' : '.', regs->loadstate ? 'L' : '.', regs->checkstop ? 'C' : '.', PROBSTATE(®s->psw) ? 'P' : '.', SIE_MODE(regs) ? 'S' : '.', regs->arch_mode == ARCH_900 ? 'Z' : '.'); } else len += sprintf (buf+len,"%s", "Offline"); buf[len++] = ' '; #if defined(OPTION_MIPS_COUNTING) /* Bottom line right corner can be when there is space: * "" * "instcnt " * "instcnt ; mips nnnnn" * nnnnn can be nnnnn, nnn.n, nn.nn or n.nnn * "instcnt ; mips nnnnn; IO/s nnnnnn" * "IO/s nnnnnn" */ i = 0; if (numcpu) { U32 mipsrate = sysblk.mipsrate / 1000000; /* Format instruction count */ i = snprintf(ibuf, sizeof(ibuf), "instcnt %s", format_int(totalcount)); if ((len + i + 12) < cons_cols) { if (mipsrate > 999) i += snprintf(ibuf + i, sizeof(ibuf) - i, "; mips %1d,%03d", sysblk.mipsrate / 1000000000, ((sysblk.mipsrate % 1000000000) + 500000) / 1000000); else { U32 mipsfrac = sysblk.mipsrate % 1000000; if (mipsrate > 99) i += snprintf(ibuf + i, sizeof(ibuf) - i, "; mips %3d.%01d", mipsrate, (mipsfrac + 50000) / 100000); else if (mipsrate > 9) i += snprintf(ibuf + i, sizeof(ibuf) - i, "; mips %2d.%02d", mipsrate, (mipsfrac + 5000) / 10000); else i += snprintf(ibuf + i, sizeof(ibuf) - i, "; mips %1d.%03d", mipsrate, (mipsfrac + 500) / 1000); } } } /* Prepare I/O statistics */ if (1 && (len + i + (numcpu ? 13 : 11)) < cons_cols && (0 || numcpu #if defined(OPTION_SHARED_DEVICES) || (!numcpu && sysblk.shrdport) #endif // defined(OPTION_SHARED_DEVICES) ) ) { if (numcpu) ibuf[(int)i++] = ';', ibuf[(int)i++] = ' '; i += snprintf(ibuf + i, sizeof(ibuf) - i, "I/O %6.6s", format_int(sysblk.siosrate)); } /* Copy prepared statistics to buffer */ if (i) { if ((len + i) < cons_cols) len = cons_cols - i; strcpy (buf + len, ibuf); len = cons_cols - 1; } #endif /* OPTION_MIPS_COUNTING */ buf[cons_cols] = '\0'; set_pos (cons_rows, 1); set_color (COLOR_LIGHT_YELLOW, COLOR_RED); draw_text (buf); /* restore cursor location */ cur_cons_row = saved_cons_row; cur_cons_col = saved_cons_col; } /* end if(redraw_status) */ /* Flush screen buffer and reset display update indicators */ if (redraw_msgs || redraw_cmd || redraw_status) { set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); if (NPDup == 0 && NPDinit == 1) { NPDinit = 0; restore_command_line(); set_pos (cur_cons_row, cur_cons_col); } else if (redraw_cmd) set_pos (CMDLINE_ROW, CMDLINE_COL + cmdoff - cmdcol); else set_pos (cur_cons_row, cur_cons_col); fflush (confp); redraw_msgs = redraw_cmd = redraw_status = 0; } } else { /* (NPDup == 1) */ if (redraw_status || (NPDinit == 0 && NPDup == 1) || (redraw_cmd && NPdataentry == 1)) { if (NPDinit == 0) { NPDinit = 1; NP_screen_redraw(regs); NP_update(regs); fflush (confp); } } /* Update New Panel every panrate interval */ if (!npquiet) { NP_update(regs); fflush (confp); } redraw_msgs = redraw_cmd = redraw_status = 0; } /* =END= */ /* Force full screen repaint if needed */ if (!sysblk.npquiet && npquiet) redraw_msgs = redraw_cmd = redraw_status = 1; npquiet = sysblk.npquiet; } /* end while */ sysblk.panel_init = 0; WRMSG (HHC00101, "I", thread_id(), get_thread_priority(0), "Control panel"); ASSERT( sysblk.shutdown ); // (why else would we be here?!) } /* end function panel_display */ static void panel_cleanup(void *unused) { int i; PANMSG* p; UNREFERENCED(unused); log_wakeup(NULL); if(topmsg) { set_screen_color( stderr, COLOR_DEFAULT_FG, COLOR_DEFAULT_BG ); clear_screen( stderr ); /* Scroll to last full screen's worth of messages */ scroll_to_bottom_screen( 1 ); /* Display messages in scrolling area */ for (i=0, p = topmsg; i < SCROLL_LINES && p != curmsg->next; i++, p = p->next) { set_pos (i+1, 1); #if defined(OPTION_MSGCLR) set_color (p->fg, p->bg); #else // !defined(OPTION_MSGCLR) set_color (COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); #endif // defined(OPTION_MSGCLR) write_text (p->msg, MSG_SIZE); } } sysblk.panel_init = 0; /* Panel is no longer running */ /* Restore the terminal mode */ set_or_reset_console_mode( keybfd, 0 ); /* Position to next line */ fwrite("\n",1,1,stderr); #ifdef OPTION_MIPS_COUNTING { char* pszCurrIntervalStartDateTime; char* pszCurrentDateTime; char buf[128]; time_t current_time; current_time = time( NULL ); pszCurrIntervalStartDateTime = strdup( ctime( &curr_int_start_time ) ); pszCurrIntervalStartDateTime[strlen(pszCurrIntervalStartDateTime) - 1] = 0; pszCurrentDateTime = strdup( ctime( ¤t_time ) ); pszCurrentDateTime[strlen(pszCurrentDateTime) - 1] = 0; WRMSG(HHC02272, "I", "Highest observed MIPS and IO/s rates"); MSGBUF( buf, " from %s", pszCurrIntervalStartDateTime); WRMSG(HHC02272, "I", buf); MSGBUF( buf, " to %s", pszCurrentDateTime); WRMSG(HHC02272, "I", buf); MSGBUF( buf, " MIPS: %d.%02d IO/s: %d", curr_high_mips_rate / 1000000, curr_high_mips_rate % 1000000, curr_high_sios_rate ); WRMSG(HHC02272, "I", buf); free( pszCurrIntervalStartDateTime ); free( pszCurrentDateTime ); } #endif /* Read and display any msgs still remaining in the system log */ while((lmscnt = log_read(&lmsbuf, &lmsnum, LOG_NOBLOCK))) fwrite(lmsbuf,lmscnt,1,stderr); set_screen_color(stderr, COLOR_DEFAULT_FG, COLOR_DEFAULT_BG); fflush(stderr); }