/* top.c - Source file: show Linux processes */
/*
- * Copyright (c) 2002 - James C. Warner, <warnerjc@worldnet.att.net>
- * All rights reserved.
+ * Copyright (c) June, 2002 - James C. Warner
+ * All rights reserved. 8921 Hilloway Road
+ * Eden Prairie, Minnesota 55347 USA
+ * <warnerjc@worldnet.att.net>
+ *
* This file may be used subject to the terms and conditions of the
* GNU Library General Public License Version 2, or any later version
* at your option, as published by the Free Software Foundation.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*/
-#include <asm/param.h>
+/* For their contributions to this program, the author wishes to thank:
+ * Craig Small, <csmall@eye-net.com.au>
+ * Albert D. Cahalan, <acahalan@cs.uml.edu>
+ */
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/time.h>
/* need: signal_name_to_number */
#include "proc/sig.h"
#endif
+#ifdef USE_LIB_STA3
/* need: status */
#include "proc/status.h"
+#endif
/* need: meminfo stuff */
#include "proc/sysinfo.h"
/* need: procps_version */
#include "top.h"
-
/*###### Miscellaneous global stuff ####################################*/
/* The original and new terminal attributes */
Rawtty;
static int Ttychanged = 0;
- /* Program names used in error messages and 'rc' file names */
-static char *Myname,
- *Myrealname;
+ /* Program name used in error messages and 'rc' file names */
+static char *Myname;
/* The Name of the config file(s), dynamically constructed */
static char RCfile [OURPATHSZ],
/* The run-time acquired page size */
static int Page_size;
+#ifdef UGH_ITS_4_RH
+static unsigned Mem_pages;
+#endif
/* SMP and Irix/Solaris mode support */
static int Cpu_tot,
/* Configurable Display support ##################################*/
-static unsigned PFlags [PFLAGSSIZ];
-static char CurFields [PFLAGSSIZ],
- ColHeadings [SMLBUFSIZ],
- ColUsername [USRNAMSIZ];
-static int NumFields;
-
- /* Current window size.
- note: Max_tasks is the specified number of processes to display
- (zero for infinite), and Max_lines is the actual number
- which, in turn, depends on screen size and summary info. */
-static int Screen_cols, Screen_rows,
- Max_lines, Max_tasks;
-
- /* Number of lines needed to display the summary information
- which is never less than 2 since it also must accomodate the
- message line + column headings -- set soley by mkheadings! */
-static int HSum_lines;
-
- /* Maximum length to display of a process' command name/line
- (excluding padding due to terminfo strings) */
-static int Max_cmd;
-
- /* Controls how long we sleep between screen updates.
- Accurate to microseconds (when not in 'Batch' mode). */
-static float Delay_time = DEF_DELAY;
-
- /* Special flags dealing with the kernel symbol table */
-static int No_ksyms = -1, /* set to '0' if ksym avail, '1' otherwise */
- PSDBopen = 0; /* set to '1' if psdb opened (now postponed) */
+ /* Current screen dimensions.
+ note: the number of processes displayed is tracked on a per window
+ basis (see the WIN_t). Max_lines is the total number of
+ screen rows after deducting summary information overhead. */
+ /* Current terminal screen size. */
+static int Screen_cols, Screen_rows, Max_lines;
+
+ /* This is really the number of lines needed to display the summary
+ information (0 - nn), but is used as the relative row where we
+ stick the cursor between frames. */
+static int Msg_row;
+
+ /* Global/Non-windows mode stuff that IS persistent (in rcfile) */
+static int Show_altscr; /* 'A' - 'Alt' display mode (multi windows) */
+static int Show_irixps = 1; /* 'I' - Irix vs. Solaris mode (SMP-only) */
+static float Delay_time = DEF_DELAY; /* how long to sleep between updates */
- /* The Mode flags.
- Except for Batch and Loops, all of them are preserved in the
- rc file. Thus, once personalized it stays personalized!
- note: the 'letter' shown is the On condition, some default to Off */
-static int Batch = 0, /* batch mode, collect no input, dumb output */
+ /* Global/Non-windows mode stuff that is NOT persistent */
+static int No_ksyms = -1, /* set to '0' if ksym avail, '1' otherwise */
+ PSDBopen = 0, /* set to '1' if psdb opened (now postponed) */
+ Batch = 0, /* batch mode, collect no input, dumb output */
Loops = -1, /* number of iterations, -1 loops forever */
- Secure_mode = 0, /* set if some functionality restricted */
- Irix_mode = 1, /* 'I' - Irix vs. Solaris view (SMP-only) */
- Sort_normal = 1, /* 'R' - reversed column sort order */
- HSum_loadav = 1, /* 'l' - display load avg and uptime summary */
- HSum_states = 1, /* 't' - display task/cpu(s) states summary */
- HSum_memory = 1, /* 'm' - display memory summary */
- Show_ctimes = 1, /* 'S' - show times as cumulative */
- Show_cmdlin = 0, /* 'c' - show cmdline vs. name */
- Show_idleps = 1, /* 'i' - show idle processes (all processes) */
- Show_hicols = 0, /* 'x' - show sort column highlighted */
- Show_hirows = 1, /* 'y' - show running task(s) highlighted */
- Show_colors = 0, /* 'z' - show in color (vs. mono) */
- Show_hibold = 1, /* 'b' - rows and/or col bold (vs. reverse) */
- Show_cpusum = 1; /* '1' - show combined cpu stats (vs. each) */
-
- /* Current current sort type (this too is preserved in the rc file)
- * and handler -- goodbye libproc mult_lvl_cmp, etc. overkill. */
-static int Sort_type = -1;
-static QSORT_t Sort_func = NULL;
+ Secure_mode = 0; /* set if some functionality restricted */
+
/* These are our gosh darn 'Fields' !
They MUST be kept in sync with pflags !! */
{ " SHR ", "%4.4s ", 4, SK_Kb, -1, "Shared Mem size (kb)" },
{ "nFLT ", "%4.4s ", 4, SK_no, -1, "Page Fault count" },
{ "nDRT ", "%4.4s ", 4, SK_no, -1, "Dirty Pages count" },
+#ifdef USE_LIB_STA3
{ "STA ", "%3.3s ", -1, -1, -1, "Process Status" },
+#else
+ { "S ", "%c ", -1, -1, -1, "Process Status" },
+#endif
/** next entry's special: '.head' will be formatted using table entry's own
'.fmts' plus runtime supplied conversion args! */
{ "Command ", "%-*.*s ", -1, -1, S_CMD, "Command line/name" },
{ "WCHAN ", "%-9.9s ", -1, -1, -1, "Sleeping in Function" },
/** next entry's special: the 0's will be replaced with '.'! */
-#ifdef UPCASE_HEXES
+#ifdef CASEUP_HEXES
{ "Flags ", "%08lX ", -1, -1, -1, "Task Flags <sched.h>" }
#else
{ "Flags ", "%08lx ", -1, -1, -1, "Task Flags <sched.h>" }
/* Miscellaneous Color stuff #####################################*/
- /* Our three basic colors --
- they can be manipulated by the 'tweak_colors' routine */
-static int Base_color = BASEcolor,
- Msgs_color = MSGScolor,
- Head_color = HEADcolor;
-
/* Some cap's stuff to reduce runtime calls --
to accomodate 'Batch' mode, they begin life as empty strings */
static char Cap_bold [CAPBUFSIZ] = "",
Cap_norm [CAPBUFSIZ] = "",
Cap_reverse [CAPBUFSIZ] = "",
Caps_off [CAPBUFSIZ] = "";
-static char Sum_color [CLRBUFSIZ] = "",
- Msg_color [CLRBUFSIZ] = "",
- Pmt_color [CLRBUFSIZ] = "",
- Hdr_color [CLRBUFSIZ] = "",
- Row_color_norm [CLRBUFSIZ] = "",
- Row_color_high [CLRBUFSIZ] = "";
-static int Cap_can_goto = 0,
- Len_row_high = 0,
- Len_row_norm = 0;
-
- /* Development/debug stuff #######################################*/
-
-#ifdef TRAK_MAXCAPS
-static int Max_pads = 0, Min_pads = MAXINT,
- Max_rbuf = 0, Min_rbuf = MAXINT;
-#endif
+static int Cap_can_goto = 0;
-#ifdef TRAK_MAXBUFS
- BUF2INT(fmtmk, buf)
- BUF2INT(show_special, tmp)
- BUF2INT(ask_str, buf)
- BUF2INT(scale_num, buf)
- BUF2INT(scale_tics, buf)
- BUF2INT(std_err, buf)
- BUF2INT(frame_states, tmp)
- BUF2INT(mkcol, tmp)
- BUF2INT(show_a_task, cbuf)
- BUF2INT(show_a_task, rbuf)
- BUF2INT(rcfiles_read, fbuf)
- BUF2INT(rcfiles_read, RCfile)
- BUF2INT(rcfiles_read, RCfile_Sys)
- BUF2INT(do_key, ColUsername)
- BUF2INT(mkheadings, CurFields)
- BUF2INT(mkheadings, ColHeadings)
- BUF2INT(main, not_really_tmp)
-#endif
+
+ /* ////////////////////////////////////////////////////////////// */
+ /* Special Section: multiple windows/field groups ---------------*/
+
+ /* The pointers to our four WIN_t's, and which of those is considered
+ the 'current' window (ie. which window is associated with any summ
+ info displayed and to which window commands are directed) */
+static WIN_t *Winstk [GROUPSMAX],
+ *Curwin;
+
+ /* Frame oriented stuff that can't remain local to any 1 function
+ and/or that would be too cumbersome managed as parms */
+static int Frame_maxtask, /* last known number of active tasks */
+ /* ie. current 'size' of proc table */
+ Frame_srtflg, /* the subject window sort direction */
+ Frame_ctimes, /* the subject window's ctimes flag */
+ Frame_cmdlin; /* the subject window's cmdlin flag */
+ /* ////////////////////////////////////////////////////////////// */
\f
/*###### Sort callbacks ################################################*/
+ /*
+ * About the naming variance --
+ * pids are often treated as our secondary sort key,
+ * thus this guy must be alphabetically first in this section */
+static int pid_sort (proc_t **P, proc_t **Q)
+{
+ if ( (*P)->pid < (*Q)->pid ) return SORT_lt;
+ if ( (*P)->pid > (*Q)->pid ) return SORT_gt;
+ return 0;
+}
+
+
static int sort_cmd (proc_t **P, proc_t **Q)
{
/* if a process doesn't have a cmdline, we'll consider it a kernel thread
-- since show_a_task gives such tasks special treatment, we must too */
- if (Show_cmdlin && ((*P)->cmdline || (*Q)->cmdline)) {
+ if (Frame_cmdlin && ((*P)->cmdline || (*Q)->cmdline)) {
if (!(*P)->cmdline) return SORT_lt;
if (!(*Q)->cmdline) return SORT_gt;
- if ( 0 > strncmp((*P)->cmdline[0], (*Q)->cmdline[0], (unsigned)Max_cmd) )
+ if ( 0 > strncmp((*P)->cmdline[0], (*Q)->cmdline[0], (unsigned)Curwin->maxcmdln) )
return SORT_lt;
- if ( 0 < strncmp((*P)->cmdline[0], (*Q)->cmdline[0], (unsigned)Max_cmd) )
+ if ( 0 < strncmp((*P)->cmdline[0], (*Q)->cmdline[0], (unsigned)Curwin->maxcmdln) )
return SORT_gt;
} else {
/* this part also handles the compare if both are kernel threads */
{
if ( (*P)->pcpu < (*Q)->pcpu ) return SORT_lt;
if ( (*P)->pcpu > (*Q)->pcpu ) return SORT_gt;
+ /* still equal? we'll try to fix that... */
+ return pid_sort(P, Q);
return 0;
}
if ( (*P)->resident < (*Q)->resident ) return SORT_lt;
if ( (*P)->resident > (*Q)->resident ) return SORT_gt;
/* still equal? we'll try to fix that... */
- if ( (*P)->size < (*Q)->size ) return SORT_lt;
- if ( (*P)->size > (*Q)->size ) return SORT_gt;
- return 0;
-}
-
-
-static int sort_pid (proc_t **P, proc_t **Q)
-{
- if ( (*P)->pid < (*Q)->pid ) return SORT_lt;
- if ( (*P)->pid > (*Q)->pid ) return SORT_gt;
+ return pid_sort(P, Q);
return 0;
}
static int sort_tme (proc_t **P, proc_t **Q)
{
- if (Show_ctimes) {
+ if (Frame_ctimes) {
if ( ((*P)->cutime + (*P)->cstime + (*P)->utime + (*P)->stime)
< ((*Q)->cutime + (*Q)->cstime + (*Q)->utime + (*Q)->stime) )
return SORT_lt;
if ( (*P)->tty < (*Q)->tty ) return SORT_lt;
if ( (*P)->tty > (*Q)->tty ) return SORT_gt;
/* still equal? we'll try to fix that... */
- return sort_pid(P, Q);
+ return pid_sort(P, Q);
}
if ( 0 > strcmp((*P)->euser, (*Q)->euser) ) return SORT_lt;
if ( 0 < strcmp((*P)->euser, (*Q)->euser) ) return SORT_gt;
/* still equal? we'll try to fix that... */
- return sort_pid(P, Q);
+ return sort_tty(P, Q);
}
\f
va_start(va, fmts);
vsprintf(buf, fmts, va);
va_end(va);
-#ifdef TRAK_MAXBUFS
- MAXBUFS(fmtmk, buf);
-#endif
return (const char *)buf;
}
* This guy just facilitates Batch and protects against dumb ttys. */
static char *tg2 (int x, int y)
{
- return Cap_can_goto ? tgoto(cursor_address, x, y) : (char *)"\n";
+ return Cap_can_goto ? tgoto(cursor_address, x, y) : (char *)"";
+}
+
+\f
+/*###### Exit/Interrput routines #######################################*/
+
+ /*
+ * The usual program end --
+ * called only by functions in this section. */
+static void bye_bye (int eno, const char *str)
+{
+#ifdef UGH_ITS_4_RH
+ if (PSDBopen)
+ close_psdb();
+#endif
+ if (!Batch)
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
+ printf("%s%s\n", tg2(0, Screen_rows), Cap_curs_norm);
+
+#ifdef ATEOJ_REPORT
+ fprintf(stderr,
+ "\nbye_bye's Summary report:"
+ "\n\tProgram"
+ "\n\t Page_size = %d, Cpu_tot = %d"
+ "\n\tTerminal: %s"
+ "\n\t device = %s, ncurses = v%s"
+ "\n\t max_colors = %d, max_pairs = %d"
+ "\n\t Cap_can_goto = %s"
+ "\n\t Screen_cols = %d, Screen_rows = %d"
+ "\n\t Max_lines = %d"
+ "\n\tWindows and Curwin->"
+ "\n\t sizeof(WIN_t) = %u, GROUPSMAX = %d"
+ "\n\t winname = %s, grpname = %s,"
+#ifdef CASEUP_HEXES
+ "\n\t winflags = %08X, maxpflgs = %d"
+#else
+ "\n\t winflags = %08x, maxpflgs = %d"
+#endif
+ "\n\t fieldscur = %s"
+ "\n\t winlines = %d, maxtasks = %d, maxcmdln = %d"
+ "\n\t sorttype = %c"
+ "\n"
+ , Page_size, Cpu_tot
+#ifdef PRETENDNOCAP
+ , "dumb"
+#else
+ , termname()
+#endif
+ , ttyname(STDOUT_FILENO), NCURSES_VERSION
+ , max_colors, max_pairs
+ , Cap_can_goto ? "yes" : "No!"
+ , Screen_cols, Screen_rows
+ , Max_lines
+ , sizeof(WIN_t), GROUPSMAX
+ , Curwin->winname, Curwin->grpname
+ , Curwin->winflags, Curwin->maxpflgs
+ , Curwin->fieldscur
+ , Curwin->winlines, Curwin->maxtasks, Curwin->maxcmdln
+ , Curwin->sorttype
+ );
+#endif
+
+ if (str) {
+ if (eno) perror(str);
+ else {
+ fputs(str, stderr);
+ eno = 1;
+ }
+ }
+ exit(eno);
+}
+
+
+ /*
+ * Normal end of execution.
+ * catches:
+ * SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT and SIGTERM */
+static void stop (int dont_care_sig)
+{
+ bye_bye(0, NULL);
+}
+
+
+ /*
+ * Standard error handler to normalize the look of all err o/p */
+static void std_err (const char *str)
+{
+ static char buf[SMLBUFSIZ];
+
+ fflush(stdout);
+ /* we'll use our own buffer so callers can still use fmtmk() and, yes the
+ leading tab is not the standard convention, but the standard is wrong
+ -- OUR msg won't get lost in screen clutter, like so many others! */
+ sprintf(buf, "\t%s: %s\n", Myname, str);
+ if (!Ttychanged) {
+ fprintf(stderr, buf);
+ exit(1);
+ }
+ /* not to worry, he'll change our exit code to 1 due to 'buf' */
+ bye_bye(0, buf);
+}
+
+
+ /*
+ * Suspend ourself.
+ * catches:
+ * SIGTSTP, SIGTTIN and SIGTTOU */
+static void suspend (int dont_care_sig)
+{
+ /* reset terminal */
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
+ printf("%s%s", tg2(0, Screen_rows), Cap_curs_norm);
+ fflush(stdout);
+ raise(SIGSTOP);
+ /* later, after SIGCONT... */
+ if (!Batch)
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);
}
\f
* columns and an actual printf row!
* note: we avoid the use of background color so as to maximize
* compatibility with the user's xterm settings */
-static void capsmk (void)
+static void capsmk (WIN_t *q)
{
/* macro to test if a basic (non-color) capability is valid
thanks: Floyd Davidson <floyd@ptialaska.net> */
#define tIF(s) s ? s : ""
static int capsdone = 0;
- /* just a precaution for the future, we aren't called now... */
+ /* we must NOT disturb our 'empty' terminfo strings! */
if (Batch) return;
/* these are the unchangeable puppies, so we only do 'em once */
if (tgoto(cursor_address, 1, 1)) Cap_can_goto = 1;
capsdone = 1;
}
-
- /* now do the changeable guys... */
- if (Show_colors && max_colors > 0) {
- strcpy(Sum_color, tparm(set_a_foreground, Base_color));
- sprintf(Msg_color, "%s%s"
- , tparm(set_a_foreground, Msgs_color), Cap_reverse);
- sprintf(Pmt_color, "%s%s"
- , tparm(set_a_foreground, Msgs_color), Cap_bold);
- sprintf(Hdr_color, "%s%s"
- , tparm(set_a_foreground, Head_color), Cap_reverse);
- sprintf(Row_color_norm, "%s%s"
- , Caps_off, tparm(set_a_foreground, Base_color));
+ /* the key to NO run-time costs for configurable colors -- we spend a
+ little time with the user now setting up our terminfo strings, and
+ the job's done until he/she/it has a change-of-heart */
+ if (CHKw(q, Show_COLORS) && max_colors > 0) {
+ strcpy(q->capclr_sum, tparm(set_a_foreground, q->summclr));
+ sprintf(q->capclr_msg, "%s%s"
+ , tparm(set_a_foreground, q->msgsclr), Cap_reverse);
+ sprintf(q->capclr_pmt, "%s%s"
+ , tparm(set_a_foreground, q->msgsclr), Cap_bold);
+ sprintf(q->capclr_hdr, "%s%s"
+ , tparm(set_a_foreground, q->headclr), Cap_reverse);
+ sprintf(q->capclr_rownorm, "%s%s"
+ , Caps_off, tparm(set_a_foreground, q->taskclr));
} else {
- Sum_color[0] = '\0';
- strcpy(Msg_color, Cap_reverse);
- strcpy(Pmt_color, Cap_bold);
- strcpy(Hdr_color, Cap_reverse);
- strcpy(Row_color_norm, Cap_norm);
+ q->capclr_sum[0] = '\0';
+ strcpy(q->capclr_msg, Cap_reverse);
+ strcpy(q->capclr_pmt, Cap_bold);
+ strcpy(q->capclr_hdr, Cap_reverse);
+ strcpy(q->capclr_rownorm, Cap_norm);
}
-
- sprintf(Row_color_high, "%s%s"
- , Row_color_norm, Show_hibold ? Cap_bold : Cap_reverse);
- Len_row_norm = strlen(Row_color_norm);
- Len_row_high = strlen(Row_color_high);
+ /* this guy's a composite, so we do him outside the if */
+ sprintf(q->capclr_rowhigh, "%s%s"
+ , q->capclr_rownorm, CHKw(q, Show_HIBOLD) ? Cap_bold : Cap_reverse);
+ q->len_rownorm = strlen(q->capclr_rownorm);
+ q->len_rowhigh = strlen(q->capclr_rowhigh);
#undef tIF
}
* Show an error, but not right now.
* Due to the postponed opening of ksym, using open_psdb_message,
* if P_WCHAN had been selected and the program is restarted, the
- * message would otherwise be displayed prematurely */
+ * message would otherwise be displayed prematurely.
+ * (old top handles that situation with typical inelegance) */
static void msg_save (const char *fmts, ...)
{
char tmp[SMLBUFSIZ];
static void show_msg (const char *str)
{
printf("%s%s %s %s%s"
- , tg2(0, MSG_line)
- , Msg_color
+ , tg2(0, Msg_row)
+ , Curwin->capclr_msg
, str
, Caps_off
, Cap_clr_eol);
static void show_pmt (const char *str)
{
printf("%s%s%s: %s%s"
- , tg2(0, MSG_line)
- , Pmt_color
+ , tg2(0, Msg_row)
+ , Curwin->capclr_pmt
, str
, Cap_curs_huge
, Caps_off);
* Our special formatting consists of:
* "some text <_delimiter_> some more text <_delimiter_>...\n"
* Where <_delimiter_> is a single byte in the range of:
- * \01 through \07 (more properly \0001 - \0007)
+ * \01 through \10 (in decimalizee, 1 - 8)
* and is used to select an 'attribute' from a capabilities table
* which is then applied to the *preceding* substring.
- *
* Once recognized, the delimiter is replaced with a null character
* and viola, we've got a substring ready to output! Strings or
* substrings without delimiters will receive the Cap_norm attribute.
* Tabs must always be avoided or our efforts are wasted and
* lines will wrap. To lessen but not eliminate the risk of
* terminfo string truncation, such non-display stuff should
- * be placed at the beginning of a "short" line. */
+ * be placed at the beginning of a "short" line.
+ * (and as for tabs, gimme 1 more color then no worries, mate) */
static void show_special (const char *glob)
-{
- static char *captab[] = { /* Cap's/Delim's */
- Cap_norm, Cap_norm, Cap_bold, /* \00, \01, \02 */
- Sum_color, /* \03 */
- Msg_color, Pmt_color, /* \04, \05 */
- Hdr_color, /* \06 */
- Row_color_high }; /* \07 */
+{ /* note: the following is for documentation only,
+ the real captab is now found in a group's WIN_t !
+ +------------------------------------------------------+
+ | char *captab[] = { : Cap's/Delim's |
+ | Cap_norm, Cap_norm, Cap_bold, = \00, \01, \02 |
+ | Sum_color, = \03 |
+ | Msg_color, Pmt_color, = \04, \05 |
+ | Hdr_color, = \06 |
+ | Row_color_high, = \07 |
+ | Row_color_norm }; = \10 [octal!] |
+ +------------------------------------------------------+ */
char tmp[BIGBUFSIZ], *cap, *lin_end, *sub_beg, *sub_end;
int room;
/* create a local copy we can extend and otherwise abuse */
memcpy(tmp, glob, (unsigned)(lin_end - glob));
-#ifdef TRAK_MAXBUFS
- MAXBUFS(show_special, tmp);
-#endif
/* zero terminate this part and prepare to parse substrings */
tmp[lin_end - glob] = '\0';
room = Screen_cols;
while (*sub_beg) {
switch (*sub_end) {
- case '\00' : /* no end delim, captab makes normal */
+ case 0: /* no end delim, captab makes normal */
*(sub_end + 1) = '\0'; /* extend str end, then fall through */
- case '\01' ... '\07' :
- cap = captab[(int)*sub_end];
+ case 1: case 2: case 3: case 4:
+ case 5: case 6: case 7: case 8:
+ cap = Curwin->captab[(int)*sub_end];
*sub_end = '\0';
printf("%s%.*s%s", cap, room, sub_beg, Caps_off);
room -= (sub_end - sub_beg);
sub_beg = ++sub_end;
break;
- default : /* nothin' special, just text */
+ default: /* nothin' special, just text */
++sub_end;
}
printf("%s\n", Cap_clr_eol); /* emulate truncated newline */
glob = ++lin_end; /* point to next line (maybe) */
-
} /* end: while 'lines' */
/* if there's anything left in the glob (by virtue of no trailing '\n'),
fflush(stdout);
}
-
- /*
- * Change colors used in display */
-static void tweak_colors (void)
-{
-#define kbdABORT 'q'
-#define kbdAPPLY '\n'
- int clrssav = Show_colors, boldsav = Show_hibold,
- basesav = Base_color, msgssav = Msgs_color, headsav = Head_color;
- int clr = Base_color, *pclr = &Base_color;
- char ch, tgt = 'B';
-
- if (0 >= max_colors) {
- show_msg("\aNo colors to map!");
- return;
- }
- if (!Show_colors) {
- Show_colors = 1;
- capsmk();
- }
- printf("%s%s", Cap_clr_scr, Cap_curs_huge);
-
- do {
- /* this string is well above ISO C89's minimum requirements! */
- show_special(fmtmk(COLOR_sample
- , Cap_home, Myname, procps_version, tgt, clr));
- chin(0, &ch, 1);
- switch (ch) {
- case 'B' :
- pclr = &Base_color;
- clr = *pclr;
- tgt = ch;
- break;
- case 'M' :
- pclr = &Msgs_color;
- clr = *pclr;
- tgt = ch;
- break;
- case 'H' :
- pclr = &Head_color;
- clr = *pclr;
- tgt = ch;
- break;
- case '0' ... '7' :
- clr = ch - '0';
- break;
- case 'b' :
- Show_hibold = !Show_hibold;
- break;
- case 'z' :
- Show_colors = !Show_colors;
- break;
- }
- *pclr = clr;
- capsmk();
- } while (kbdAPPLY != ch && kbdABORT != ch);
-
- if (kbdABORT == ch) {
- Show_colors = clrssav; Show_hibold = boldsav;
- Base_color = basesav; Msgs_color = msgssav; Head_color = headsav;
- capsmk();
- }
- putp(Cap_curs_norm);
-
-#undef kbdABORT
-#undef kbdAPPLY
-}
-
\f
-/*###### Small utility routines ########################################*/
+/*###### Small Utility routines ########################################*/
/*
* Get a string from the user */
-static char *ask_str (const char *prompt)
+static char *ask4str (const char *prompt)
{
static char buf[GETBUFSIZ];
chin(1, buf, sizeof(buf) - 1);
putp(Cap_curs_norm);
-#ifdef TRAK_MAXBUFS
- MAXBUFS(ask_str, buf);
-#endif
return strim(0, buf);
}
char *line;
float f;
- if (!(*(line = ask_str(prompt)))) return -1;
+ if (!(*(line = ask4str(prompt)))) return -1;
/* note: we're not allowing negative floats */
- if (strcspn(line, ".1234567890")) {
+ if (strcspn(line, ",.1234567890")) {
show_msg("\aNot valid");
return -1;
}
char *line;
int n;
- if (!(*(line = ask_str(prompt)))) return -1;
+ if (!(*(line = ask4str(prompt)))) return -1;
/* note: we've got to allow negative ints (renice) */
if (strcspn(line, "-1234567890")) {
show_msg("\aNot valid");
}
- /*
- * Set the number of fields/columns to display.
- * Create the field/column headings and set maximum cmdline length.
- * Establish the heading/summary lines currently in use.
- * Adjust the number of tasks to display. */
-static void mkheadings (void)
-{
- const char *h;
- int i, needpsdb = 0;
-
- /* build our PFlags array and establish a tentative NumFields */
- for (i = 0, NumFields = 0; i < (int)strlen(CurFields); i++) {
- if (isupper(CurFields[i]))
- PFlags[NumFields++] = CurFields[i] - 'A';
- }
-
- /* build a preliminary ColHeadings not to exceed screen width */
- ColHeadings[0] = '\0';
- for (i = 0; i < NumFields; i++) {
- h = Fieldstab[PFlags[i]].head;
- /* oops, won't fit -- we're outta here... */
- if (Screen_cols < (int)(strlen(ColHeadings) + strlen(h))) break;
- strcat(ColHeadings, h);
- }
-
- /* establish the final NumFields and prepare to grow the command
- column heading via Max_cmd -- it may be a fib if P_CMD wasn't
- encountered, but that's ok because it won't be displayed anyway */
- NumFields = i;
- Max_cmd = Screen_cols
- - (strlen(ColHeadings) - strlen(Fieldstab[P_CMD].head)) - 1;
-
- /* now we can build the true run-time ColHeadings and format the
- command column heading if P_CMD is really being displayed */
- ColHeadings[0] = '\0';
- for (i = 0; i < NumFields; i++) {
- /* are we gonna' need the kernel symbol table? */
- if (P_WCHAN == PFlags[i]) needpsdb = 1;
- h = Fieldstab[PFlags[i]].head;
- if (P_CMD == PFlags[i])
- strcat(ColHeadings, fmtmk(Fieldstab[P_CMD].fmts, Max_cmd, Max_cmd, h));
- else
- strcat(ColHeadings, h);
- }
-
- /* set the number of heading lines and calc display height */
- HSum_lines = SUMMINLINS;
- if (HSum_loadav) HSum_lines += 1;
- if (HSum_states) {
- if (Show_cpusum) HSum_lines += 2;
- /* no tellin' how darn many cpus they might have -- if they exceed
- screen height, they'll have to suffer scroll...
- (Max_lines may go negative, which is as good as 0) */
- else HSum_lines += Cpu_tot + 1;
- }
- if (HSum_memory) HSum_lines += 2;
-
- Max_lines = Screen_rows - HSum_lines;
- if (Max_tasks && Max_tasks < Max_lines)
- Max_lines = Max_tasks;
-
- /* do we (still) need the kernel symbol table? */
- if (needpsdb) {
- if (-1 == No_ksyms) {
- No_ksyms = 0;
- if (open_psdb_message(NULL, msg_save))
- /* why so counter-intuitive, couldn't open_psdb_message
- mirror sysmap_mmap -- that func does all the work anyway? */
- No_ksyms = 1;
- else
- PSDBopen = 1;
- }
- }
-#ifdef UGH_ITS_4_RH
- else if (PSDBopen) {
- close_psdb();
- PSDBopen = 0;
- No_ksyms = -1;
- }
-#endif
-
-#ifdef TRAK_MAXBUFS
- MAXBUFS(mkheadings, CurFields);
- MAXBUFS(mkheadings, ColHeadings);
-#endif
-}
-
-
/*
* Do some scaling stuff.
* We'll interpret 'num' as one of the following types and
/* kilobytes, megabytes, gigabytes, too-big-for-int-bytes */
static double scale[] = { 1024, 1024*1024, 1024*1024*1024, 0 };
/* kilo, mega, giga, none */
-#ifdef UPCASE_SCALE
+#ifdef CASEUP_SCALE
static char nextup[] = { 'K', 'M', 'G', 0 };
#else
static char nextup[] = { 'k', 'm', 'g', 0 };
/* try an unscaled version first... */
sprintf(buf, "%d", num);
-#ifdef TRAK_MAXBUFS
- MAXBUFS(scale_num, buf);
-#endif
if (strlen(buf) <= width)
return buf;
const char *fmt;
} ttab[] = {
/* minutes hours days weeks */
-#ifdef UPCASE_SCALE
+#ifdef CASEUP_SCALE
{ 60, "%uM" }, { 60, "%uH" }, { 24, "%uD" }, { 7, "%uW" }
#else
{ 60, "%um" }, { 60, "%uh" }, { 24, "%ud" }, { 7, "%uw" }
t = tics / Hertz;
sprintf(buf, "%d:%02d.%02d" /* minutes:seconds.tenths */
, t/60, t%60, (int)((tics*100)/Hertz)%100);
-#ifdef TRAK_MAXBUFS
- MAXBUFS(scale_tics, buf);
-#endif
-
if (strlen(buf) <= width)
return buf;
+
sprintf(buf, "%d:%02d", t/60, t%60); /* minutes:seconds */
if (strlen(buf) <= width)
return buf;
}
\f
-/*###### Exit and Signal handled routines ##############################*/
+/*###### Library Alternatives ##########################################*/
/*
- * The usual program end --
- * called only by functions in this section. */
-static void bye_bye (int eno, const char *str)
-{
-#ifdef UGH_ITS_4_RH
- if (PSDBopen)
- close_psdb();
-#endif
- if (!Batch)
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
- printf("%s%s\n", tg2(0, Screen_rows), Cap_curs_norm);
-
- if (str) {
- if (eno) perror(str);
- else fputs(str, stderr);
- }
-#ifdef TRAK_MAXCAPS
- fprintf(stderr,
- "\nTRAK_MAXCAPS report:"
- "\n\tBasic lengths:"
- "\n\t Cap_home = %d, Cap_bold = %d, Cap_norm = %d, Cap_reverse = %d"
- "\n\t Cap_clr_eol = %d, Cap_clr_eos = %d, Cap_clr_scr = %d"
- "\n\t Cap_curs_norm = %d, Cap_curs_huge = %d"
- "\n\t Caps_off = %d"
- "\n\tColor lengths:"
- "\n\t Sum_color = %d, Msg_color = %d, Pmt_color = %d, Hdr_color = %d"
- "\n\t Row_color_norm = %d, Len_row_norm = '%d'"
- "\n\t Row_color_high = %d, Len_row_high = '%d'"
- "\n\tMax_pads = %d, Min_pads = %d"
- "\n\tMax_rbuf = %d, Min_rbuf = %d"
- "\n"
- , strlen(Cap_home), strlen(Cap_bold), strlen(Cap_norm), strlen(Cap_reverse)
- , strlen(Cap_clr_eol), strlen(Cap_clr_eos), strlen(Cap_clr_scr)
- , strlen(Cap_curs_norm), strlen(Cap_curs_huge)
- , strlen(Caps_off)
- , strlen(Sum_color), strlen(Msg_color), strlen(Pmt_color), strlen(Hdr_color)
- , strlen(Row_color_norm), Len_row_norm
- , strlen(Row_color_high), Len_row_high
- , Max_pads, Min_pads
- , Max_rbuf, Min_rbuf);
-#endif
-#ifdef TRAK_MAXBUFS
- fprintf(stderr,
- "\nTRAK_MAXBUFS report:"
- "\n\tused size\tfunction, buffer"
- "\n\t---- ----\t-----------------------"
- ARPTBUF(fmtmk, buf)
- ARPTBUF(show_special, tmp)
- ARPTBUF(ask_str, buf)
- ARPTBUF(scale_num, buf)
- ARPTBUF(scale_tics, buf)
- ARPTBUF(std_err, buf)
- ARPTBUF(frame_states, tmp)
- ARPTBUF(mkcol, tmp)
- ARPTBUF(show_a_task, cbuf)
- ARPTBUF(show_a_task, rbuf)
- ARPTBUF(rcfiles_read, fbuf)
- ARPTBUF(rcfiles_read, RCfile)
- ARPTBUF(rcfiles_read, RCfile_Sys)
- ARPTBUF(do_key, ColUsername)
- ARPTBUF(mkheadings, CurFields)
- ARPTBUF(mkheadings, ColHeadings)
- ARPTBUF(main, not_really_tmp)
- "\n"
- , AUSEBUF(fmtmk, buf), ASIZBUF(fmtmk, buf)
- , AUSEBUF(show_special, tmp), ASIZBUF(show_special, tmp)
- , AUSEBUF(ask_str, buf), ASIZBUF(ask_str, buf)
- , AUSEBUF(scale_num, buf), ASIZBUF(scale_num, buf)
- , AUSEBUF(scale_tics, buf), ASIZBUF(scale_tics, buf)
- , AUSEBUF(std_err, buf), ASIZBUF(std_err, buf)
- , AUSEBUF(frame_states, tmp), ASIZBUF(frame_states, tmp)
- , AUSEBUF(mkcol, tmp), ASIZBUF(mkcol, tmp)
- , AUSEBUF(show_a_task, cbuf), ASIZBUF(show_a_task, cbuf)
- , AUSEBUF(show_a_task, rbuf), ASIZBUF(show_a_task, rbuf)
- , AUSEBUF(rcfiles_read, fbuf), ASIZBUF(rcfiles_read, fbuf)
- , AUSEBUF(rcfiles_read, RCfile) , ASIZBUF(rcfiles_read, RCfile)
- , AUSEBUF(rcfiles_read, RCfile_Sys) , ASIZBUF(rcfiles_read, RCfile_Sys)
- , AUSEBUF(do_key, ColUsername), ASIZBUF(do_key, ColUsername)
- , AUSEBUF(mkheadings, CurFields), ASIZBUF(mkheadings, CurFields)
- , AUSEBUF(mkheadings, ColHeadings), ASIZBUF(mkheadings, ColHeadings)
- , AUSEBUF(main, not_really_tmp), ASIZBUF(main, not_really_tmp));
-#endif
+ * Handle our own memory stuff without the risk of leaving the
+ * user's terminal in an ugly state should things go sour. */
+static const char *alloc_msg = "Failed memory allocate (%d bytes)";
-#if defined(TRAK_MAXCAPS) || defined(TRAK_MAXBUFS)
- fprintf(stderr,
- "\nbye_bye's Summary report:"
- "\n\tprogram names:"
- "\n\t Myrealname = %s, Myname = %s"
- "\n\tterminal = '%s'"
- "\n\t device = %s, ncurses = v%s"
- "\n\t max_colors = %d, max_pairs = %d"
- "\n\t Cap_can_goto = %s"
- "\n\tScreen_cols = %d, Screen_rows = %d"
- "\n\tNumFields = %d, HSum_lines = %d"
- "\n\tMax_lines = %d, Max_cmd = %d, Max_tasks = %d"
- "\n\tPage_size = %d"
- "\n"
- , Myrealname, Myname
-#ifdef PRETENDNOCAP
- , "dumb"
-#else
- , termname()
-#endif
- , ttyname(STDOUT_FILENO), NCURSES_VERSION
- , max_colors, max_pairs
- , Cap_can_goto ? "yes" : "No!"
- , Screen_cols, Screen_rows
- , NumFields, HSum_lines
- , Max_lines, Max_cmd, Max_tasks
- , Page_size);
-#endif
+static void *alloc_c (unsigned numb)
+{
+ void * p;
- if (str && !eno) eno = 1;
- exit(eno);
+ if (!numb) ++numb;
+ if (!(p = calloc(1, numb)))
+ std_err(fmtmk(alloc_msg, numb));
+ return p;
}
- /*
- * Standard error handler to normalize the look of all err o/p */
-static void std_err (const char *str)
+static void *alloc_r (void *q, unsigned numb)
{
- static char buf[SMLBUFSIZ];
+ void *p;
- fflush(stdout);
- /* we'll use our own buffer so callers can still use fmtmk() */
- sprintf(buf, "\t%s: %s\n", Myname, str);
-#ifdef TRAK_MAXBUFS
- MAXBUFS(std_err, buf);
-#endif
- if (!Ttychanged) {
- fprintf(stderr, buf);
- exit(1);
- }
- /* not to worry, he'll change our exit code to 1 due to 'buf' */
- bye_bye(0, buf);
+ if (!numb) ++numb;
+ if (!(p = realloc(q, numb)))
+ std_err(fmtmk(alloc_msg, numb));
+ return p;
}
/*
- * Normal end of execution.
- * catches:
- * SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGQUIT and SIGTERM */
-static void stop (int dont_care_sig)
+ * This guy is modeled on libproc's readproctab function except
+ * we reuse and extend any prior proc_t's. He's been customized
+ * for our specific needs and to avoid the use of <stdarg.h> */
+static proc_t **refreshprocs (proc_t **tbl)
{
- bye_bye(0, NULL);
+#define PTRsz sizeof(proc_t *) /* eyeball candy */
+#define ENTsz sizeof(proc_t)
+ static int flags = PROC_FILLMEM | PROC_FILLCMD | PROC_FILLUSR
+ | PROC_FILLSTATUS | PROC_FILLSTAT;
+ static unsigned savmax = 0; /* first time, Bypass: (i) */
+ proc_t *ptsk = (proc_t *)-1; /* first time, Force: (ii) */
+ unsigned curmax = 0; /* every time (jeeze) */
+ PROCTAB* PT;
+
+ if (Monpidsidx) {
+ PT = openproc(flags | PROC_PID, Monpids);
+ /* work around a previous bug in openproc (now corrected) */
+ PT->procfs = NULL;
+ } else
+ PT = openproc(flags);
+
+ /* i) Allocated Chunks: *Existing* table; refresh + reuse */
+ while (curmax < savmax) {
+ if (tbl[curmax]->cmdline) {
+ free(*tbl[curmax]->cmdline);
+ tbl[curmax]->cmdline = NULL;
+ }
+ if (!(ptsk = readproc(PT, tbl[curmax]))) break;
+ ++curmax;
+ }
+
+ /* ii) Unallocated Chunks: *New* or *Existing* table; extend + fill */
+ while (ptsk) {
+ /* realloc as we go, keeping 'tbl' ahead of 'currmax++' */
+ tbl = alloc_r(tbl, (curmax + 1) * PTRsz);
+ /* here, readproc will allocate the underlying proc_t stg */
+ if ((ptsk = readproc(PT, NULL)))
+ tbl[curmax++] = ptsk;
+ }
+ closeproc(PT);
+
+ /* iii) Chunkless: make 'eot' entry, after possible extension */
+ if (curmax >= savmax) {
+ tbl = alloc_r(tbl, (curmax + 1) * PTRsz);
+ /* here, we must allocate the underlying proc_t stg ourselves */
+ tbl[curmax] = alloc_c(ENTsz);
+ savmax = curmax + 1;
+ }
+ /* this frame's end, but not necessarily end of allocated space */
+ tbl[curmax]->pid = -1;
+ return tbl;
+
+#undef PTRsz
+#undef ENTsz
}
+\f
+/*###### Startup routines ##############################################*/
/*
- * Suspend ourself.
- * catches:
- * SIGTSTP, SIGTTIN and SIGTTOU */
-static void suspend (int dont_care_sig)
+ * No mater what *they* say, we handle the really really BIG and
+ * IMPORTANT stuff upon which all those lessor functions depend! */
+static void before (char *me)
{
- /* reset terminal */
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &Savedtty);
- printf("%s%s", tg2(0, Screen_rows), Cap_curs_norm);
- fflush(stdout);
- raise(SIGSTOP);
- /* later, after SIGCONT... */
- if (!Batch)
- tcsetattr(STDIN_FILENO, TCSAFLUSH, &Rawtty);
+ int i;
+
+ /* setup our program name -- big! */
+ Myname = strrchr(me, '/');
+ if (Myname) ++Myname; else Myname = me;
+
+ /* establish cpu particulars -- even bigger! */
+#ifdef PRETEND4CPUS
+ Cpu_tot = 4;
+#else
+ Cpu_tot = sysconf(_SC_NPROCESSORS_ONLN);
+#endif
+ if (1 > Cpu_tot) Cpu_tot = 1;
+ Cpu_map = alloc_r(NULL, sizeof(int) * Cpu_tot);
+ for (i = 0; i < Cpu_tot; i++)
+ Cpu_map[i] = i;
+
+ /* get virtual page size -- nearing huge! */
+ Page_size = getpagesize();
}
/*
- * Set the screen dimensions and call the real workhorse.
- * catches:
- * SIGWINCH and SIGCONT */
-static void window_resize (int dont_care_sig)
+ * Build the two RC file names then try to read 'em. */
+ /* '/etc/RCfile_Sys' contains two lines consisting of the secure
+ * mode switch and an update interval. It's presence limits what
+ * ordinary users are allowed to do. */
+ /* '$HOME/RCfile' contains multiple lines - 2 global + 3 per window.
+ * line 1: a shameless advertisement
+ * line 2: an id, Show_altcsr, Show_irixps, Delay_time and Curwin.
+ * If running in secure mode via the /etc/rcfile,
+ * Delay_time will be ignored except for root.
+ * For each of the 4 windows:
+ * line a: contains w->winname, fieldscur
+ * line b: contains w->winflags, sorttype, maxtasks
+ * line c: contains w->summclr, msgsclr, headclr, taskclr */
+static void configs_read (void)
{
- struct winsize w;
+ static const char *err_rc = "bad rcfile, you should delete '%s'";
+ char fbuf[RCFBUFSIZ];
+ FILE *fp;
+ float delay = DEF_DELAY;
+ char id;
+ int i;
- Screen_cols = columns;
- Screen_rows = lines;
- if (-1 != (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w))) {
- Screen_cols = w.ws_col;
- Screen_rows = w.ws_row;
+ strcpy(RCfile_Sys, fmtmk("/etc/%src", Myname));
+ if (getenv("HOME"))
+ strcpy(RCfile, fmtmk("%s%c", getenv("HOME"), '/'));
+ strcat(RCfile, fmtmk(".%src", Myname));
+
+ fp = fopen(RCfile_Sys, "r");
+ if (fp) {
+ fbuf[0] = '\0';
+ fgets(fbuf, sizeof(fbuf), fp); /* sys rc file, line #1 */
+ if (strchr(fbuf, 's')) Secure_mode = 1;
+
+ fbuf[0] = '\0';
+ fgets(fbuf, sizeof(fbuf), fp); /* sys rc file, line #2 */
+ fclose(fp);
+ sscanf(fbuf, "%f", &delay);
+ }
+ fp = fopen(RCfile, "r");
+ if (fp) {
+ fgets(fbuf, sizeof(fbuf), fp); /* ignore shameless advertisement */
+ if (5 != (fscanf(fp, "Id:%c, "
+ "Show_altscr=%d, Show_irixps=%d, Delay_time=%f, Curwin=%d\n"
+ , &id, &Show_altscr, &Show_irixps, &delay, &i)))
+ std_err(fmtmk(err_rc, RCfile));
+
+ /* you saw that, right? (fscanf stickin' it to 'i') */
+ Curwin = Winstk[i];
+ for (i = 0; i < GROUPSMAX; i++) {
+ /* we won't check fscanf returns from here on out -- we'll be
+ hunky-dory with nothing in an rcfile except the 1st 2 lines */
+ fscanf(fp, "%s\tfieldscur=%s\n"
+ , Winstk[i]->winname, Winstk[i]->fieldscur);
+ /*
+ Our winname buffer is 4 bytes big - 3 chars + '\0'.
+ Q. let's say someone manually edits the rcfile and increases
+ a winname name to oh, 500 bytes - what's the net result?
+ A. fscanf wipes out 496 bytes of adjacent stg (fieldscur, etc),
+ then we catch it with strlen and end via std_err - no worries!
+ we might not have been so lucky if our WIN_t was laid out
+ differently or statically allocated/stack based!! */
+ if (RCF_FILEID != id || WINNAMSIZ <= strlen(Winstk[i]->winname)
+ || strlen(DEF_FIELDS) != strlen(Winstk[i]->fieldscur))
+ std_err(fmtmk(err_rc, RCfile));
+ fscanf(fp, "\twinflags=%d, sorttype=%c, maxtasks=%d \n"
+ , &Winstk[i]->winflags
+ , (char *)&Winstk[i]->sorttype
+ , &Winstk[i]->maxtasks);
+ fscanf(fp, "\tsummclr=%d, msgsclr=%d, headclr=%d, taskclr=%d \n"
+ , &Winstk[i]->summclr
+ , &Winstk[i]->msgsclr
+ , &Winstk[i]->headclr
+ , &Winstk[i]->taskclr);
+ }
+ fclose(fp);
}
- /* he'll calculate header size, length of command field, etc ... */
- mkheadings();
+ /* lastly, establish the true runtime secure mode and delay time */
+ Secure_mode = getuid() ? Secure_mode : 0;
+ if (!Secure_mode || !getuid()) Delay_time = delay;
}
-\f
-/*###### Startup routines ##############################################*/
/*
- * Parse command line arguments
- * (and force ol' main into a much needed diet)
+ * Parse command line arguments.
* Note: it's assumed that the rc file(s) have already been read
* and our job is to see if any of those options are to be
* overridden -- we'll force some on and negate others in our
- * best effort to honor the user's wishes... */
-static void parse_argvs (char **argv)
+ * best effort to honor the loser's (oops, user's) wishes... */
+static void parse_args (char **args)
{
- /* difference(s) from traditional top:
- -q (zero delay time) eliminated as redundant, use -d0
- -p (pid monitoring) allows comma delimited list
- no deprecated/illegal use of 'goto' with 'breakargv:'
- bunched args are actually handled properly and none are ignored
- (we tolerate No whitespace and No switches -- maybe too tolerant) */
+ /* differences between us and the former top:
+ -q (zero delay) eliminated as redundant, incomplete and inappropriate
+ use: "nice -n-10 top -d0" to achieve what was only claimed
+ -p (pid monitoring) allows, not requires, a comma delimited list
+ . no deprecated/illegal use of 'breakargv:' with goto
+ . bunched args are actually handled properly and none are ignored
+ . we tolerate NO whitespace and NO switches -- maybe too tolerant? */
const char *usage = " -hv | -bcisS -d delay -n iterations -p pid [,pid ...]\n";
float tmp_delay = MAXFLOAT;
char *p;
- ++argv;
- while (*argv) {
- char *cp = *(argv++);
+ while (*args) {
+ char *cp = *(args++);
while (*cp) {
switch (*cp) {
Batch = 1;
break;
case 'c':
- Show_cmdlin = !Show_cmdlin;
+ TOGw(Curwin, Show_CMDLIN);
break;
case 'd':
if (cp[1]) ++cp;
- else if (*argv) cp = *argv++;
+ else if (*args) cp = *args++;
else std_err("-d requires argument");
/* a negative delay will be dealt with shortly... */
if (1 != sscanf(cp, "%f", &tmp_delay))
std_err(fmtmk("\t%s\nusage:\t%s%s"
, procps_version, Myname, usage));
case 'i':
- Show_idleps = !Show_idleps;
+ TOGw(Curwin, Show_IDLEPS);
+ Curwin->maxtasks = 0;
break;
case 'n':
if (cp[1]) cp++;
- else if (*argv) cp = *argv++;
+ else if (*args) cp = *args++;
else std_err("-n requires argument");
if (1 != sscanf(cp, "%d", &Loops) || 0 > Loops)
std_err(fmtmk("bad iterations arg '%s'", cp));
break;
case 'p':
- if (cp[1]) cp++;
- else if (*argv) cp = *argv++;
- else std_err("-p requires argument");
do {
+ if (cp[1]) cp++;
+ else if (*args) cp = *args++;
+ else std_err("-p argument missing");
if (Monpidsidx >= MONPIDMAX)
std_err(fmtmk("pid limit (%d) exceeded", MONPIDMAX));
if (1 != sscanf(cp, "%d", &Monpids[Monpidsidx])
Monpidsidx++;
if (!(p = strchr(cp, ',')))
break;
- cp = ++p;
+ cp = p;
} while (*cp);
break;
case 's':
Secure_mode = 1;
break;
case 'S':
- Show_ctimes = !Show_ctimes;
+ TOGw(Curwin, Show_CTIMES);
break;
default :
std_err(fmtmk("unknown argument '%c'\nusage:\t%s%s"
, *cp, Myname, usage));
- } /* end: switch */
- /* advance cp and jump over any numerical args used above */
- cp += strspn(++cp, "-.1234567890 ");
+ } /* end: switch (*cp) */
- } /* end: while *cp */
- } /* end: while *argv */
+ /* advance cp and jump over any numerical args used above */
+ if (*cp) cp += strspn(++cp, "- ,.1234567890");
+ } /* end: while (*cp) */
+ } /* end: while (*args) */
/* fixup delay time, maybe... */
if (MAXFLOAT != tmp_delay) {
else
Delay_time = tmp_delay;
}
-
- /* set the default sort type, maybe... */
- if (-1 == Sort_type || Monpidsidx) {
- Sort_type = S_PID;
- Sort_func = (QSORT_t)sort_pid;
- }
-}
-
-
- /*
- * Parse the options string as read from line two of the "local"
- * configuration file. */
-static void parse_rc (char *opts)
-{
- unsigned i;
-
- for (i = 0; i < strlen(opts); i++) {
- switch (opts[i]) {
- case 'b':
- Show_hibold = 1;
- break;
- case 'c':
- Show_cmdlin = 1;
- break;
- case 'C':
- Sort_type = S_CMD;
- Sort_func = (QSORT_t)sort_cmd;
- break;
- case 'E':
- Sort_type = S_USR;
- Sort_func = (QSORT_t)sort_usr;
- break;
- case 'i':
- Show_idleps = 1;
- break;
- case 'I':
- Irix_mode = 1;
- break;
- case 'l':
- HSum_loadav = 1;
- break;
- case 'm':
- HSum_memory = 1;
- break;
- case 'M':
- Sort_type = S_MEM;
- Sort_func = (QSORT_t)sort_mem;
- break;
- case 'P':
- Sort_type = S_PID;
- Sort_func = (QSORT_t)sort_pid;
- break;
- case 'R':
- Sort_normal = 1;
- break;
- case 'S':
- Show_ctimes = 1;
- break;
- case 't':
- HSum_states = 1;
- break;
- case 'T':
- Sort_type = S_TME;
- Sort_func = (QSORT_t)sort_tme;
- break;
- case 'U':
- Sort_type = S_CPU;
- Sort_func = (QSORT_t)sort_cpu;
- break;
- case 'x':
- Show_hicols = 1;
- break;
- case 'y':
- Show_hirows = 1;
- break;
- case 'Y':
- Sort_type = S_TTY;
- Sort_func = (QSORT_t)sort_tty;
- break;
- case 'z':
- Show_colors = 1;
- break;
- case '1':
- Show_cpusum = 1;
- break;
- case ' ' : /* these serve as rc file comments */
- case '\t': /* and will be treated as 'eol' */
- case '\n':
- return;
- default :
- std_err(fmtmk("bad config option - '%c'", opts[i]));
- }
- }
-}
-
-
- /*
- * Build the two RC file names then try to read 'em.
- *
- * '/etc/RCfile_Sys' contains two lines consisting of the secure mode
- * switch and an update interval. It's presence limits what ordinary
- * users are allowed to do.
- *
- * '$HOME/RCfile' contains five lines.
- * line 1: specifies the fields that are to be displayed
- * and their order. Uppercase letters == displayed,
- * lowercase letters == not shown.
- * line 2: specifies miscellaneous display options and
- * toggles along with the prefered sort order.
- * line 3: specifies maximum processes, 0 == unlimited.
- * line 4: specifies the update interval. If run in secure
- * mode, this value will be ignored except for root.
- * line 5: specifies the 3 basic color values. */
-static void rcfiles_read (void)
-{
- char fbuf[RCFBUFSIZ];
- FILE *fp;
-
- strcpy(RCfile_Sys, fmtmk("/etc/%src", Myrealname));
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, RCfile_Sys);
-#endif
- if (getenv("HOME"))
- strcpy(RCfile, fmtmk("%s%c", getenv("HOME"), '/'));
- strcat(RCfile, fmtmk(".%src", Myname));
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, RCfile);
-#endif
-
- fp = fopen(RCfile_Sys, "r");
- if (fp) {
- fbuf[0] = '\0';
- fgets(fbuf, sizeof(fbuf), fp); /* sys rc file, line #1 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- if (strchr(fbuf, 's')) Secure_mode = 1;
-
- fbuf[0] = '\0';
- fgets(fbuf, sizeof(fbuf), fp); /* sys rc file, line #2 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- fclose(fp);
- sscanf(fbuf, "%f", &Delay_time);
- }
-
- fp = fopen(RCfile, "r");
- if (fp) {
- fbuf[0] = '\0';
- if (fgets(fbuf, sizeof(fbuf), fp)) { /* rc file, line #1 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- strcpy(CurFields, strim(0, fbuf));
- /* Now that we've found an rc file, we'll honor those
- preferences by first turning off everything... */
- Irix_mode = 0;
- HSum_states = HSum_memory = HSum_loadav = Show_cpusum = 0;
- Show_cmdlin = Show_ctimes = Show_idleps = Sort_normal = 0;
- Show_colors = Show_hicols = Show_hirows = Show_hibold = 0;
-
- fbuf[0] = '\0';
- fgets(fbuf, sizeof(fbuf), fp); /* rc file, line #2 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- /* we could subsume this next guy since we're the only caller
- -- but we're both too fat already... */
- parse_rc(strim(0, fbuf));
-
- fbuf[0] = '\0';
- fgets(fbuf, sizeof(fbuf), fp); /* rc file, line #3 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- sscanf(fbuf, "%d", &Max_tasks);
-
- fbuf[0] = '\0';
- fgets(fbuf, sizeof(fbuf), fp); /* rc file, line #4 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- if (!Secure_mode || !getuid())
- sscanf(fbuf, "%f", &Delay_time);
-
- fbuf[0] = '\0';
- fgets(fbuf, sizeof(fbuf), fp); /* rc file, line #5 */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(rcfiles_read, fbuf);
-#endif
- sscanf(fbuf, "%d,%d,%d", &Base_color, &Msgs_color, &Head_color);
- }
- fclose(fp);
- }
- /* protect against meddling leading to a possible fault --
- shorter would kinda' work, longer ain't healthy for us! */
- if (strlen(CurFields) != strlen(DEF_FIELDS))
- strcpy(CurFields, DEF_FIELDS);
-
- /* lastly, establish the true runtime secure mode */
- Secure_mode = getuid() ? Secure_mode : 0;
}
/*
* Set up the terminal attributes */
-static void terminal_set (void)
+static void whack_terminal (void)
{
struct termios newtty;
- /* first the ncurses part... */
+ /* first the curses part... */
#ifdef PRETENDNOCAP
setupterm((char *)"dumb", STDOUT_FILENO, NULL);
#else
if (!Batch) {
if (-1 == tcgetattr(STDIN_FILENO, &Savedtty))
std_err("tcgetattr() failed");
- capsmk();
newtty = Savedtty;
newtty.c_lflag &= ~ICANON;
newtty.c_lflag &= ~ECHO;
* text is then output */
static void display_fields (void)
{
+#define yRSVD 3
const char *p, *x;
- int i, cmax = Screen_cols / 2, rmax = Screen_rows - 3;
+ int i, cmax = Screen_cols / 2, rmax = Screen_rows - yRSVD;
/* we're relying on our callers to first clear the screen --
thus 'fields_toggle' can avoid screen flicker since he's
for (p = Fieldstab[i].head; ' ' == *p; ++p)
;
printf("%s%c %c: %-10s = %s"
- , tg2((i / rmax) * cmax, (i % rmax) + 3)
- , strchr(CurFields, i + 'A') ? '*' : ' '
+ , tg2((i / rmax) * cmax, (i % rmax) + yRSVD)
+ , strchr(Curwin->fieldscur, i + 'A') ? '*' : ' '
, i + 'A'
, p
, Fieldstab[i].desc);
}
- putp(Row_color_norm);
+ putp(Curwin->capclr_rownorm);
x = FIELDS_xtra;
while ((p = strchr(x, '\n'))) {
++i;
printf("%s%.*s"
- , tg2((i / rmax) * cmax, (i % rmax) + 3)
+ , tg2((i / rmax) * cmax, (i % rmax) + yRSVD)
, p - x, x);
x = ++p;
}
putp(Caps_off);
+
+#undef yRSVD
}
* Change order of displayed fields. */
static void fields_reorder (void)
{
- static char prompt[] =
+ static const char *prompt =
"Upper case characters move field left, lower case right";
char c, *p;
int i;
display_fields();
do {
show_special(fmtmk(FIELDS_current
- , Cap_home, Myname, CurFields, prompt));
+ , Cap_home, Myname, Curwin->fieldscur, Curwin->grpname, prompt));
chin(0, &c, 1);
i = toupper(c) - 'A';
if (i < 0 || i >= MAXtbl(Fieldstab))
break;
- if (((p = strchr(CurFields, i + 'A')))
- || ((p = strchr(CurFields, i + 'a')))) {
+ if (((p = strchr(Curwin->fieldscur, i + 'A')))
+ || ((p = strchr(Curwin->fieldscur, i + 'a')))) {
if (isupper(c)) p--;
- if (('\0' != p[1]) && (p >= CurFields)) {
+ if (('\0' != p[1]) && (p >= Curwin->fieldscur)) {
c = p[0];
p[0] = p[1];
p[1] = c;
}
} while (1);
putp(Cap_curs_norm);
- mkheadings();
}
* Toggle displayed fields. */
static void fields_toggle (void)
{
- static char prompt[] =
+ static const char *prompt =
"Toggle fields with a-x, type any other key to return";
char c, *p;
int i;
do {
display_fields();
show_special(fmtmk(FIELDS_current
- , Cap_home, Myname, CurFields, prompt));
+ , Cap_home, Myname, Curwin->fieldscur, Curwin->grpname, prompt));
chin(0, &c, 1);
i = toupper(c) - 'A';
if (i < 0 || i >= MAXtbl(Fieldstab))
break;
- if ((p = strchr(CurFields, i + 'A')))
+ if ((p = strchr(Curwin->fieldscur, i + 'A')))
*p = i + 'a';
- else if ((p = strchr(CurFields, i + 'a')))
+ else if ((p = strchr(Curwin->fieldscur, i + 'a')))
*p = i + 'A';
} while (1);
putp(Cap_curs_norm);
- mkheadings();
}
\f
-/*###### Library Alternatives ##########################################*/
+/*###### Windows/Field Groups support #################################*/
/*
- * Handle our own memory stuff without the risk of leaving the
- * user's terminal in an ugly state should things go sour. */
-static const char *alloc_msg = "Failed memory allocate (%d bytes)";
-
-static void *alloc_c (unsigned numb)
+ * Set the number of fields/columns to display;
+ * Create the field columns heading; and then
+ * Set maximum cmdline length. */
+static void win_colsheads (WIN_t *q)
{
- void * p;
+ const char *h;
+ int i, needpsdb = 0;
- if (!numb) ++numb;
- if (!(p = calloc(1, numb)))
- std_err(fmtmk(alloc_msg, numb));
- return p;
+ /* build window's procflags array and establish a tentative maxpflgs */
+ for (i = 0, q->maxpflgs = 0; i < (int)strlen(q->fieldscur); i++) {
+ if (isupper(q->fieldscur[i]))
+ q->procflags[q->maxpflgs++] = q->fieldscur[i] - 'A';
+ }
+
+ /* build a preliminary columns header not to exceed screen width
+ (and account for a possible leading window number) */
+ if (Show_altscr) strcpy(q->columnhdr, " "); else q->columnhdr[0] = '\0';
+ for (i = 0; i < q->maxpflgs; i++) {
+ h = Fieldstab[q->procflags[i]].head;
+ /* oops, won't fit -- we're outta here... */
+ if (Screen_cols < (int)(strlen(q->columnhdr) + strlen(h))) break;
+ strcat(q->columnhdr, h);
+ }
+
+ /* establish the final maxpflgs and prepare to grow the command
+ column heading via maxcmdln -- it may be a fib if P_CMD wasn't
+ encountered, but that's ok because it won't be displayed anyway */
+ q->maxpflgs = i;
+ q->maxcmdln = Screen_cols
+ - (strlen(q->columnhdr) - strlen(Fieldstab[P_CMD].head)) - 1;
+
+ /* now we can build the true run-time columns header and format the
+ command column heading if P_CMD is really being displayed --
+ show_a_task is aware of the addition of winnum to the header */
+ sprintf(q->columnhdr, "%s", Show_altscr ? fmtmk("%d", mkWNO(q)) : "");
+ for (i = 0; i < q->maxpflgs; i++) {
+ /* are we gonna' need the kernel symbol table? */
+ if (P_WCHAN == q->procflags[i]) needpsdb = 1;
+ h = Fieldstab[q->procflags[i]].head;
+ if (P_CMD == q->procflags[i])
+ strcat(q->columnhdr
+ , fmtmk(Fieldstab[P_CMD].fmts, q->maxcmdln, q->maxcmdln, h));
+ else
+ strcat(q->columnhdr, h);
+ }
+
+ /* do we need the kernel symbol table (and is it already open?) */
+ if (needpsdb) {
+ if (-1 == No_ksyms) {
+ No_ksyms = 0;
+ if (open_psdb_message(NULL, msg_save))
+ /* why so counter-intuitive, couldn't open_psdb_message
+ mirror sysmap_mmap -- that func does all the work anyway? */
+ No_ksyms = 1;
+ else
+ PSDBopen = 1;
+ }
+ }
}
-static void *alloc_r (void *q, unsigned numb)
+ /*
+ * Value a window's name and make the associated group name. */
+static void win_names (WIN_t *q, const char *name)
{
- void *p;
-
- if (!numb) ++numb;
- if (!(p = realloc(q, numb)))
- std_err(fmtmk(alloc_msg, numb));
- return p;
+ /* these safeguards are totally unnecessary if our caller(s) are
+ internal, they can be trusted -- it's those darn users that we
+ worry 'bout... */
+ sprintf(q->winname, "%.*s", WINNAMSIZ -1, name);
+ sprintf(q->grpname, "%d:%.*s", mkWNO(q), WINNAMSIZ -1, name);
}
/*
- * This guy is modeled on libproc's readproctab function except
- * we reuse and extend any prior proc_t's. He's been customized
- * for our specific needs and to avoid the use of <stdarg.h> */
-static proc_t **readprocs (proc_t **tbl)
+ * Display a window/field group (ie. make it "current"). */
+static void win_select (int ch)
{
-#define PTRsz sizeof(proc_t *) /* eyeball candy */
-#define ENTsz sizeof(proc_t)
- static int flags = PROC_FILLMEM | PROC_FILLCMD | PROC_FILLUSR
- | PROC_FILLSTATUS | PROC_FILLSTAT;
- static unsigned savmax = 0; /* first time, bypass: (i) */
- proc_t *ptsk = (proc_t *)-1; /* first time, force: (ii) */
- unsigned curmax = 0; /* every time */
- PROCTAB* PT;
-
- if (Monpidsidx) {
- PT = openproc(flags | PROC_PID, Monpids);
- /* work around a previous bug in openproc (now corrected) */
- PT->procfs = NULL;
- } else
- PT = openproc(flags);
-
- /* i) Allocated Chunks: *Existing* table; refresh + reuse */
- while (curmax < savmax) {
- if (tbl[curmax]->cmdline) {
- free(*tbl[curmax]->cmdline);
- tbl[curmax]->cmdline = NULL;
- }
- if (!(ptsk = readproc(PT, tbl[curmax]))) break;
- ++curmax;
- }
+ static const char *prompt = "Choose field group (1 - 4)";
- /* ii) Unallocated Chunks: *New* or *Existing* table; extend + fill */
- while (ptsk) {
- /* realloc as we go, keeping 'tbl' ahead of 'currmax++' */
- tbl = alloc_r(tbl, (curmax + 1) * PTRsz);
- /* here, readproc will allocate the underlying proc_t stg */
- if ((ptsk = readproc(PT, NULL)))
- tbl[curmax++] = ptsk;
+ /* if there's no ch, it means we're supporting the normal do_key routine,
+ so we must try to get our own darn ch by begging the user... */
+ if (!ch) {
+ show_pmt(prompt);
+ chin(0, (char *)&ch, 1);
}
- closeproc(PT);
-
- /* iii) Chunkless: make 'eot' entry, after possible extension */
- if (curmax >= savmax) {
- tbl = alloc_r(tbl, (curmax + 1) * PTRsz);
- /* here, we must allocate the underlying proc_t stg ourselves */
- tbl[curmax] = alloc_c(ENTsz);
- savmax = curmax + 1;
+ switch (ch) {
+ case 'a': /* we don't carry 'a' / 'w' in our */
+ Curwin = Curwin->next; /* user prompt - those case labels */
+ break; /* are just here for a good friend */
+ case 'w': /* of ours, wins_colors (however, */
+ Curwin = Curwin->prev; /* those letters work via the pmt */
+ break; /* too -- but really the end-loser */
+ case '1': /* should just press the darn key */
+ Curwin = Winstk[Def_WINDOW]; /* in the first place) */
+ break;
+ case '2':
+ Curwin = Winstk[Job_WINDOW];
+ break;
+ case '3':
+ Curwin = Winstk[Mem_WINDOW];
+ break;
+ case '4':
+ Curwin = Winstk[Usr_WINDOW];
+ break;
}
- /* this frame's end, but not necessarily end of allocated space */
- tbl[curmax]->pid = -1;
- return tbl;
-
-#undef PTRsz
-#undef ENTsz
}
-\f
-/*###### Main screen routines ##########################################*/
/*
- * Process keyboard input during the main loop plus the three
- * special immediate keys used with help processing.
- * (thus making us only slightly recursive) */
-static void do_key (unsigned c)
+ * Establish the requested sort environment */
+static void win_sortset (WIN_t *q, const int which)
{
-#define kbdCTRL_L 12
- /* standardized 'secure mode' errors */
- const char *smerror = "\aCan't %s in secure mode";
-
- switch (c) {
- case 'b':
- if (!Show_hicols && !Show_hirows)
- show_msg("\aNothing to highlight!");
- else {
- Show_hibold = !Show_hibold;
- }
- capsmk();
- break;
-
- case 'c':
- Show_cmdlin = !Show_cmdlin;
- break;
-
+ /* note: everyone and their brother uses only the enum's to identify
+ sort type, but we use both the actual value and the enum so
+ somewhere outside the header it's apparent which is what */
+ switch (which) {
case 'C':
- Sort_type = S_CMD;
- Sort_func = (QSORT_t)sort_cmd;
+ q->sorttype = S_CMD;
+ q->sortfunc = (QSORT_t)sort_cmd;
break;
-
case 'E':
- Sort_type = S_USR;
- Sort_func = (QSORT_t)sort_usr;
- break;
-
- case 'f':
- case 'F':
- fields_toggle();
- break;
-
- case 'i':
- Show_idleps = !Show_idleps;
- break;
-
- case 'I':
- if (Cpu_tot > 1) {
- Irix_mode = !Irix_mode;
- show_msg(fmtmk("Irix mode %s", Irix_mode ? "On" : "Off"));
- } else
- show_msg("\aIrix mode requires SMP!");
- break;
-
- case 'k':
- if (Secure_mode) {
- show_msg(fmtmk(smerror, "kill"));
- } else {
- int sig, pid = get_int("PID to kill");
-
- if (-1 != pid) {
-#ifdef UGH_ITS_4_RH
- sig = get_signal2(
-#else
- sig = signal_name_to_number(
-#endif
- ask_str(fmtmk("Kill PID %d with signal [%i]"
- , pid, DEF_SIGNAL)));
- if (-1 == sig) sig = DEF_SIGNAL;
- if (sig && kill(pid, sig))
- show_msg(fmtmk("\aKill of PID '%d' with '%d' failed: %s"
- , pid, sig, strerror(errno)));
- }
- }
- break;
-
- case 'l':
- HSum_loadav = !HSum_loadav;
- mkheadings();
+ q->sorttype = S_USR;
+ q->sortfunc = (QSORT_t)sort_usr;
break;
-
- case 'm':
- HSum_memory = !HSum_memory;
- mkheadings();
- break;
-
case 'M':
- Sort_type = S_MEM;
- Sort_func = (QSORT_t)sort_mem;
- break;
-
- case 'n':
- case '#':
- { int num;
-
- if (-1 != (num = get_int("Processes to display (0 = unlimited)"))) {
- Max_tasks = num;
- window_resize(0);
- }
- }
- break;
-
- case 'o':
- case 'O':
- fields_reorder();
+ q->sorttype = S_MEM;
+ q->sortfunc = (QSORT_t)sort_mem;
break;
-
case 'P':
- Sort_type = S_PID;
- Sort_func = (QSORT_t)sort_pid;
- break;
-
- case 'q':
- stop(0);
-
- case 'r':
- if (Secure_mode)
- show_msg(fmtmk(smerror, "renice"));
- else {
- int pid, val;
-
- pid = get_int("PID to renice");
- if (-1 == pid) break;
- val = get_int(fmtmk("Renice PID %d to value", pid));
- if (setpriority(PRIO_PROCESS, (unsigned)pid, val))
- show_msg(fmtmk("\aRenice of PID %d to %d failed: %s"
- , pid, val, strerror(errno)));
- }
- break;
-
- case 'R':
- Sort_normal = !Sort_normal;
- break;
-
- case 's':
- case 'd':
- if (Secure_mode)
- show_msg(fmtmk(smerror, "change delay"));
- else {
- float tmp =
- get_float(fmtmk("Change delay from %.1f to", Delay_time));
- if (tmp > -1) Delay_time = tmp;
- }
- break;
-
- case 'S':
- Show_ctimes = !Show_ctimes;
- show_msg(fmtmk("Cumulative time %s", Show_ctimes ? "On" : "Off"));
- break;
-
- case 't':
- HSum_states = !HSum_states;
- mkheadings();
+ q->sorttype = S_PID;
+ q->sortfunc = (QSORT_t)pid_sort;
break;
-
case 'T':
- Sort_type = S_TME;
- Sort_func = (QSORT_t)sort_tme;
- break;
-
- case 'u':
- strcpy(ColUsername, ask_str("Which User (Blank for All)"));
-#ifdef TRAK_MAXBUFS
- MAXBUFS(do_key, ColUsername);
-#endif
+ q->sorttype = S_TME;
+ q->sortfunc = (QSORT_t)sort_tme;
break;
-
case 'U':
- Sort_type = S_CPU;
- Sort_func = (QSORT_t)sort_cpu;
- break;
-
- case 'W':
- { FILE *fp = fopen(RCfile, "w");
-
- if (fp) {
- fprintf(fp, "%s\t\t# Fields displayed and ordering\n"
- , CurFields);
- fprintf(fp, "%s%s%s%s%s%s%s%s%s%s%s%s%s%c"
- "\t\t\t\t# Misc options (spelled poorly)\n"
- , Show_cmdlin ? "c" : "", Sort_normal ? "R" : ""
- , HSum_loadav ? "l" : "", Show_hirows ? "y" : ""
- , HSum_memory ? "m" : "", Show_hicols ? "x" : ""
- , Show_idleps ? "i" : "", Show_ctimes ? "S" : ""
- , Irix_mode ? "I" : "", HSum_states ? "t" : ""
- , Show_hibold ? "b" : "", Show_colors ? "z" : ""
- , Show_cpusum ? "1" : "", Sort_type);
- fprintf(fp, "%d\t\t\t\t\t# Number of tasks shown\n"
- , Max_tasks);
- fprintf(fp, "%.1f\t\t\t\t\t# Delay between updates\n"
- , Delay_time);
- fprintf(fp, "%u,%u,%u\t\t\t\t\t# Base, Msgs & Head colors\n"
- , Base_color, Msgs_color, Head_color);
- fclose(fp);
- show_msg(fmtmk("Wrote configuration to '%s'", RCfile));
- } else
- show_msg(fmtmk("\aFailed '%s' open: %s", RCfile, strerror(errno)));
- }
- break;
-
- case 'x':
- Show_hicols = !Show_hicols;
- capsmk();
- break;
-
- case 'y':
- Show_hirows = !Show_hirows;
- capsmk();
+ q->sorttype = S_CPU;
+ q->sortfunc = (QSORT_t)sort_cpu;
break;
-
case 'Y':
- Sort_type = S_TTY;
- Sort_func = (QSORT_t)sort_tty;
- break;
-
- case 'z':
- Show_colors = !Show_colors;
- capsmk();
- break;
-
- case 'Z':
- tweak_colors();
- break;
-
- case '?':
- case 'h':
- { char ch;
-
- printf("%s%s", Cap_clr_scr, Cap_curs_huge);
- /* this string is well above ISO C89's minimum requirements! */
- show_special(fmtmk(HELP_data
- , Myname, procps_version
- , Secure_mode ? "On" : "Off", Show_ctimes ? "On" : "Off", Delay_time
- , Secure_mode ? "" : HELP_unsecured));
- chin(0, &ch, 1);
- putp(Cap_curs_norm);
- /* our help screen currently provides for three 'immediate' keys,
- two of which conflict with the main process display keys */
- switch (ch) {
- case 'j' :
- strcpy(CurFields, JOB_FIELDS);
- ch = 'T'; /* force sort on time */
- break;
- case 'm' :
- strcpy(CurFields, MEM_FIELDS);
- ch = 'M'; /* force sort on %mem/res */
- break;
- case 'u' :
- strcpy(CurFields, USR_FIELDS);
- ch = 'E'; /* force sort on user */
- break;
- default :
- ch = 0;
- }
- if (ch) {
- /* besides resetting the sort environment with the call to us
- below, the 'Show_' manipulations will provide our most subtle
- hint as to what the user has just wrought */
- Show_hibold = Show_hicols = Sort_normal = 1;
- capsmk();
- mkheadings();
- do_key((unsigned)ch);
- }
- }
- break;
-
- case ' ':
- case kbdCTRL_L:
- putp(Cap_clr_scr);
+ q->sorttype = S_TTY;
+ q->sortfunc = (QSORT_t)sort_tty;
break;
-
- case '1':
- Show_cpusum = !Show_cpusum;
- mkheadings();
- break;
-
- case '\n': /* just ignore it */
- break;
-
- default:
- show_msg("\aUnknown command -- try 'h' for help");
}
-
-#undef kbdCTRL_L
-#undef smERROR
}
-
-#ifdef UGH_ITS_4_RH
/*
- * Obtain memory information and display it.
- * Return the total memory available as a page count which is
- * then used in % memory calc's. */
-static unsigned frame_memory (void)
+ * Just warn the user when a command can't be honored. */
+static int win_warn (void)
{
- /* don't be mislead by the proc/sysinfo subscripts, they're just poorly
- chosen names for enumerations apparently designed to make source
- lines as imbalanced and as long as possible */
- unsigned long long **memarray;
-
- if (!(memarray = meminfo()))
- std_err("Failed /proc/meminfo read");
-
- if (HSum_memory) {
- show_special(fmtmk(MEMORY_line1
- , BYTES_2K(memarray[meminfo_main][meminfo_total])
- , BYTES_2K(memarray[meminfo_main][meminfo_used])
- , BYTES_2K(memarray[meminfo_main][meminfo_free])
- , BYTES_2K(memarray[meminfo_main][meminfo_buffers])));
-
- show_special(fmtmk(MEMORY_line2
- , BYTES_2K(memarray[meminfo_swap][meminfo_total])
- , BYTES_2K(memarray[meminfo_swap][meminfo_used])
- , BYTES_2K(memarray[meminfo_swap][meminfo_free])
- , BYTES_2K(memarray[meminfo_total][meminfo_cached])));
- }
+ show_msg(fmtmk("\aCommand disabled, activate window #%d with '-' or '_'"
+ , mkWNO(Curwin)));
- return PAGE_CNT(memarray[meminfo_main][meminfo_total]);
+ /* we gotta' return false 'cause we're somewhat well known within
+ macro society, by way of that sassy little tertiary operator... */
+ return 0;
}
-#else
/*
- * Obtain memory information and display it. */
-static void frame_memory (void)
+ * Change colors *Helper* function to save/restore settings;
+ * ensure colors will show; and rebuild the terminfo strings. */
+static void winsclr (WIN_t *q, int save)
{
- meminfo();
- if (HSum_memory) {
- show_special(fmtmk(MEMORY_line1
- , kb_main_total
- , kb_main_used
- , kb_main_free
- , kb_main_buffers));
+ static int flgssav, summsav, msgssav, headsav, tasksav;
- show_special(fmtmk(MEMORY_line2
- , kb_swap_total
- , kb_swap_used
- , kb_swap_free
- , kb_main_cached));
+ if (save) {
+ flgssav = q->winflags; summsav = q->summclr;
+ msgssav = q->msgsclr; headsav = q->headclr; tasksav = q->taskclr;
+ SETw(q, Show_COLORS);
+ } else {
+ q->winflags = flgssav; q->summclr = summsav;
+ q->msgsclr = msgssav; q->headclr = headsav; q->taskclr = tasksav;
}
+ capsmk(q);
}
-#endif /* end: UGH_ITS_4_RH */
/*
- * State display *Helper* function to calc and display the state
- * percentages for a single cpu. In this way, we can support
- * the following environments without the usual code bloat.
- * 1 - single cpu machines
- * 2 - modest smp boxes with room for each cpu's percentages
- * 3 - massive smp guys leaving little or no room for process
- * display and thus requiring the Show_cpusum toggle */
-static void frame_smp (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx)
+ * Change colors used in display */
+static void wins_colors (void)
{
- /* we'll trim to zero if we get negative time ticks,
- which has happened with some SMP kernels (pre-2.4?) */
-#define TRIMz(x) ((tz = (long)x) < 0 ? 0 : tz)
- TICS_t u_tics, s_tics, n_tics, i_tics;
- long u_frme, s_frme, n_frme, i_frme, tot_frme, tz;
-
- if (4 != fscanf(fp, fmt, &u_tics, &n_tics, &s_tics, &i_tics))
- std_err("Failed /proc/stat read");
+#define kbdABORT 'q'
+#define kbdAPPLY '\n'
+ int clr = Curwin->taskclr, *pclr = &Curwin->taskclr;
+ char ch, tgt = 'T';
- u_frme = TRIMz(u_tics - cpu->u);
+ if (0 >= max_colors) {
+ show_msg("\aNo colors to map!");
+ return;
+ }
+ winsclr(Curwin, 1);
+ printf("%s%s", Cap_clr_scr, Cap_curs_huge);
+
+ do {
+ /* this string is well above ISO C89's minimum requirements! */
+ show_special(fmtmk(COLOR_help
+ , Cap_home, Myname, procps_version, Curwin->grpname
+ , CHKw(Curwin, Show_HIBOLD) ? "On" : "Off"
+ , CHKw(Curwin, Show_COLORS) ? "On" : "Off"
+ , tgt, clr, Curwin->winname));
+ chin(0, &ch, 1);
+ switch (ch) {
+ case 'S':
+ pclr = &Curwin->summclr;
+ clr = *pclr;
+ tgt = ch;
+ break;
+ case 'M':
+ pclr = &Curwin->msgsclr;
+ clr = *pclr;
+ tgt = ch;
+ break;
+ case 'H':
+ pclr = &Curwin->headclr;
+ clr = *pclr;
+ tgt = ch;
+ break;
+ case 'T':
+ pclr = &Curwin->taskclr;
+ clr = *pclr;
+ tgt = ch;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ clr = ch - '0';
+ *pclr = clr;
+ break;
+ case 'b':
+ TOGw(Curwin, Show_HIBOLD);
+ break;
+ case 'z':
+ TOGw(Curwin, Show_COLORS);
+ break;
+ case 'a':
+ case 'w':
+ win_select(ch);
+ winsclr(Curwin, 1);
+ clr = Curwin->taskclr, pclr = &Curwin->taskclr;
+ tgt = 'T';
+ break;
+ }
+ capsmk(Curwin);
+ } while (kbdAPPLY != ch && kbdABORT != ch);
+
+ if (kbdABORT == ch)
+ winsclr(Curwin, 0);
+ putp(Cap_curs_norm);
+
+#undef kbdABORT
+#undef kbdAPPLY
+}
+
+
+ /*
+ * Manipulate flag(s) for all our windows. */
+static void wins_reflag (int what, int flg)
+{
+ WIN_t *w;
+
+ w = Curwin;
+ do {
+ switch (what) {
+ case Flgs_TOG:
+ TOGw(w, flg);
+ break;
+ case Flgs_SET:
+ SETw(w, flg);
+ break;
+ case Flgs_OFF:
+ OFFw(w, flg);
+ break;
+ }
+ w = w->next;
+ } while (w != Curwin);
+
+ /* a flag with special significance -- user wants to rebalance display
+ so darn it, we gotta' spin thru all those windows one mo' time and
+ 'off' one number then force on two flags... */
+ /* (jeeze, doesn't this idiot know there are just 4 windows?) */
+ if (EQUWINS_cwo == flg) {
+ w = Curwin;
+ do {
+ w->maxtasks = 0;
+ SETw(w, Show_IDLEPS | VISIBLE_tsk);
+ w = w->next;
+ } while (w != Curwin);
+ }
+}
+
+
+ /*
+ * Set the screen dimensions and call the real workhorse.
+ * (also) catches:
+ * SIGWINCH and SIGCONT */
+static void wins_resize (int dont_care_sig)
+{
+ struct winsize wz;
+ WIN_t *w;
+
+ Screen_cols = columns;
+ Screen_rows = lines;
+ if (-1 != (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wz))) {
+ Screen_cols = wz.ws_col;
+ Screen_rows = wz.ws_row;
+ }
+ w = Curwin;
+ do {
+ win_colsheads(w);
+ w = w->next;
+ } while (w != Curwin);
+}
+
+
+ /*
+ * Set up the raw/incomplete field group windows --
+ * they'll be finished off after startup completes.
+ * (and very likely that will override most/all of our efforts)
+ * ( --- life-is-NOT-fair --- ) */
+static void windows_stage1 (void)
+{
+ static struct {
+ const char *name;
+ const char *flds;
+ int sort;
+ int clrs[4]; /* summ, msgs, heads, task */
+ } wtab[] = {
+ { "Def", DEF_FIELDS, S_PID,
+ { COLOR_RED, COLOR_RED, COLOR_YELLOW, COLOR_RED } },
+ { "Job", JOB_FIELDS, S_TME,
+ { COLOR_CYAN, COLOR_CYAN, COLOR_WHITE, COLOR_CYAN } },
+ { "Mem", MEM_FIELDS, S_MEM,
+ { COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLUE, COLOR_MAGENTA } },
+ { "Usr", USR_FIELDS, S_USR,
+ { COLOR_YELLOW, COLOR_YELLOW, COLOR_GREEN, COLOR_YELLOW } },
+ };
+ WIN_t *w;
+ char *pc;
+ int i, x, *pi;
+
+ /* get all our window structs in one big chunk */
+ w = alloc_c(sizeof(WIN_t) * GROUPSMAX);
+
+ for (i = 0; i < GROUPSMAX; i++) {
+ Winstk[i] = w;
+ w->winnum = i;
+ strcpy(w->winname, wtab[i].name);
+ strcpy(w->fieldscur, wtab[i].flds);
+ w->sorttype = wtab[i].sort;
+ w->winflags = DEF_WINFLGS;
+ for (x = 0, pi = &w->summclr; x < 4; x++, pi++)
+ *pi = wtab[i].clrs[x];
+ w->captab[0] = Cap_norm;
+ w->captab[1] = Cap_norm;
+ w->captab[2] = Cap_bold;
+ /* complete this win's captab, but not the brute force way... */
+ for (x = 3, pc = w->capclr_sum; x < CAPTABMAX; x++) {
+ w->captab[x] = pc;
+ pc += CLRBUFSIZ;
+ }
+ w->next = w + 1;
+ w->prev = w - 1;
+ ++w;
+ }
+ /* fixup the circular chains... */
+ Winstk[Usr_WINDOW]->next = Winstk[0];
+ Winstk[0]->prev = Winstk[Usr_WINDOW];
+ Curwin = Winstk[0];
+ Show_altscr = 0;
+}
+
+
+ /*
+ * This guy just completes the field group windows after the
+ * rcfiles have been read and command line arguments parsed
+ * (he's also key to the success of that darn Batch mode). */
+static void windows_stage2 (void)
+{
+ int i;
+
+ if (Batch) {
+ Show_altscr = 0;
+ OFFw(Curwin, Show_COLORS);
+ }
+ wins_resize(0);
+ for (i = 0; i < GROUPSMAX; i++) {
+ win_names(Winstk[i], Winstk[i]->winname);
+ win_sortset(Winstk[i], Winstk[i]->sorttype);
+ capsmk(Winstk[i]);
+ }
+}
+
+\f
+/*###### Per-Frame Display support #####################################*/
+
+ /*
+ * State display *Helper* function to calc and display the state
+ * percentages for a single cpu. In this way, we can support
+ * the following environments without the usual code bloat.
+ * 1 - single cpu machines
+ * 2 - modest smp boxes with room for each cpu's percentages
+ * 3 - massive smp guys leaving little or no room for process
+ * display and thus requiring the cpu summary toggle */
+static void cpudo (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx)
+{
+ /* we'll trim to zero if we get negative time ticks,
+ which has happened with some SMP kernels (pre-2.4?) */
+#define TRIMz(x) ((tz = (long)x) < 0 ? 0 : tz)
+ TICS_t u_tics, s_tics, n_tics, i_tics;
+ long u_frme, s_frme, n_frme, i_frme, tot_frme, tz;
+
+#ifdef PRETEND4CPUS
+ rewind(fp);
+ fmt = CPU_FMTS_JUST1;
+#endif
+ if (4 != fscanf(fp, fmt, &u_tics, &n_tics, &s_tics, &i_tics))
+ std_err("Failed /proc/stat read");
+
+ u_frme = TRIMz(u_tics - cpu->u);
s_frme = TRIMz(s_tics - cpu->s);
n_frme = TRIMz(n_tics - cpu->n);
i_frme = TRIMz(i_tics - cpu->i);
/*
* Calc the number of tasks in each state (run, sleep, etc)
* Calc percent cpu usage for each task (pcpu)
- * Calc the cpu(s) percent in each state (user, system, nice, idle) */
+ * Calc the cpu(s) percent in each state (user, system, nice, idle)
+ * AND establish the total number of tasks for this frame! */
static void frame_states (proc_t **p, int show)
{
static HIST_t *hist_sav = NULL;
static unsigned hist_siz;
- static int hist_tot, showsav;
+ static int viewsav;
static CPUS_t *smpcpu;
HIST_t *hist_new;
unsigned total, running, sleeping, stopped, zombie;
int i;
if (!hist_sav) {
- hist_tot = 0;
+ Frame_maxtask = 0;
/* room for 512 HIST_t's (if Page_size == 4k) */
hist_siz = (Page_size / sizeof(HIST_t));
hist_sav = alloc_c(hist_siz);
/* note: we allocate one more CPUS_t than Cpu_tot so that the last
slot can hold tics representing the /proc/stat cpu summary
- (first line read) -- that slot supports Show_cpusum */
+ (first line read) -- that slot supports summary cpu info */
smpcpu = alloc_c((1 + Cpu_tot) * sizeof(CPUS_t));
- showsav = Show_cpusum;
+ viewsav = CHKw(Curwin, View_CPUSUM);
}
-
hist_new = alloc_c(hist_siz);
total = running = sleeping = stopped = zombie = 0;
etime = time_elapsed();
/* make a pass through the data to get stats */
- while (-1 != p[total]->pid) {
+ while (-1 != p[total]->pid) { /* calculations //// */
TICS_t tics;
proc_t *this = p[total];
running++;
break;
}
-
if (total * sizeof(HIST_t) >= hist_siz) {
hist_siz += (Page_size / sizeof(HIST_t));
hist_sav = alloc_r(hist_sav, hist_siz);
hist_new = alloc_r(hist_new, hist_siz);
}
-
/* calculate time in this process; the sum of user time (utime)
- + system time (stime) -- but PLEASE dont waste time and effort
- calculating and saving data that goes unused, like the old top! */
+ + system time (stime) -- but PLEASE dont waste time and effort on
+ calcs and saves that go unused, like the old top! */
hist_new[total].pid = this->pid;
hist_new[total].tics = tics = (this->utime + this->stime);
/* find matching entry from previous pass and make ticks elapsed */
- for (i = 0; i < hist_tot; i++) {
+ for (i = 0; i < Frame_maxtask; i++) {
if (this->pid == hist_sav[i].pid) {
tics -= hist_sav[i].tics;
break;
}
}
-
/* finally calculate an integer version of %cpu for this task
and plug it into the unfilled slot in proc_t */
this->pcpu = (tics * 1000 / Hertz) / etime;
if (this->pcpu > 999) this->pcpu = 999;
-
/* if in Solaris mode, adjust cpu percentage not only for the cpu
the process is running on, but for all cpus together */
- if (!Irix_mode) this->pcpu /= Cpu_tot;
+ if (!Show_irixps) this->pcpu /= Cpu_tot;
total++;
- } /* end: while 'p[total]->pid' */
+ } /* end: while 'pids' */
- if (show) {
- FILE *fp;
- /* whoa, we've changed modes -- gotta' clean old histories */
- if (Show_cpusum != showsav) {
- /* fresh start for the last slot in the history area */
- if (Show_cpusum) memset(&smpcpu[Cpu_tot], '\0', sizeof(CPUS_t));
- /* fresh start for the true smpcpu history area */
- else memset(smpcpu, '\0', Cpu_tot * sizeof(CPUS_t));
- showsav = Show_cpusum;
- }
+ if (show) { /* display ///////// */
+ FILE *fp;
/* display Task states */
show_special(fmtmk(STATES_line1
, total, running, sleeping, stopped, zombie));
+ Msg_row += 1;
+
+ /* clean old histories if we've changed modes */
+ if (CHKw(Curwin, View_CPUSUM) != viewsav) {
+ if (CHKw(Curwin, View_CPUSUM))
+ /* fresh start for the last slot in the history area */
+ memset(&smpcpu[Cpu_tot], '\0', sizeof(CPUS_t));
+ else
+ /* fresh start for the true smpcpu history area */
+ memset(smpcpu, '\0', Cpu_tot * sizeof(CPUS_t));
+ viewsav = CHKw(Curwin, View_CPUSUM);
+ }
- /* now arrange to calculate and display states for all Cpu's */
if (!(fp = fopen("/proc/stat", "r")))
std_err(fmtmk("Failed /proc/stat open: %s", strerror(errno)));
- if (Show_cpusum)
+ if (CHKw(Curwin, View_CPUSUM)) {
/* retrieve and display just the 1st /proc/stat line */
- frame_smp(fp, CPU_FMTS_JUST1, &smpcpu[Cpu_tot], "Cpu(s) state:");
- else {
+ cpudo(fp, CPU_FMTS_JUST1, &smpcpu[Cpu_tot], "Cpu(s) state:");
+ Msg_row += 1;
+ } else {
char tmp[SMLBUFSIZ];
/* skip the 1st line, which reflects total cpu states */
if (!fgets(tmp, sizeof(tmp), fp))
std_err("Failed /proc/stat read");
-#ifdef TRAK_MAXBUFS
- MAXBUFS(frame_states, tmp);
-#endif
/* now do each cpu's states separately */
for (i = 0; i < Cpu_tot; i++) {
sprintf(tmp, "%-6scpu%-2d:" /* [ cpu states as ] */
, i ? " " : "State" /* 'State cpu0 : ... ' */
- , Irix_mode ? i : Cpu_map[i]); /* ' cpu1 : ... ' */
- frame_smp(fp, CPU_FMTS_MULTI, &smpcpu[i], tmp);
+ , Show_irixps ? i : Cpu_map[i]); /* ' cpu1 : ... ' */
+ cpudo(fp, CPU_FMTS_MULTI, &smpcpu[i], tmp);
+ Msg_row += 1;
}
}
+ fclose(fp);
+ } /* end: if 'show' */
+
+ /* save this frame's information */
+ memcpy(hist_sav, hist_new, hist_siz);
+ free(hist_new);
+ /* shout results to the world (and us too, the next time around) */
+ Frame_maxtask = total;
+}
+
+
+#ifdef UGH_ITS_4_RH
+ /*
+ * Obtain memory information and display it.
+ * 'Return' the total memory available as a page count. */
+static void frame_storage (void)
+{ /* don't be mislead by the proc/sysinfo subscripts, they're just poorly
+ chosen names for enum's apparently designed to make source lines as
+ imbalanced and long as possible (not to mention the constant, recurring
+ run-time costs of subscript resolution in the first place - duh?!) */
+ unsigned long long **memarray;
+
+ if (!(memarray = meminfo()))
+ std_err("Failed /proc/meminfo read");
+
+ if (CHKw(Curwin, View_MEMORY)) {
+ show_special(fmtmk(MEMORY_line1
+ , BYTES_2K(memarray[meminfo_main][meminfo_total])
+ , BYTES_2K(memarray[meminfo_main][meminfo_used])
+ , BYTES_2K(memarray[meminfo_main][meminfo_free])
+ , BYTES_2K(memarray[meminfo_main][meminfo_buffers])));
+
+ show_special(fmtmk(MEMORY_line2
+ , BYTES_2K(memarray[meminfo_swap][meminfo_total])
+ , BYTES_2K(memarray[meminfo_swap][meminfo_used])
+ , BYTES_2K(memarray[meminfo_swap][meminfo_free])
+ , BYTES_2K(memarray[meminfo_total][meminfo_cached])));
+ Msg_row += 2;
+ }
+
+ Mem_pages = PAGE_CNT(memarray[meminfo_main][meminfo_total]);
+}
+
+#else
+
+ /*
+ * Obtain memory information and display it. */
+static void frame_storage (void)
+{
+ meminfo();
+ if (CHKw(Curwin, View_MEMORY)) {
+ show_special(fmtmk(MEMORY_line1
+ , kb_main_total, kb_main_used, kb_main_free, kb_main_buffers));
+ show_special(fmtmk(MEMORY_line2
+ , kb_swap_total, kb_swap_used, kb_swap_free, kb_main_cached));
+ Msg_row += 2;
+ }
+}
+#endif /* end: UGH_ITS_4_RH */
+
+
+ /*
+ * Task display *Helper* function to handle highlighted
+ * column transitions. */
+static void mkcol (WIN_t *q, unsigned idx, int sta, int *pad, char *buf, ...)
+{
+ char tmp[COLBUFSIZ];
+ va_list va;
+
+ va_start(va, buf);
+ if (!CHKw(q, Show_HICOLS) || q->sorttype != Fieldstab[idx].sort) {
+ vsprintf(buf, Fieldstab[idx].fmts, va);
+ } else {
+ vsprintf(tmp, Fieldstab[idx].fmts, va);
+ sprintf(buf, "%s%s", q->capclr_rowhigh, tmp);
+ *pad += q->len_rowhigh;
+ if (!CHKw(q, Show_HIROWS) || 'R' != sta) {
+ strcat(buf, q->capclr_rownorm);
+ *pad += q->len_rownorm;
+ }
+ }
+ va_end(va);
+}
+
+
+ /*
+ * Display information for a single task row. */
+static void show_a_task (WIN_t *q, proc_t *task)
+{
+ /* the following macro is used for those columns that are NOT sortable
+ so as to avoid the function call overhead since mkcol cannot be made
+ inline -- if additional sort columns are added, change the appropriate
+ switch label's usage to lower case and thus invoke the real function */
+#define MKCOL(q,idx,sta,pad,buf,arg) \
+ sprintf(buf, Fieldstab[idx].fmts, arg)
+ char rbuf[ROWBUFSIZ];
+ int i, x, pad;
+
+ /* since win_colsheads adds a number to the window's column header,
+ we must begin a row with that in mind... */
+ pad = Show_altscr;
+ if (pad) strcpy(rbuf, " "); else rbuf[0] = '\0';
+
+ for (i = 0; i < q->maxpflgs; i++) {
+ char cbuf[COLBUFSIZ];
+ unsigned f, s, w;
+
+ cbuf[0] = '\0';
+ f = q->procflags[i];
+ s = Fieldstab[f].scale;
+ w = Fieldstab[f].width;
+
+ switch (f) {
+ case P_CMD:
+ { char *cmdptr, cmdnam[ROWBUFSIZ];
+
+ if (!CHKw(q, Show_CMDLIN))
+ cmdptr = task->cmd;
+ else {
+ cmdnam[0] = '\0';
+ if (task->cmdline) {
+ x = 0;
+ do {
+ /* during a kernel build, parts of the make will create
+ cmdlines in excess of 3000 bytes but *without* the
+ intervening nulls -- so we must limit our strcat... */
+ strcat(cmdnam
+ , fmtmk("%.*s ", q->maxcmdln, task->cmdline[x++]));
+ /* whoa, gnome's xscreensaver had a ^I in his cmdline
+ creating a line wrap when the window was maximized &
+ the tab came into view -- so whack those suckers... */
+ strim(1, cmdnam);
+ if (q->maxcmdln < (int)strlen(cmdnam)) break;
+ } while (task->cmdline[x]);
+ } else {
+ /* if cmdline is absent, consider it a kernel thread and
+ display it uniquely (we'll need sort_cmd's complicity) */
+ strcpy(cmdnam, fmtmk("( %s )", task->cmd));
+ }
+ cmdptr = cmdnam;
+ }
+ mkcol(q, f, task->state, &pad
+ , cbuf, q->maxcmdln, q->maxcmdln, cmdptr);
+ }
+ break;
+ case P_CODE:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num(PAGES_2K(task->trs), w, s));
+ break;
+ case P_CPU:
+ mkcol(q, f, task->state, &pad, cbuf, (float)task->pcpu / 10);
+ break;
+ case P_DATA:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num(PAGES_2K(task->drs), w, s));
+ break;
+ case P_DIRTY:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num((unsigned)task->dt, w, s));
+ break;
+ case P_FAULT:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num(task->maj_flt, w, s));
+ break;
+ case P_FLAGS:
+ MKCOL(q, f, task->state, &pad, cbuf, task->flags);
+ for (x = 0; x < (int)strlen(cbuf); x++)
+ if ('0' == cbuf[x]) cbuf[x] = '.';
+ break;
+ case P_GROUP:
+ MKCOL(q, f, task->state, &pad, cbuf, task->egroup);
+ break;
+ case P_MEM:
+ mkcol(q, f, task->state, &pad, cbuf
+#ifdef UGH_ITS_4_RH
+ , (float)task->resident * 100 / Mem_pages);
+#else
+ , (float)PAGES_2K(task->resident) * 100 / kb_main_total);
+#endif
+ break;
+ case P_NCPU:
+#ifdef UGH_ITS_4_RH
+ MKCOL(q, f, task->state, &pad, cbuf, task->lproc);
+#else
+ MKCOL(q, f, task->state, &pad, cbuf, task->processor);
+#endif
+ break;
+ case P_NI:
+ MKCOL(q, f, task->state, &pad, cbuf, task->nice);
+ break;
+ case P_PID:
+ mkcol(q, f, task->state, &pad, cbuf, task->pid);
+ break;
+ case P_PPID:
+ MKCOL(q, f, task->state, &pad, cbuf, task->ppid);
+ break;
+ case P_PR:
+ MKCOL(q, f, task->state, &pad, cbuf, task->priority);
+ break;
+ case P_RES:
+ mkcol(q, f, task->state, &pad, cbuf
+ , scale_num(PAGES_2K(task->resident), w, s));
+ break;
+ case P_SHR:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num(PAGES_2K(task->share), w, s));
+ break;
+ case P_STA:
+#ifdef USE_LIB_STA3
+ MKCOL(q, f, task->state, &pad, cbuf, status(task));
+#else
+ MKCOL(q, f, task->state, &pad, cbuf, task->state);
+#endif
+ break;
+ case P_SWAP:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num(PAGES_2K(task->size - task->resident), w, s));
+ break;
+ case P_TIME:
+ case P_TIME2:
+ { TICS_t t;
+
+ t = task->utime + task->stime;
+ if (CHKw(q, Show_CTIMES))
+ t += (task->cutime + task->cstime);
+ mkcol(q, f, task->state, &pad, cbuf, scale_tics(t, w));
+ }
+ break;
+ case P_TTY:
+ { char tmp[TNYBUFSIZ];
+
+ dev_to_tty(tmp, (int)w, task->tty, task->pid, ABBREV_DEV);
+ mkcol(q, f, task->state, &pad, cbuf, tmp);
+ }
+ break;
+ case P_UID:
+ MKCOL(q, f, task->state, &pad, cbuf, task->euid);
+ break;
+ case P_USER:
+ mkcol(q, f, task->state, &pad, cbuf, task->euser);
+ break;
+ case P_VIRT:
+ MKCOL(q, f, task->state, &pad, cbuf
+ , scale_num(PAGES_2K(task->size), w, s));
+ break;
+ case P_WCHAN:
+ if (No_ksyms)
+#ifdef CASEUP_HEXES
+ MKCOL(q, f, task->state, &pad, cbuf
+ , fmtmk("x%08lX", (long)task->wchan));
+#else
+ MKCOL(q, f, task->state, &pad, cbuf
+ , fmtmk("x%08lx", (long)task->wchan));
+#endif
+ else
+ MKCOL(q, f, task->state, &pad, cbuf, wchan(task->wchan));
+ break;
+
+ } /* end: switch 'flg' */
+
+ strcat(rbuf, cbuf);
+ } /* end: for 'maxpflgs' */
+
+ /* This row buffer could be stuffed with parameterized strings.
+ We are thus advised to always use tputs/putp, but it works just
+ fine with good ol' printf... */
+ printf("\n%s%.*s%s%s", (CHKw(q, Show_HIROWS) && 'R' == task->state)
+ ? q->capclr_rowhigh : q->capclr_rownorm
+ , Screen_cols + pad
+ , rbuf
+ , Caps_off
+ , Cap_clr_eol);
+
+#undef MKCOL
+}
+
+\f
+/*###### Main Screen routines ##########################################*/
+
+ /*
+ * Process keyboard input during the main loop */
+static void do_key (unsigned c)
+{
+#ifndef QUIT_NORMALQ
+#define kbdESCAPE 27
+#endif
+#define kbdCTRL_L 12
+ /* standardized 'secure mode' errors */
+ const char *err_secure = "\aCan't %s in secure mode";
+ /* standardized 'smp' errors */
+#ifdef WARN_NOT_SMP
+ const char *err_smp = "\aSorry, only 1 cpu detected";
+#endif
+
+ switch (c) {
+ /* begin windows grouping /////////////////////////// */
+ case '-': /* 'Dash' lower case ----------------------- */
+ if (Show_altscr)
+ TOGw(Curwin, VISIBLE_tsk);
+ break;
+
+ case '_': /* 'Dash' upper case ----------------------- */
+ if (Show_altscr) /* switcharoo, all viz & inviz ............. */
+ wins_reflag(Flgs_TOG, VISIBLE_tsk);
+ break;
+
+ case '=': /* 'Equals' lower case --------------------- */
+ if (Show_altscr) { /* equalize task display ................... */
+ Curwin->maxtasks = 0;
+ SETw(Curwin, Show_IDLEPS | VISIBLE_tsk);
+ }
+ break;
+
+ case '+': /* 'Equals' upper case --------------------- */
+ /* Special New Provision:
+ . escape from monitoring selected pids ('-p' cmdline switch)
+ -- just seems to go naturally with this new '+' command key
+ . and who knows, maybe the documentation will NOT be overlooked */
+ Monpidsidx = 0;
+ if (Show_altscr) /* equalize ALL task windows (& make viz) .. */
+ SETw(Curwin, EQUWINS_cwo);
+ break;
+
+ case 'A':
+ Show_altscr = !Show_altscr;
+ wins_resize(0);
+ break;
+
+ case 'a':
+ if (Show_altscr) Curwin = Curwin->next;
+ break;
+
+ case 'F':
+ case 'O':
+ win_select(0); /* we won't restrict this one, ok? ......... */
+ break;
+
+ case 'g':
+ if (Show_altscr) {
+ char tmp[GETBUFSIZ];
+ strcpy(tmp, ask4str(fmtmk("Rename window '%s' to (0-3 chars)"
+ , Curwin->winname)));
+ if (tmp[0]) win_names(Curwin, tmp);
+ }
+ break;
+
+ case 'w':
+ if (Show_altscr) Curwin = Curwin->prev;
+ break;
+ /* end windows grouping ///////////////////////////// */
+ case 'b':
+ if (VIZCHKc) {
+ if (!CHKw(Curwin, Show_HICOLS) && !CHKw(Curwin, Show_HIROWS))
+ show_msg("\aNothing to highlight!");
+ else {
+ TOGw(Curwin, Show_HIBOLD);
+ capsmk(Curwin);
+ }
+ }
+ break;
+
+ case 'c':
+ VIZTOGc(Show_CMDLIN);
+ break;
+
+ case 'f':
+ if (VIZCHKc) {
+ fields_toggle();
+ win_colsheads(Curwin);
+ }
+ break;
+
+ case 'i':
+ VIZTOGc(Show_IDLEPS);
+ break;
+
+ case 'I':
+#ifdef WARN_NOT_SMP
+ if (Cpu_tot > 1) {
+ Show_irixps = !Show_irixps;
+ show_msg(fmtmk("Irix mode %s", Show_irixps ? "On" : "Off"));
+ } else
+ show_msg(err_smp);
+#else
+ Show_irixps = !Show_irixps;
+ show_msg(fmtmk("Irix mode %s", Show_irixps ? "On" : "Off"));
+#endif
+ break;
+
+ case 'k':
+ if (Secure_mode) {
+ show_msg(fmtmk(err_secure, "kill"));
+ } else {
+ int sig, pid = get_int("PID to kill");
+
+ if (-1 != pid) {
+#ifdef UGH_ITS_4_RH
+ sig = get_signal2(
+#else
+ sig = signal_name_to_number(
+#endif
+ ask4str(fmtmk("Kill PID %d with signal [%i]"
+ , pid, DEF_SIGNAL)));
+ if (-1 == sig) sig = DEF_SIGNAL;
+ if (sig && kill(pid, sig))
+ show_msg(fmtmk("\aKill of PID '%d' with '%d' failed: %s"
+ , pid, sig, strerror(errno)));
+ }
+ }
+ break;
+
+ case 'l':
+ TOGw(Curwin, View_LOADAV);
+ break;
+
+ case 'm':
+ TOGw(Curwin, View_MEMORY);
+ break;
+
+ case 'n':
+ case '#':
+ if (VIZCHKc) {
+ int num;
+ if (-1 < (num = get_int(
+ fmtmk("Maximum tasks = %d, change to (0 is unlimited)"
+ , Curwin->maxtasks))))
+ Curwin->maxtasks = num;
+ }
+ break;
+
+ case 'o':
+ if (VIZCHKc) {
+ fields_reorder();
+ win_colsheads(Curwin);
+ }
+ break;
+
+ case 'r':
+ if (Secure_mode)
+ show_msg(fmtmk(err_secure, "renice"));
+ else {
+ int pid, val;
+
+ pid = get_int("PID to renice");
+ if (-1 == pid) break;
+ val = get_int(fmtmk("Renice PID %d to value", pid));
+ if (setpriority(PRIO_PROCESS, (unsigned)pid, val))
+ show_msg(fmtmk("\aRenice of PID %d to %d failed: %s"
+ , pid, val, strerror(errno)));
+ }
+ break;
+
+ case 'R':
+ VIZTOGc(Qsrt_NORMAL);
+ break;
+
+ case 's':
+ case 'd':
+ if (Secure_mode)
+ show_msg(fmtmk(err_secure, "change delay"));
+ else {
+ float tmp =
+ get_float(fmtmk("Change delay from %.1f to", Delay_time));
+ if (tmp > -1) Delay_time = tmp;
+ }
+ break;
- fclose(fp);
- } /* end: if 'show' */
+ case 'S':
+ if (VIZCHKc) {
+ TOGw(Curwin, Show_CTIMES);
+ show_msg(fmtmk("Cumulative time %s"
+ , CHKw(Curwin, Show_CTIMES) ? "On" : "Off"));
+ }
+ break;
- /* save this frame's information */
- hist_tot = total;
- memcpy(hist_sav, hist_new, hist_siz);
- free(hist_new);
- /* finally, sort the processes on whatever... */
- qsort(p, total, sizeof(proc_t *), (QSORT_t)Sort_func);
-}
+ case 't':
+ TOGw(Curwin, View_STATES);
+ break;
+ case 'u':
+ if (VIZCHKc)
+ strcpy(Curwin->colusrnam, ask4str("Which user (blank for all)"));
+ break;
- /*
- * Task display *Helper* function to handle highlighted
- * column transitions. */
-static void mkcol (unsigned idx, int sta, int *pad, char *buf, ...)
-{
- char tmp[COLBUFSIZ];
- va_list va;
+ case 'W':
+ { FILE *fp = fopen(RCfile, "w"); int i;
- va_start(va, buf);
- if (!Show_hicols || Sort_type != Fieldstab[idx].sort) {
- vsprintf(buf, Fieldstab[idx].fmts, va);
- } else {
- vsprintf(tmp, Fieldstab[idx].fmts, va);
- sprintf(buf, "%s%s", Row_color_high, tmp);
- *pad += Len_row_high;
- if (!Show_hirows || 'R' != sta) {
- strcat(buf, Row_color_norm);
- *pad += Len_row_norm;
+ if (fp) {
+ fprintf(fp, "RCfile for \"%s with windows\"\t\t# shameless braggin'\n"
+ , Myname);
+ fprintf(fp, "Id:%c, "
+ "Show_altscr=%d, Show_irixps=%d, Delay_time=%.1f, Curwin=%d\n"
+ , RCF_FILEID
+ , Show_altscr, Show_irixps, Delay_time, Curwin - Winstk[0]);
+ for (i = 0; i < GROUPSMAX; i++) {
+ fprintf(fp, "%s\tfieldscur=%s\n"
+ , Winstk[i]->winname, Winstk[i]->fieldscur);
+ fprintf(fp, "\twinflags=%d, sorttype=%c, maxtasks=%d\n"
+ , Winstk[i]->winflags
+ , Winstk[i]->sorttype
+ , Winstk[i]->maxtasks);
+ fprintf(fp, "\tsummclr=%d, msgsclr=%d, headclr=%d, taskclr=%d\n"
+ , Winstk[i]->summclr
+ , Winstk[i]->msgsclr
+ , Winstk[i]->headclr
+ , Winstk[i]->taskclr);
+ }
+ fclose(fp);
+ show_msg(fmtmk("Wrote configuration to '%s'", RCfile));
+ } else
+ show_msg(fmtmk("\aFailed '%s' open: %s", RCfile, strerror(errno)));
}
- }
- va_end(va);
-#ifdef TRAK_MAXBUFS
- MAXBUFS(mkcol, tmp);
-#endif
-}
-
+ break;
- /*
- * Displays information for a single task. */
-#ifdef UGH_ITS_4_RH
-static void show_a_task (proc_t *task, unsigned mempgs)
-#else
-static void show_a_task (proc_t *task)
-#endif
-{
- /* the following macro is used for those columns that are NOT sortable
- so as to avoid the function call overhead since mkcol cannot be made
- inline -- if additional sort columns are added, change the appropriate
- switch label's usage to lower case and thus invoke the real function */
-#define MKCOL(idx,sta,pad,buf,arg) \
- sprintf(buf, Fieldstab[idx].fmts, arg)
- char rbuf[ROWBUFSIZ];
- int i, x, pad;
+ case 'x':
+ if (VIZCHKc) {
+ TOGw(Curwin, Show_HICOLS);
+ capsmk(Curwin);
+ }
+ break;
- pad = 0;
- rbuf[0] = '\0';
+ case 'y':
+ if (VIZCHKc) {
+ TOGw(Curwin, Show_HIROWS);
+ capsmk(Curwin);
+ }
+ break;
- for (i = 0; i < NumFields; i++) {
- char cbuf[COLBUFSIZ];
- unsigned f, s, w;
+ case 'z':
+ if (VIZCHKc) {
+ TOGw(Curwin, Show_COLORS);
+ capsmk(Curwin);
+ }
+ break;
- cbuf[0] = '\0';
- f = PFlags[i];
- s = Fieldstab[f].scale;
- w = Fieldstab[f].width;
+ case 'Z':
+ wins_colors();
+ break;
- switch (f) {
- case P_CMD:
- { char *cmdptr, cmdnam[ROWBUFSIZ];
+ case '?':
+ case 'h':
+ { char ch;
- if (Show_cmdlin) {
- cmdnam[0] = '\0';
- if (task->cmdline) {
- x = 0;
- do {
- /* whoa, during a kernel build, parts of the make
- process will create cmdlines in excess of 3000 bytes
- but *without* the typical intervening nulls */
- strcat(cmdnam
- , fmtmk("%.*s ", Max_cmd, task->cmdline[x++]));
- /* whoa, gnome's xscreensaver had a ^I in his cmdline
- creating a line wrap when the window was maximized &
- the tab came into view -- that in turn, whacked
- our heading lines so we'll strim those !#@*#!... */
- strim(1, cmdnam);
- /* enough, don't ya think? */
- if (Max_cmd < (int)strlen(cmdnam))
- break;
- } while (task->cmdline[x]);
- } else {
- /* if this process really doesn't have a cmdline, we'll
- consider it a kernel thread and display it uniquely
- [ we need sort_cmd's complicity in this plot ] */
- strcpy(cmdnam, fmtmk("( %s )", task->cmd));
- }
- cmdptr = cmdnam;
- } else
- cmdptr = task->cmd;
- /* hurry up, before cmdptr goes out of scope... */
- mkcol(f, task->state, &pad, cbuf, Max_cmd, Max_cmd, cmdptr);
+ printf("%s%s", Cap_clr_scr, Cap_curs_huge);
+ /* this string is well above ISO C89's minimum requirements! */
+ show_special(fmtmk(KEYS_help
+ , Myname, procps_version
+ , Curwin->winname
+ , CHKw(Curwin, Show_CTIMES) ? "On" : "Off"
+ , Delay_time
+ , Secure_mode ? "On" : "Off"
+ , Secure_mode ? "" : KEYS_help_unsecured));
+ chin(0, &ch, 1);
+ if ('?' == ch || 'h' == ch) {
+ do {
+ putp(Cap_clr_scr);
+ show_special(fmtmk(WINDOWS_help
+ , Myname, Curwin->grpname
+ , Winstk[Def_WINDOW]->winname
+ , Winstk[Job_WINDOW]->winname
+ , Winstk[Mem_WINDOW]->winname
+ , Winstk[Usr_WINDOW]->winname));
+ chin(0, &ch, 1);
+ win_select(ch);
+ } while ('\n' != ch);
}
- break;
- case P_CODE:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num(PAGES_2K(task->trs), w, s));
- break;
- case P_CPU:
- mkcol(f, task->state, &pad, cbuf, (float)task->pcpu / 10);
- break;
- case P_DATA:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num(PAGES_2K(task->drs), w, s));
- break;
- case P_DIRTY:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num((unsigned)task->dt, w, s));
- break;
- case P_FAULT:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num(task->maj_flt, w, s));
- break;
- case P_FLAGS:
- MKCOL(f, task->state, &pad, cbuf, task->flags);
- for (x = 0; x < (int)strlen(cbuf); x++)
- if ('0' == cbuf[x]) cbuf[x] = '.';
- break;
- case P_GROUP:
- MKCOL(f, task->state, &pad, cbuf, task->egroup);
- break;
- case P_MEM:
- mkcol(f, task->state, &pad, cbuf
-#ifdef UGH_ITS_4_RH
- , (float)task->resident * 100 / mempgs);
-#else
- , (float)PAGES_2K(task->resident) * 100 / kb_main_total);
-#endif
- break;
- case P_NCPU:
-#ifdef UGH_ITS_4_RH
- MKCOL(f, task->state, &pad, cbuf, task->lproc);
-#else
- MKCOL(f, task->state, &pad, cbuf, task->processor);
-#endif
- break;
- case P_NI:
- MKCOL(f, task->state, &pad, cbuf, task->nice);
- break;
- case P_PID:
- mkcol(f, task->state, &pad, cbuf, task->pid);
- break;
- case P_PPID:
- MKCOL(f, task->state, &pad, cbuf, task->ppid);
- break;
- case P_PR:
- MKCOL(f, task->state, &pad, cbuf, task->priority);
- break;
- case P_RES:
- /* 'rss' vs 'resident' (which includes IO memory) ?
- -- we'll ensure that VIRT = SWAP + RES */
- mkcol(f, task->state, &pad, cbuf
- , scale_num(PAGES_2K(task->resident), w, s));
- break;
- case P_SHR:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num(PAGES_2K(task->share), w, s));
- break;
- case P_STA:
- MKCOL(f, task->state, &pad, cbuf, status(task));
- break;
- case P_SWAP:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num(PAGES_2K(task->size - task->resident), w, s));
- break;
- case P_TIME:
- case P_TIME2:
- { TICS_t t;
+ putp(Cap_curs_norm);
+ }
+ break;
- t = task->utime + task->stime;
- if (Show_ctimes)
- t += (task->cutime + task->cstime);
- mkcol(f, task->state, &pad, cbuf, scale_tics(t, w));
- }
- break;
- case P_TTY:
- { char tmp[TNYBUFSIZ];
+ case ' ':
+ case kbdCTRL_L:
+ putp(Cap_clr_scr);
+ break;
- dev_to_tty(tmp, Fieldstab[f].width
- , task->tty, task->pid, ABBREV_DEV);
- mkcol(f, task->state, &pad, cbuf, tmp);
- }
- break;
- case P_UID:
- MKCOL(f, task->state, &pad, cbuf, task->euid);
- break;
- case P_USER:
- mkcol(f, task->state, &pad, cbuf, task->euser);
- break;
- case P_VIRT:
- MKCOL(f, task->state, &pad, cbuf
- , scale_num(PAGES_2K(task->size), w, s));
- break;
- case P_WCHAN:
- if (No_ksyms)
-#ifdef UPCASE_HEXES
- MKCOL(f, task->state, &pad, cbuf
- , fmtmk("x%08lX", (long)task->wchan));
+ case '1':
+#ifdef WARN_NOT_SMP
+ if (Cpu_tot > 1)
+ TOGw(Curwin, View_CPUSUM);
+ else
+ show_msg(err_smp);
#else
- MKCOL(f, task->state, &pad, cbuf
- , fmtmk("x%08lx", (long)task->wchan));
+ TOGw(Curwin, View_CPUSUM);
#endif
- else
- MKCOL(f, task->state, &pad, cbuf, wchan(task->wchan));
- break;
+ break;
- } /* end: switch 'PFlags[i]' */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(show_a_task, cbuf);
-#endif
- strcat(rbuf, cbuf);
+ case S_CMD: case S_CPU: case S_MEM:
+ case S_PID: case S_TME: case S_TTY: case S_USR:
+ if (VIZCHKc)
+ win_sortset(Curwin, (int)c);
+ break;
+
+ case '\n': /* just ignore it */
+ break;
- } /* end: for 'NumFields' */
-#ifdef TRAK_MAXBUFS
- MAXBUFS(show_a_task, rbuf);
+#ifdef QUIT_NORMALQ
+ case 'q':
+#else
+ case kbdESCAPE:
#endif
+ stop(0);
- /* This row buffer could be stuffed with parameterized strings.
- We are thus advised to always use tputs/putp, but it works just
- fine with good ol' printf... */
- printf("\n%s%.*s%s%s"
- , (Show_hirows && 'R' == task->state) ? Row_color_high : Row_color_norm
- , Screen_cols + pad
- , rbuf
- , Caps_off
- , Cap_clr_eol);
+ default:
+ show_msg("\aUnknown command - try 'h' for help");
+ }
-#ifdef TRAK_MAXCAPS
- if (pad > Max_pads) Max_pads = pad;
- if (pad < Min_pads) Min_pads = pad;
- /* now that we have TRAK_MAXBUFS, the next two duplicate some effort */
- if ((int)strlen(rbuf) > Max_rbuf) Max_rbuf = (int)strlen(rbuf);
- if ((int)strlen(rbuf) < Min_rbuf) Min_rbuf = (int)strlen(rbuf);
+#ifndef QUIT_NORMALQ
+#undef kbdESCAPE
#endif
-
-#undef MKCOL
+#undef kbdCTRL_L
}
/*
- * Read all process info and display it. */
-static void show_everything (void)
+ * Begin a new frame by:
+ * 1) Refreshing the all important proc table
+ * 2) Displaying uptime and load average (maybe)
+ * 3) Arranging for task/cpu states to be displayed
+ * 4) Arranging for memory & swap usage to be displayed
+ * and then, returning a pointer to the pointers to the proc_t's! */
+static proc_t **do_summary (void)
{
static proc_t **p_table = NULL;
- int ntask, nline;
-#ifdef UGH_ITS_4_RH
- unsigned mempgs;
-#endif
if (!p_table) {
- p_table = readprocs(p_table);
+ /* whoa first time, gotta' prime the pump... */
+ p_table = refreshprocs(NULL);
frame_states(p_table, 0);
+ putp(Cap_clr_scr);
sleep(1);
} else
- putp(Batch ? "\n" : Cap_home);
+ putp(Batch ? "\n\n" : Cap_home);
- /*
- ** Display Load averages */
- if (HSum_loadav)
- show_special(fmtmk(LOADAV_line, Myname, sprint_uptime()));
- /*
- ** Display System stats (also calc 'pcpu' and sort p_table) */
- p_table = readprocs(p_table);
- frame_states(p_table, HSum_states);
+ /*
+ ** Display Load averages */
+ if (CHKw(Curwin, View_LOADAV)) {
+ if (!Show_altscr)
+ show_special(fmtmk(LOADAV_line, Myname, sprint_uptime()));
+ else
+ show_special(fmtmk(CHKw(Curwin, VISIBLE_tsk)
+ ? LOADAV_line_alt
+ : LOADAV_line
+ , Curwin->grpname, sprint_uptime()));
+ Msg_row += 1;
+ }
- /*
- ** Display Memory and Swap space usage */
-#ifdef UGH_ITS_4_RH
- mempgs = frame_memory();
-#else
- frame_memory();
-#endif
+ /*
+ ** Display Tasks and Cpu(s) states and also calc 'pcpu',
+ ** but NO p_table sort yet -- that's done on a per window basis! */
+ p_table = refreshprocs(p_table);
+ frame_states(p_table, CHKw(Curwin, View_STATES));
+
+ /*
+ ** Display Memory and Swap space usage */
+ frame_storage();
+
+ SETw(Curwin, NEWFRAM_cwo);
+ return p_table;
+}
- /*
- ** Display Headings for columns */
- printf("%s%s%s%s%s"
- , tg2(0, MSG_line + 1)
- , Hdr_color
- , ColHeadings
- , Caps_off
- , Cap_clr_eol);
- /* Finally! Loop through to find each task, and display it ...
- ... lather, rinse, repeat */
- ntask = nline = 0;
- while (-1 != p_table[ntask]->pid && nline < Max_lines) {
- if ((Show_idleps
- || ('S' != p_table[ntask]->state && 'Z' != p_table[ntask]->state))
- && ((!ColUsername[0])
- || (!strcmp(ColUsername, p_table[ntask]->euser)) ) ) {
/*
- ** Display a process Row */
-#ifdef UGH_ITS_4_RH
- show_a_task(p_table[ntask], mempgs);
-#else
- show_a_task(p_table[ntask]);
+ * Squeeze as many tasks as we can into a single window,
+ * after sorting the passed proc table. */
+static void do_window (proc_t **ppt, WIN_t *q, int *lscr)
+{
+#ifdef SORT_SUPRESS
+ /* the 1 flag that DOES and 2 flags that MAY impact our proc table qsort */
+#define srtMASK ~( Qsrt_NORMAL | Show_CMDLIN | Show_CTIMES )
+ static QSORT_t sav_func = NULL;
+ static int sav_flgs = -1;
+#endif
+ int i, lwin;
+
+ /*
+ ** Display Column Headings -- and distract 'em while we sort (maybe) */
+ printf("\n%s%s%s%s", q->capclr_hdr, q->columnhdr, Caps_off, Cap_clr_eol);
+
+#ifdef SORT_SUPRESS
+ if (CHKw(Curwin, NEWFRAM_cwo)
+ || sav_func != q->sortfunc
+ || sav_flgs != (q->winflags & srtMASK)) {
+ sav_flgs = (q->winflags & srtMASK);
+ sav_func = q->sortfunc;
#endif
- if (!Batch) ++nline;
+ Frame_srtflg = CHKw(q, Qsrt_NORMAL); /* this one's always needed! */
+ Frame_ctimes = CHKw(q, Show_CTIMES); /* this and next, only maybe */
+ Frame_cmdlin = CHKw(q, Show_CMDLIN);
+ qsort(ppt, (unsigned)Frame_maxtask, sizeof(proc_t *), (QSORT_t)q->sortfunc);
+#ifdef SORT_SUPRESS
+ }
+#endif
+ /* account for column headings */
+ if (!Batch) (*lscr)++;
+ lwin = 1;
+ i = 0;
+
+ while ( -1 != ppt[i]->pid && *lscr < Max_lines
+ && (!q->winlines || (lwin <= q->winlines)) ) {
+ if ((CHKw(q, Show_IDLEPS)
+ || ('S' != ppt[i]->state && 'Z' != ppt[i]->state))
+ && ((!q->colusrnam[0])
+ || (!strcmp(q->colusrnam, ppt[i]->euser)) ) ) {
+ /*
+ ** Display a process Row */
+ show_a_task(q, ppt[i]);
+ if (!Batch) (*lscr)++;
+ ++lwin;
}
- ++ntask;
+ ++i;
}
+ /* for this frame that window's toast, cleanup for next time */
+ q->winlines = 0;
+ OFFw(Curwin, FLGSOFF_cwo);
- printf("%s%s%s", Cap_clr_eos, tg2(0, MSG_line), Cap_clr_eol);
- fflush(stdout);
+#ifdef SORT_SUPRESS
+#undef srtMASK
+#endif
}
-\f
-/*###### Entry point ###################################################*/
-int main (int dont_care_argc, char **argv)
+ /*
+ * This guy's just a *Helper* function who apportions the
+ * remaining amount of screen real estate under multiple windows
+ * -- i swear that's the whole truth, so-help-me ! */
+static void sohelpme (int wix, int max)
{
- char not_really_tmp[OURPATHSZ];
- int i;
+ WIN_t *w;
+ int i, rsvd, size, wins;
+
+ /* calc remaining number of visible windows + total 'user' lines */
+ for (i = wix, rsvd = 0, wins = 0; i < GROUPSMAX; i++) {
+ if (CHKw(Winstk[i], VISIBLE_tsk)) {
+ rsvd += Winstk[i]->maxtasks;
+ ++wins;
+ if (max <= rsvd) break;
+ }
+ }
+ if (!wins) wins = 1;
+ /* set aside 'rsvd' & deduct 1 line/window for the columns heading */
+ size = (max - wins) - rsvd;
+ if (0 <= size) size = max;
+ size = (max - wins) / wins;
+
+ /* for remaining windows, set do_window's winlines to either the
+ user's maxtask (1st choice) or our 'foxized' size calculation
+ (foxized adj. - 'fair and balanced') */
+ for (i = wix ; i < GROUPSMAX; i++) {
+ if (CHKw(Winstk[i], VISIBLE_tsk)) {
+ Winstk[i]->winlines =
+ Winstk[i]->maxtasks ? Winstk[i]->maxtasks : size;
+ w = Winstk[i];
+ }
+ }
+ /* award any remaining lines to the screen's last visible window
+ (for the best/most stable display) */
+ w->winlines += (max - wins) % wins;
+}
- /* setup our program name(s)... */
- Myname = strrchr(argv[0], '/');
- if (Myname) ++Myname; else Myname = argv[0];
- Myrealname = Myname;
- memset(not_really_tmp, '\0', sizeof(not_really_tmp));
- /* proper permissions should deny symlinks to /usr/bin for ordinary
- users, but root may have employed them -- Myrealname will be used
- in constructing the global rc filename ... */
- if (-1 != readlink(argv[0], not_really_tmp, sizeof(not_really_tmp) - 1)) {
- Myrealname = strrchr(not_really_tmp, '/');
- if (Myrealname) ++Myrealname; else Myrealname = not_really_tmp;
-#ifdef TRAK_MAXBUFS
- MAXBUFS(main, not_really_tmp);
-#endif
+
+ /*
+ * Initiate the Frame Display Update cycle at someone's whim!
+ * This routine doesn't do much, mostly he just calls others.
+ *
+ * (Whoa, wait a minute, we DO caretake that Msg_row guy and)
+ * (we CALCULATE that IMPORTANT Max_lines thingy so that the)
+ * (*subordinate* functions invoked know WHEN the user's had)
+ * (ENOUGH already. And at Frame End, it SHOULD be apparent)
+ * (WE am d'MAN -- clearing UNUSED screen LINES and ensuring)
+ * (the CURSOR is STUCK in just the RIGHT place, know what I)
+ * (mean? Huh, "doesn't DO MUCH"! Never, EVER think or say)
+ * (THAT about THIS function again, Ok? Good that's better.)
+ *
+ * (ps. we ARE the UNEQUALED justification KING of COMMENTS!)
+ * (No, I don't mean significance/relevance, only alignment.)
+ *
+ * (What's that? Are you sure? Old main's REALLY GOOD too?)
+ * (You say he even JUSTIFIES comments in his FUNCTION BODY?)
+ * (Jeeze, how COULD I have known? That sob's NOT IN SCOPE!)
+ */
+static void so_lets_see_em (void)
+{
+ proc_t **ppt;
+ int i, scrlins;
+
+ Msg_row = scrlins = 0;
+ ppt = do_summary();
+ Max_lines = (Screen_rows - Msg_row) - 1;
+
+ if (CHKw(Curwin, EQUWINS_cwo))
+ wins_reflag(Flgs_OFF, EQUWINS_cwo);
+ /* sure hope each window's columns header begins with a newline... */
+ putp(tg2(0, Msg_row));
+
+ if (!Show_altscr) {
+ /* only 1 window to show so, piece o' cake */
+ Curwin->winlines = Curwin->maxtasks;
+ do_window(ppt, Curwin, &scrlins);
+ } else {
+ /* maybe NO window is visible but assume, pieces o' cakes */
+ for (i = 0 ; i < GROUPSMAX; i++) {
+ if (CHKw(Winstk[i], VISIBLE_tsk)) {
+ sohelpme(i, Max_lines - scrlins);
+ do_window(ppt, Winstk[i], &scrlins);
+ }
+ if (Max_lines <= scrlins) break;
+ }
}
+ /* clear to end-of-screen (critical if last window is 'idleps off'),
+ then put the cursor in-its-place, and rid us of any prior frame's msg
+ (main loop must iterate such that we're always called before sleep) */
+ printf("%s%s%s", Cap_clr_eos, tg2(0, Msg_row), Cap_clr_eol);
+ fflush(stdout);
+}
- /* setup some important system stuff... */
- Page_size = getpagesize();
- Cpu_tot = sysconf(_SC_NPROCESSORS_ONLN);
- if (1 > Cpu_tot) Cpu_tot = 1;
- Cpu_map = alloc_r(NULL, sizeof(int) * Cpu_tot);
- for (i = 0; i < Cpu_tot; i++)
- Cpu_map[i] = i;
- rcfiles_read();
- parse_argvs(argv);
- terminal_set();
- window_resize(0);
+/*###### Entry point ###################################################*/
- /* set up signal handlers */
+ /*
+ * Darling, you DO look simply MARVELOUS -- have you been dieting?
+ * Or maybe it's because YOU and WINDOWS seem such a HAPPY couple.
+ *
+ * Of course NO. Not THOSE deathly BLUE WINDOWS! I mean your 'A'
+ * mode (alt display) windows. Yes, yes those completely OPTIONAL
+ * ones. We ALL know you'd NEVER FORCE that interface on ANY user
+ * - unlike You-Know-Who! Well I've got to run. But you're doing
+ * it just SPLENDIDLY! You go right on doing it EXACTLY the SAME!
+ */
+int main (int dont_care_argc, char **argv)
+{ /*
+ Ok, she's gone now. Don't you mind her, she means well but yes, she is
+ a bit of a busy-body. Always playing the matchmaker role, trying to do
+ away with unmarried windows and bachelors. So, back to business buddy!
+
+ You're hungry, you said? How'd you like a sandwich? No, no, no -- not
+ the usual slopped together, hacked up illogic. I'm talkin' a carefully
+ reasoned, artfully crafted, extremely capable, well behaved executable!
+
+ Well then, here, try THIS sandwich...
+ +-------------+ */
+ windows_stage1(); /* top (sic) slice */
+ before(*argv); /* > seasonings, < */
+ configs_read(); /* > spread etc, < */
+ parse_args(&argv[1]); /* > lean stuff, < */
+ whack_terminal(); /* > onions etc. < */
+ windows_stage2(); /* as bottom slice */
+ /* +-------------+ */
signal(SIGALRM, stop);
signal(SIGHUP, stop);
signal(SIGINT, stop);
signal(SIGTSTP, suspend);
signal(SIGTTIN, suspend);
signal(SIGTTOU, suspend);
- signal(SIGCONT, window_resize);
- signal(SIGWINCH, window_resize);
+ signal(SIGCONT, wins_resize);
+ signal(SIGWINCH, wins_resize);
- /* loop, collecting process info and sleeping */
do {
struct timeval tv;
fd_set fs;
char c;
+ /* This is it? */
+ so_lets_see_em(); /* Impossible! */
- show_everything();
if (Msg_awaiting) show_msg(Msg_delayed);
if (0 < Loops) --Loops;
if (!Loops) stop(0);
if (Batch)
sleep((unsigned)Delay_time);
- else {
- /* Linux reports time not slept, so we must reinit every time */
- tv.tv_sec = Delay_time;
+ else { /* Linux reports time not slept, */
+ tv.tv_sec = Delay_time; /* so we must reinit every time. */
tv.tv_usec = (Delay_time - (int)Delay_time) * 1000000;
FD_ZERO(&fs);
FD_SET(STDIN_FILENO, &fs);
}
} while (1);
+ /*
+ (listen before we return, aren't you sort of sad for 'so_lets_see-em'?)
+ (so, uh, why don't we just move this main guy to near the beginning of)
+ (the C source file. then that poor old function would be sure to have)
+ (at least a chance at scopin' us out, ya know what i mean? so what do)
+ (ya think? all things considered, would that be a proper thing to do?)
+
+ Now there's an EXCELLENT idea! After all, SOME programmers DO code the
+ main function ANY OLD PLACE they feel like. And in doing THAT, they're
+ helping to keep those that FOLLOW out of mischief, busy HUNTING for the
+ <bleepin'> thing. Further, by moving it we can contribute to PROTOTYPE
+ PROLIFERATION for every function main calls. Don't you KNOW that those
+ declarations OFTEN LINGER, usually long AFTER the REAL definitions have
+ DISAPPEARED, since programs do evolve? Yep that's a GREAT idea you got
+ there, NICE GOING! But, here's an opposing view: ANYONE who'd put main
+ ANYWHERE such that its LOCATION cannot be REACHED with JUST 1 KEYSTROKE
+ better turn in their Coding_Badge and Pocket_Protector then -- BE GONE!
+ The main function has only ONE proper HOME: always the LAST function in
+ that C Listing. End-of-Story, No-More-Discussion, so BE QUIET already!
+
+ \---------------------------------------------------------------------/
+ Sheeesh, didn't that dufus know the return statement can't be executed,
+ or a signal & stop() will do-us-in? Oh Lordy, I is DROWNING in morons;
+ they done REACHED clear up to my OUTER braces. We's all DOOMED, I say!
+ /---------------------------------------------------------------------\
+ */
return 0;
}
+
/* top.h - Header file: show Linux processes */
/*
- * Copyright (c) 2002 - James C. Warner, <warnerjc@worldnet.att.net>
- * All rights reserved.
+ * Copyright (c) June, 2002 - James C. Warner
+ * All rights reserved. 8921 Hilloway Road
+ * Eden Prairie, Minnesota 55347 USA
+ * <warnerjc@worldnet.att.net>
+ *
* This file may be used subject to the terms and conditions of the
* GNU Library General Public License Version 2, or any later version
* at your option, as published by the Free Software Foundation.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*/
+/* For their contributions to this program, the author wishes to thank:
+ * Craig Small, <csmall@eye-net.com.au>
+ * Albert D. Cahalan, <acahalan@cs.uml.edu>
+ */
#ifndef _Itop
#define _Itop
- /* Determines for whom we're destined, debian or !#@*#! redhat ----- */
+ /* Determines for whom we're destined ------------------------------ */
//#define UGH_ITS_4_RH /* use the redhat libproc conventions */
- /* Defines intended to be played with ------------------------------ */
-//#define UPCASE_HEXES /* show any hex values in upper case */
-//#define UPCASE_SCALE /* show scaled times & memory upper case */
-//#define UPCASE_SUMMK /* show memory summary kilobytes with 'K' */
-
-//#define COLOR_SLEEPY /* purples and blues (sissy colors) */
-//#define COLOR_CONSOL /* for linux consoles (white on black) */
+ /* Defines intended to be experimented with ------------------------ */
+//#define CASEUP_HEXES /* show any hex values in upper case */
+//#define CASEUP_SCALE /* show scaled times & memory upper case */
+//#define CASEUP_SUMMK /* show memory summary kilobytes with 'K' */
+//#define QUIT_NORMALQ /* use 'q' to quit, not new default <Esc> */
+//#define SORT_SUPRESS /* *attempt* to reduce qsort overhead */
+//#define USE_LIB_STA3 /* use lib status (3 ch) vs. proc_t (1 ch) */
+//#define WARN_NOT_SMP /* restrict '1' & 'I' commands to true smp */
/* Development/Debugging defines ----------------------------------- */
-//#define TRAK_MAXCAPS /* track & report misc terminfo stuff */
-//#define TRAK_MAXBUFS /* track & report internal buffer usage */
-
- /* Special define to test extremely dumb terminals! ---------------- */
+//#define ATEOJ_REPORT /* report a bunch of stuff, at end-of-job */
+//#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */
//#define PRETENDNOCAP /* use a terminal without essential caps */
+/*###### Some Miscellaneous constants ##################################*/
+
+ /* The default delay twix updates */
+#define DEF_DELAY 2.0
+
+ /* The length of time a 'message' is displayed */
+#define MSG_SLEEP 2
+
+ /* The default value for the 'k' (kill) request */
+#define DEF_SIGNAL SIGTERM
+
+ /* Specific process id monitoring support (command line only) */
+#define MONPIDMAX 20
+
+ /* Miscellaneous buffer sizes with liberal values
+ -- mostly just to pinpoint source code usage/dependancies */
+#define PFLAGSSIZ 32
+#define CAPBUFSIZ 32
+#define CLRBUFSIZ 64
+#define GETBUFSIZ 32
+#define TNYBUFSIZ 32
+#define SMLBUFSIZ 256
+#define MEDBUFSIZ 512
+#define OURPATHSZ 1024
+#define BIGBUFSIZ 2048
+#define RCFBUFSIZ SMLBUFSIZ
+#define USRNAMSIZ GETBUFSIZ
+#define COLBUFSIZ SMLBUFSIZ + CLRBUFSIZ
+#define ROWBUFSIZ MEDBUFSIZ + CLRBUFSIZ
+
+
+/*###### Some Miscellaneous Macro definitions ##########################*/
+
+ /* Used as return arguments to achieve normal/reversed sorts
+ in the sort callbacks */
+#define SORT_lt ( Frame_srtflg ? 1 : -1 )
+#define SORT_gt ( Frame_srtflg ? -1 : 1 )
+
+ /* Convert some proc stuff into vaules we can actually use */
+#define BYTES_2K(n) (unsigned)( (n) >> 10 )
+#define PAGES_2B(n) (unsigned)( (n) * Page_size )
+#define PAGES_2K(n) BYTES_2K(PAGES_2B(n))
+#define PAGE_CNT(n) (unsigned)( (n) / Page_size )
+
+ /* Yield table size as 'int' */
+#define MAXtbl(t) ( (int)(sizeof(t)/sizeof(t[0])) )
+
+
+/*###### Special Macros (debug and/or informative) #####################*/
+
+ /* Orderly end, with any sort of message - see fmtmk */
+#define debug_END(s) { \
+ static void std_err (const char *); \
+ fputs(Cap_clr_scr, stdout); \
+ std_err(s); \
+ }
+
+ /* A poor man's breakpoint, if he's too lazy to learn gdb */
+#define its_YOUR_fault { *((char *)0) = '!'; }
+
+
/*###### Some Typedef's and Enum's #####################################*/
/* This typedef attempts to ensure consistent 'ticks' handling. */
TICS_t tics;
} HIST_t;
- /* This structure serves single (non-smp), multiple (smp) and
- consolidated (smp, but Show_cpusum == 1) environments. It is
- used to calculate a frame's cpu(s) state percentages */
+ /* This structure stores the prior frame's tics used in history
+ calculations. It exists primarily for SMP support but serves
+ all environments. There will always Cpu_tot + 1 allocated
+ -- see frame_states for details. */
typedef struct {
TICS_t u, /* ticks count as represented in /proc/stat */
n, /* (not in the order of our display) */
};
/* Flags for each possible field.
- At the moment 32 are supported [ see PFlags/PFLAGSSIZ ] */
+ At the moment 32 are supported [ see PFLAGSSIZ ] */
enum pflag {
P_PID, P_PPID, P_UID, P_USER, P_GROUP, P_TTY,
P_PR, P_NI,
};
-/*###### Some Miscellaneous Macro definitions ##########################*/
-
- /* Message line placement at runtime */
-#define MSG_line ( HSum_lines - 2 )
-
- /* Used as return argument to achieve normal/reversed sorts
- in the sort callbacks */
-#define SORT_lt ( Sort_normal ? 1 : -1 )
-#define SORT_gt ( Sort_normal ? -1 : 1 )
-
- /* Convert some proc stuff into vaules we can actually use */
-#define BYTES_2K(n) (unsigned)( (n) >> 10 )
-#define PAGES_2B(n) (unsigned)( (n) * Page_size )
-#define PAGES_2K(n) BYTES_2K(PAGES_2B(n))
-#define PAGE_CNT(n) (unsigned)( (n) / Page_size )
-
- /* Yield table size as 'int' */
-#define MAXtbl(t) ( (int)(sizeof(t)/sizeof(t[0])) )
-
-
-/*###### Special Macros (debug and/or informative) #####################*/
-
- /* Orderly end, with any sort of message - see fmtmk */
-#define debug_END(s) { \
- static void std_err (const char *); \
- fputs(Cap_clr_scr, stdout); \
- std_err(s); \
- }
-
-#ifdef TRAK_MAXBUFS
- /* Provide for tracking maximum buffer sizes */
-#define ARPTBUF(f,b) "\n\t%4d of %d\t" #f ", " #b
-#define ASIZBUF(f,b) Siz_ ## f ## _ ## b
-#define AUSEBUF(f,b) Use_ ## f ## _ ## b
-#define BUF2INT(f,b) static int AUSEBUF(f,b) = 0, ASIZBUF(f,b) = 0;
-#define MAXBUFS(f,b) { \
- if ((int)strlen(b) > AUSEBUF(f,b)) \
- AUSEBUF(f,b) = (int)strlen(b); \
- ASIZBUF(f,b) = (int)sizeof(b); \
- }
-#endif
-
-
-/*###### Some Miscellaneous constants ##################################*/
-
- /* The default value for the 'k' (kill) request */
-#define DEF_SIGNAL SIGTERM
-
- /* The default delay twix updates */
-#define DEF_DELAY 2.0
-
- /* The length of time a 'message' is displayed */
-#define MSG_SLEEP 1
-
- /* Minimum summary lines (thus, just msg line + col heads) */
-#define SUMMINLINS 2
-
- /* Specific process id monitoring support (command line only) */
-#define MONPIDMAX 12
-
- /* Miscellaneous buffer sizes with liberal values
- -- mostly just to pinpoint source code usage/dependancies */
-#define PFLAGSSIZ 32
-#define CAPBUFSIZ 32
-#define CLRBUFSIZ 64
-#define GETBUFSIZ 32
-#define TNYBUFSIZ 32
-#define SMLBUFSIZ 256
-#define MEDBUFSIZ 512
-#define OURPATHSZ 1024
-#define BIGBUFSIZ 2048
-#define RCFBUFSIZ SMLBUFSIZ
-#define USRNAMSIZ GETBUFSIZ
-#define COLBUFSIZ SMLBUFSIZ + CLRBUFSIZ
-#define ROWBUFSIZ MEDBUFSIZ + CLRBUFSIZ
-
- /* Color stuff...
- note: we avoid the use of background color so as to maximize
- compatibility with the user's xterm settings */
-#ifdef COLOR_SLEEPY
-#define BASEcolor COLOR_MAGENTA
-#define MSGScolor COLOR_CYAN
-#define HEADcolor COLOR_BLUE
-#else
-#ifdef COLOR_CONSOL
-#define BASEcolor COLOR_CYAN
-#define MSGScolor COLOR_RED
-#define HEADcolor COLOR_WHITE
-#else
-#define BASEcolor COLOR_RED
-#define MSGScolor COLOR_RED
-#define HEADcolor COLOR_YELLOW
-#endif
-#endif
+ /* ////////////////////////////////////////////////////////////// */
+ /* Special Section: multiple windows/field groups ---------------*/
+ /* (kind of a header within a header: constants, macros & types) */
+
+#define GROUPSMAX 4 /* the max number of simultaneous windows */
+#define WINNAMSIZ 4 /* max size of a window's basic name */
+#define GRPNAMSIZ 6 /* window's name + number as in: '#:...' */
+#define CAPTABMAX 9 /* a window's captab used by show_special */
+
+#define Def_WINDOW 0 /* these represent the pre-allocated */
+#define Job_WINDOW 1 /* WIN_t's relative position in the */
+#define Mem_WINDOW 2 /* window stack pointer array... */
+#define Usr_WINDOW 3
+
+#define Flgs_TOG 1 /* these are used to direct wins_reflag */
+#define Flgs_SET 2
+#define Flgs_OFF 3
+
+ /* The Persistent 'Mode' flags!
+ All of these are preserved in the rc file, as a single integer.
+ Thus, once personalized, this top will stay personalized across
+ restarts (not like the old top, who only remembered fields)!
+ Note: the letter shown is the corresponding 'command' toggle
+ */
+ /* 'View_' flags affect the summary information, taken from 'Curwin' */
+#define View_CPUSUM 0x8000 /* '1' - show combined cpu stats (vs. each) */
+#define View_LOADAV 0x4000 /* 'l' - display load avg and uptime summary */
+#define View_STATES 0x2000 /* 't' - display task/cpu(s) states summary */
+#define View_MEMORY 0x1000 /* 'm' - display memory summary */
+ /* 'Show_' & 'Qsrt_' flags are for task display in a visible window */
+#define Show_COLORS 0x0800 /* 'z' - show in color (vs. mono) */
+#define Show_HIBOLD 0x0400 /* 'b' - rows and/or cols bold (vs. reverse) */
+#define Show_HICOLS 0x0200 /* 'x' - show sort column highlighted */
+#define Show_HIROWS 0x0100 /* 'y' - show running tasks highlighted */
+#define Show_CMDLIN 0x0080 /* 'c' - show cmdline vs. name */
+#define Show_CTIMES 0x0040 /* 'S' - show times as cumulative */
+#define Show_IDLEPS 0x0020 /* 'i' - show idle processes (all tasks) */
+#define Qsrt_NORMAL 0x0010 /* 'R' - reversed column sort (high to low) */
+ /* these flag(s) have no command as such - they're for internal use */
+#define VISIBLE_tsk 0x0008 /* tasks are showable in 'Show_altscr' mode */
+#define NEWFRAM_cwo 0x0004 /* new frame (if anyone cares) - in Curwin */
+#define EQUWINS_cwo 0x0002 /* rebalance tasks next frame (off 'i'/ 'n') */
+ /* ...set in Curwin, but impacts all windows */
+#define flag_unused 0x0001 /* ----------------------- future use, maybe */
+
+ /* Current-window-only flags -- always turned off at end-of-window! */
+#define FLGSOFF_cwo EQUWINS_cwo | NEWFRAM_cwo
+
+ /* Default flags if there's no rcfile to provide user customizations */
+#define DEF_WINFLGS ( View_LOADAV | View_STATES | View_CPUSUM | View_MEMORY | \
+ Show_HIBOLD | Show_HIROWS | Show_IDLEPS | Qsrt_NORMAL | VISIBLE_tsk )
+
+ /* Used to test/manipulate the window flags */
+#define CHKw(q,f) (int)(q->winflags & (f))
+#define TOGw(q,f) q->winflags ^= (f)
+#define SETw(q,f) q->winflags |= (f)
+#define OFFw(q,f) q->winflags &= ~(f)
+#define VIZCHKc (!Show_altscr || Curwin->winflags & VISIBLE_tsk) \
+ ? 1 : win_warn()
+#define VIZTOGc(f) (!Show_altscr || Curwin->winflags & VISIBLE_tsk) \
+ ? TOGw(Curwin, f) : win_warn()
+
+ /* Just create a printable window number -- represented here since
+ we can't decide which to prefer (relative 0 or 1) */
+#define mkWNO(q) q->winnum + 1
+
+ /* This structure stores configurable information for each window.
+ By expending a little effort in its creation and user requested
+ maintainence, the only real additional per frame cost of having
+ windows is a *potential* extra sort -- but that's just on ptrs!
+ */
+typedef struct win {
+ struct win *next, /* next window in window stack */
+ *prev; /* prior window in window stack */
+ int winnum, /* this window's num/array pos */
+ winlines; /* task window's rows (volatile) */
+ int winflags; /* 'view', 'show' and 'sort' mode flags */
+ char grpname [GRPNAMSIZ], /* window number:name, printable */
+ winname [WINNAMSIZ], /* window name, user changeable */
+ fieldscur [PFLAGSSIZ], /* fields displayed and ordered */
+ columnhdr [SMLBUFSIZ], /* column headings for procflags */
+ colusrnam [USRNAMSIZ]; /* if selected by the 'u' command */
+ unsigned procflags [PFLAGSSIZ]; /* fieldscur subset as: int/enum */
+ int maxpflgs, /* number of procflags (upcase fieldscur) */
+ maxtasks, /* user requested maximum, 0 equals all */
+ maxcmdln, /* max length of a process' command line */
+ sorttype; /* the last chosen sort field (as enum) */
+ QSORT_t sortfunc; /* sort function for this window's tasks */
+ int summclr, /* color num used in summ info */
+ msgsclr, /* " in msgs/pmts */
+ headclr, /* " in cols head */
+ taskclr; /* " in task display */
+ char capclr_sum [CLRBUFSIZ], /* terminfo strings built from */
+ capclr_msg [CLRBUFSIZ], /* above clrs (& rebuilt too), */
+ capclr_pmt [CLRBUFSIZ], /* but NO recurring costs !!! */
+ capclr_hdr [CLRBUFSIZ], /* note: sum, msg and pmt strs */
+ capclr_rowhigh [CLRBUFSIZ], /* are only used when this */
+ capclr_rownorm [CLRBUFSIZ]; /* window is the 'Curwin'! */
+ int len_rownorm, /* lengths of the corresponding terminfo */
+ len_rowhigh; /* strings to save mkcol() a strlen call */
+ char *captab [CAPTABMAX]; /* captab needed by show_special */
+} WIN_t;
+ /* ////////////////////////////////////////////////////////////// */
/*###### Display Support *Data* ########################################*/
+ /* An rcfile 'footprint' used to invalidate existing */
+#define RCF_FILEID 'c'
+
/* The default fields displayed and their order,
if nothing is specified by the loser, oops user */
#define DEF_FIELDS "AbcDefGHiJkLMNOPqrstuVWxy"
- /* Help screen selectable grouped fields */
+ /* Pre-configured grouped fields */
#define JOB_FIELDS "ABWdefikqrstuxyLJMGHVNOPC"
#define MEM_FIELDS "AMNOPQRSTUWbcdefiklxyVGHJ"
#define USR_FIELDS "CDEFABWghiknopqrstuxyLJMV"
/* Summary Lines specially formatted string(s) --
see 'show_special' for syntax details + other cautions. */
-#define LOADAV_line "%s -\03%s\n"
+#define LOADAV_line "%s -%s\n"
+#define LOADAV_line_alt "%s\06 -%s\n"
#define STATES_line1 "Tasks:\03" \
" %3u \02total,\03 %3u \02running,\03 %3u \02sleeping,\03" \
" %3u \02stopped,\03 %3u \02zombie\03\n"
#define STATES_line2 "%s\03" \
" %#5.1f%% \02user,\03 %#5.1f%% \02system,\03" \
" %#5.1f%% \02nice,\03 %#5.1f%% \02idle\03\n"
-#ifdef UPCASE_SUMMK
+#ifdef CASEUP_SUMMK
#define MEMORY_line1 "Mem: \03" \
" %8uK \02total,\03 %8uK \02used,\03" \
" %8uK \02free,\03 %8uK \02buffers\03\n"
" %8uk \02free,\03 %8uk \02cached\03\n"
#endif
-
/* Colors Help specially formatted string(s) --
see 'show_special' for syntax details + other cautions. */
-#define COLOR_sample \
+#define COLOR_help \
"%s%s's \01Help for color mapping\02 - %s\n" \
+ "current window: \01%s\06\n" \
"\n" \
- " color -\03 08:41:24 up 1 day, 6:07, 7 users, load average:\n" \
+ " color -\03 04:25:44 up 8 days, 50 min, 7 users, load average:\n" \
" Tasks:\03 64 \02total,\03 2 \02running,\03 62 \02sleeping,\03 0 \02stopped,\03\n" \
" State cpu0 :\03 76.5%% \02user,\03 11.2%% \02system,\03 0.0%% \02nice,\03\n" \
" \01 Nasty Message! \04 -or- \01Input Prompt\05\n" \
- " \01 PID TTY PR NI %%CPU TIME+ VIRT SWAP STA Command \06\n" \
- " 17284 \03 pts/2 \07 8 0 0.0 0:00.75 1380 0 S /bin/bas\03\n" \
- " \01 8601 pts/1 7 -10 0.4 0:00.03 916 0 R< color -b\07\n" \
- " 11005 \03 ? \07 9 0 0.0 0:02.50 2852 1008 S amor -se\03\n" \
- " 2924 \03 ? \07 9 -1 0.0 1:08.16 30040 20m S< X :0\03\n" \
- " (normal toggles available: \01b\02 = bold/reverse; \01z\02 = color/mono)\n" \
- "\n\n" \
+ " \01 PID TTY PR NI %%CPU TIME+ VIRT SWAP STA Command \06\n" \
+ " 17284 \10pts/2 \07 8 0 0.0 0:00.75 1380 0 S /bin/bash \10\n" \
+ " \01 8601 pts/1 7 -10 0.4 0:00.03 916 0 R < color -b \07\n" \
+ " 11005 \10? \07 9 0 0.0 0:02.50 2852 1008 S amor -ses \10\n" \
+ " available toggles: \01b\02 =bold/reverse (\01%s\02), \01z\02 =color/mono (\01%s\02)\n" \
+ "\n" \
"Select \01target\02 as upper case letter:\n" \
- " B\02 = Base color,\01 H\02 = Column Headings,\01 M\02 = Messages/Prompts\n" \
+ " S\02 = Summary Data,\01 M\02 = Messages/Prompts,\n" \
+ " H\02 = Column Heads,\01 T\02 = Task Information\n" \
"Select \01color\02 as number:\n" \
" 0\02 = black,\01 1\02 = red, \01 2\02 = green,\01 3\02 = yellow,\n" \
" 4\02 = blue, \01 5\02 = magenta,\01 6\02 = cyan, \01 7\02 = white\n" \
"\n" \
"Selected: \01target\02 \01 %c \04; \01color\02 \01 %d \04\n" \
- " press 'q' to abort or <Enter> to commit " \
+ " press 'q' to abort changes to window '\01%s\02'\n" \
+ " press 'a' or 'w' to commit & change another, <Enter> to commit and end " \
""
-
/* Keyboard Help specially formatted string(s) --
see 'show_special' for syntax details + other cautions. */
-#define HELP_data \
- "%s's \01Help for interactive commands\02 - %s\n" \
- "status: \01Secure mode \03%s\02;\01 Cumulative mode \03%s\02; \01Delay time \03%.1f\02 seconds\n" \
- " sp or ^L Redraw screen\n" \
- " o or O Rearrange fields\n" \
- " f or F Add and remove fields, or select group now from:\n" \
- " \01j\02) job fields; \01m\02) memory fields; \01u\02) user fields\n" \
- " Z Change color mapping\05\n" \
- "\n" \
- "C,M,P,T,U,Y,E Sort: \01C\02) cmd; \01M\02) mem; \01P\02) pid; \01T\02) time; \01U\02) cpu; \01Y\02) tty; \01E\02) user\n" \
- " R Toggle normal/reverse sort for any of above\n" \
- " l,t,m Toggle summary: \01l\02) load avg; \01t\02) task/cpu stats; \01m\02) mem info\n" \
- " c,i,S Toggle: \01c\02) cmd name/line; \01i\02) idle tasks; \01S\02) cumulative time\n" \
- " x,y\05 Toggle highlights: \01x\02) sort field; \01y\02) running tasks\n" \
- " z,b\05 Toggle: \01z\02) color/mono; \01b\02) bold/reverse if 'x' or 'y'\n" \
- " 1,I SMP views:\01 1\02) single/separate states; \01I\02) Irix/Solaris mode\n" \
+#ifdef QUIT_NORMALQ
+#define HELP_STOPkey " q "
+#else
+#define HELP_STOPkey " <Esc> "
+#endif
+#define KEYS_help \
+ "%s's - \01Help for Interactive Commands\02 - %s\n" \
+ "Window %s\06: \01Cumulative mode \03%s\02. \01System\06: \01Delay time \03%.1f secs\02; \01Secure mode \03%s\02.\n" \
+ " sp or ^L Redraw screen\n" \
+ " o Rearrange current window's fields\n" \
+ " f Add and remove current window's fields\n" \
+ " Z Change color mappings for any window\05\n" \
"\n" \
+ "(7 letters) . Sort: \01C\02) cmd; \01M\02) mem; \01P\02) pid; \01T\02) time; \01U\02) cpu; \01Y\02) tty; \01E\02) user\n" \
+ " R . Toggle normal/reverse sort for any of above\n" \
+ " l,t,m Toggle summary: \01l\02) load avg; \01t\02) task/cpu stats; \01m\02) mem info\n" \
+ " c,i,S . Toggle: \01c\02) cmd name/line; \01i\02) idle tasks; \01S\02) cumulative time\n" \
+ " x,y\05 . Toggle highlights: \01x\02) sort field; \01y\02) running tasks\n" \
+ " z,b\05 . Toggle: \01z\02) color/mono; \01b\02) bold/reverse, only if 'x' or 'y'\n" \
+ " 1,I Toggle SMP view:\01 1\02) single/separate states; \01I\02) Irix/Solaris mode\n" \
"%s" \
- " u Show specific user only\n" \
- " # or n Set maximum tasks displayed\n" \
- " W Write configuration file\n" \
- " q Quit\n" \
- "Press any key to continue " \
+ " u . Show specific user only\n" \
+ " # or n . Set maximum tasks displayed\n" \
+ " W Write configuration file\n" \
+ HELP_STOPkey "Quit\n" \
+ " ( commands shown with '.' require a \01visible\02 task display \01window\02 ) \n" \
+ "Press '\01h\02' or '\01?\02' for help with \01Windows\02,\n" \
+ "any other key to continue " \
""
/* This guy goes above the 'u' help text (maybe) */
-#define HELP_unsecured \
- " k Kill a task\n" \
- " r Renice a task\n" \
- " s or d Set update interval\n" \
+#define KEYS_help_unsecured \
+ " k Kill a task\n" \
+ " r Renice a task\n" \
+ " s or d Set update interval\n" \
""
-
/* Fields Reorder/Toggle specially formatted string(s) --
see 'show_special' for syntax details + other cautions
note: the leading newline below serves really dumb terminals;
if there's no 'cursor_home', the screen will be a mess
but this part will still be functional. */
#define FIELDS_current \
- "\n%s%s's\01 Current Fields\02: \01 %s \04\n%s " \
+ "\n%s%s's\01 Current Fields\02: \01 %s \04 for window \01%s\06\n%s " \
""
/* Some extra explanatory text which accompanies the Fields display.
" VIRT = SWAP + RES\n" \
" RES = CODE + DATA\n" \
""
+
+ /* Windows/Field Group Help specially formatted string(s) --
+ see 'show_special' for syntax details + other cautions. */
+#define WINDOWS_help \
+ "%s's \01Help for Windows and Field Groups\02 - \"Current\" = \01 %s \06\n" \
+ "\n" \
+ ". Use multiple \01windows\02, each with separate config opts (color,fields,sort,etc)\n" \
+ ". The '\01Current\05' window controls the \01Summary Area\02 and responds to your \01Commands\02\n" \
+ " . that window's \01task display\02 can be turned \01Off\02 & \01On\02, growing/shrinking others\n" \
+ " . with \01NO\02 task display, some commands will be \01disabled\02 ('i','R','n','c', etc)\n" \
+ " until a \01different window\02 has been activated, making it the '\01Current\05' window\n" \
+ ". You \01change\02 a '\01Current\05' window by: \01 1\02) cycling forward/backward; \01 2\02) choosing\n" \
+ " a specific window with 'O' or 'F'; or \01 3\02) exiting the color mapping screen\n" \
+ ". Commands \01available anytime\02 -------------\n" \
+ " \01A\02 . Alternate display mode toggle, show \01Single\02 / \01Multiple\02 windows\n" \
+ " O or F . Choose another field group and make it '\01Current\05', or change now\n" \
+ " by selecting a number: \01 1\02 :%s; \01 2\02 :%s; \01 3\02 :%s; \01 4\02 :%s\n" \
+ ". Commands \01requiring\02 '\01A\02' mode -----------\n" \
+ " g . Change the '\01Current\05' window name (field group)\n" \
+ " \01*\04 a , w . Cycle through all four windows: \01a\02 Forward; \01w\02 Backward\n" \
+ " \01*\04 - , _ . Show/Hide: '\01-\05' \01Current\02 window; '\01_\05' all \01Visible\02/\01Invisible\02\n" \
+ " The screen will be divided evenly between task displays. But you can make\n" \
+ " some \01larger\02 or \01smaller\02, using '\01n\02' and '\01i\02' commands. Then later you could:\n" \
+ " \01*\04 = , + . Rebalance tasks: '\01=\05' \01Current\02 window; '\01+\05' \01Every\02 window\n" \
+ " (this also forces the \01current\02 or \01every\02 window to become visible)\n" \
+ "\n" \
+ "In '\01A\02' mode, '\01*\04' keys are your \01essential\02 commands. Please try the '\01a\02' and '\01w\02'\n" \
+ "commands plus the 'O'/'F' sub-commands NOW. Press <Enter> to make 'Current' " \
+ ""
+
\f
/*###### Some Prototypes (ha!) #########################################*/
* Note also that functions are alphabetical within a group to aid
* source code navigation, which often influences choice of identifers. */
/*------ Sort callbacks ------------------------------------------------*/
+//atic int pid_sort (proc_t **P, proc_t **Q);
//atic int sort_cmd (proc_t **P, proc_t **Q);
//atic int sort_cpu (proc_t **P, proc_t **Q);
//atic int sort_mem (proc_t **P, proc_t **Q);
-//atic int sort_pid (proc_t **P, proc_t **Q);
//atic int sort_tme (proc_t **P, proc_t **Q);
//atic int sort_tty (proc_t **P, proc_t **Q);
//atic int sort_usr (proc_t **P, proc_t **Q);
//atic const char *fmtmk (const char *fmts, ...);
//atic char *strim (int sp, char *str);
//atic char *tg2 (int x, int y);
+/*------ Exit/Interrput routines ---------------------------------------*/
+//atic void bye_bye (int eno, const char *str);
+//atic void stop (int dont_care_sig);
+//atic void std_err (const char *str);
+//atic void suspend (int dont_care_sig);
/*------ Misc Color/Highlighting support -------------------------------*/
-//atic void capsmk (void);
+//atic void capsmk (WIN_t *q);
//atic void msg_save (const char *fmts, ...);
//atic void show_msg (const char *str);
//atic void show_pmt (const char *str);
//atic void show_special (const char *glob);
-//atic void tweak_colors (void);
-/*------ Small utility routines ----------------------------------------*/
-//atic char *ask_str (const char *prompt);
+/*------ Small Utility routines ----------------------------------------*/
+//atic char *ask4str (const char *prompt);
//atic float get_float (const char *prompt);
//atic int get_int (const char *prompt);
-//atic void mkheadings (void);
//atic char *scale_num (unsigned num, const unsigned width, const unsigned type);
//atic char *scale_tics (TICS_t tics, const unsigned width);
//atic float time_elapsed (void);
-/*------ Exit and Signal handled routines ------------------------------*/
-//atic void bye_bye (int eno, const char *str);
-//atic void std_err (const char *str);
-//atic void stop (int dont_care_sig);
-//atic void suspend (int dont_care_sig);
-//atic void window_resize (int dont_care_sig);
+/*------ Library Alternatives ------------------------------------------*/
+//atic void *alloc_c (unsigned numb);
+//atic void *alloc_r (void *q, unsigned numb);
+//atic proc_t **refreshprocs (proc_t **tbl);
/*------ Startup routines ----------------------------------------------*/
-//atic void parse_argvs (char **argv);
-//atic void parse_rc (char *opts);
-//atic void rcfiles_read (void);
-//atic void terminal_set (void);
+//atic void before (char *me);
+//atic void configs_read (void);
+//atic void parse_args (char **args);
+//atic void whack_terminal (void);
/*------ Field Selection/Ordering routines -----------------------------*/
//atic void display_fields (void);
//atic void fields_reorder (void);
//atic void fields_toggle (void);
-/*------ Library Alternatives ------------------------------------------*/
-//atic void *alloc_c (unsigned numb);
-//atic void *alloc_r (void *q, unsigned numb);
-//atic proc_t **readprocs (proc_t **tbl);
-/*------ Main screen routines ------------------------------------------*/
-//atic void do_key (unsigned c);
-#ifdef UGH_ITS_4_RH
-//atic unsigned frame_memory (void);
-#else
-//atic void frame_memory (void);
-#endif
-//atic void frame_smp (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx);
+/*------ Windows/Field Groups support ----------------------------------*/
+//atic void win_colsheads (WIN_t *q);
+//atic void win_names (WIN_t *q, const char *name);
+//atic void win_select (int ch);
+//atic void win_sortset (WIN_t *q, const int which);
+//atic int win_warn (void);
+//atic void winsclr (WIN_t *q, int save);
+//atic void wins_colors (void);
+//atic void wins_reflag (int what, int flg);
+//atic void wins_resize (int dont_care_sig);
+//atic void windows_stage1 (void);
+//atic void windows_stage2 (void);
+/*------ Per-Frame Display support -------------------------------------*/
+//atic void cpudo (FILE *fp, const char *fmt, CPUS_t *cpu, const char *pfx);
//atic void frame_states (proc_t **p, int show);
-//atic void mkcol (unsigned idx, int sta, int *pad, char *buf, ...);
-#ifdef UGH_ITS_4_RH
-//atic void show_a_task (proc_t *task, unsigned mempgs);
-#else
-//atic void show_a_task (proc_t *task);
-#endif
-//atic void show_everything (void);
+//atic void frame_storage (void);
+//atic void mkcol (WIN_t *q, unsigned idx, int sta, int *pad, char *buf, ...);
+//atic void show_a_task (WIN_t *q, proc_t *task);
+/*------ Main Screen routines ------------------------------------------*/
+//atic void do_key (unsigned c);
+//atic proc_t **do_summary (void);
+//atic void do_window (proc_t **ppt, WIN_t *q, int *lscr);
+//atic void sohelpme (int wix, int max);
+//atic void so_lets_see_em (void);
/*------ Entry point ---------------------------------------------------*/
// int main (int dont_care_argc, char **argv);