diff --git a/top.c b/top.c index b6ca3810..9bccc9d4 100644 --- a/top.c +++ b/top.c @@ -810,7 +810,7 @@ static void *alloc_r (void *q, unsigned numb) * as follows: * cpus[0] thru cpus[n] == tics for each separate cpu * cpus[Cpu_tot] == tics from the 1st /proc/stat line */ -static CPUS_t *cpus_refresh (CPUS_t *restrict cpus) +static CPUS_t *cpus_refresh (CPUS_t *cpus) { static FILE *fp = NULL; int i; @@ -1132,7 +1132,7 @@ static void parse_args (char **args) char *p; while (*args) { - char *cp = *(args++); + const char *cp = *(args++); while (*cp) { switch (*cp) { @@ -1261,8 +1261,9 @@ static void whack_terminal (void) #define L_CMDLINE L_stat | PROC_FILLARG #define L_EUSER L_status | PROC_FILLUSR #define L_GROUP L_status | PROC_FILLGRP -#define L_EITHER PROC_SPARE_1 #define L_NONE 0 + // from either 'stat' or 'status' (preferred), via bits not otherwise used +#define L_EITHER ~(L_stat|L_statm|L_status|L_CMDLINE|L_EUSER|L_GROUP) // for reframewins and summary_show 1st pass #define L_DEFAULT PROC_FILLSTAT @@ -1287,7 +1288,7 @@ static FTAB_t Fieldstab[] = { { "USER ", "%-8.8s ", -1, -1, _SF(P_USR), "User Name", L_EUSER }, { "GROUP ", "%-8.8s ", -1, -1, _SF(P_GRP), "Group Name", L_GROUP }, { "TTY ", "%-8.8s ", 8, -1, _SF(P_TTY), "Controlling Tty", L_stat }, - { " PR ", "%s ", -1, -1, _SF(P_PRI), "Priority", L_stat }, + { " PR ", "%3d ", -1, -1, _SF(P_PRI), "Priority", L_stat }, { " NI ", "%3d ", -1, -1, _SF(P_NCE), "Nice value", L_stat }, { "#C ", "%2u ", -1, -1, _SF(P_CPN), "Last used cpu (SMP)", L_stat }, { "%CPU ", "%#4.1f ", -1, -1, _SF(P_CPU), "CPU usage", L_stat }, @@ -1312,7 +1313,11 @@ static FTAB_t Fieldstab[] = { { "Command ", "%-*.*s ", -1, -1, _SF(P_CMD), "Command name/line", L_stat }, { "WCHAN ", "%-9.9s ", -1, -1, _SF(P_WCH), "Sleeping in Function", L_stat }, // next entry's special: the 0's will be replaced with '.'! - { "Flags ", "%s ", -1, -1, _SF(P_FLG), "Task Flags ", L_stat } +#ifdef CASEUP_HEXES + { "Flags ", "%08lX ", -1, -1, _SF(P_FLG), "Task Flags ", L_stat } +#else + { "Flags ", "%08lx ", -1, -1, _SF(P_FLG), "Task Flags ", L_stat } +#endif }; @@ -2164,7 +2169,7 @@ static void do_key (unsigned c) * 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 summaryhlp (CPUS_t *restrict const cpu, const char *restrict const pfx) +static void summaryhlp (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?) */ @@ -2280,7 +2285,7 @@ static proc_t **summary_show (void) /* * Display information for a single task row. */ -static void task_show (const WIN_t *restrict q, const proc_t *restrict p) +static void task_show (const WIN_t *q, const proc_t *p) { /* the following macro is our means to 'inline' emitting a column -- next to procs_refresh, that's the most frequent and costly part of top's job ! */ @@ -2304,18 +2309,17 @@ static void task_show (const WIN_t *restrict q, const proc_t *restrict p) for (x = 0; x < q->maxpflgs; x++) { char cbuf[ROWBUFSIZ], _z[ROWBUFSIZ]; - PFLG_t i = q->procflags[x]; // support for our make column - const char *restrict const f = Fieldstab[i].fmts; // macro AND sometimes - unsigned s = Fieldstab[i].scale; // fmt string must be altered ! + PFLG_t i = q->procflags[x]; // support for our field/column + const char *f = Fieldstab[i].fmts; // macro AND sometimes the fmt + unsigned s = Fieldstab[i].scale; // string must be altered ! unsigned w = Fieldstab[i].width; switch (i) { case P_CMD: - { const char *restrict ret; + { char *cp; if (CHKw(q, Show_CMDLIN)) { char tmp[ROWBUFSIZ]; if (p->cmdline) { - char *cp; j = 0; *(cp = tmp) = '\0'; do { @@ -2325,10 +2329,10 @@ static void task_show (const WIN_t *restrict q, const proc_t *restrict p) strim(1, tmp); } else strcpy(tmp, fmtmk(CMDLINE_FMTS, p->cmd)); - ret = tmp; + cp = tmp; } else - ret = p->cmd; - MKCOL(q->maxcmdln, q->maxcmdln, ret); + cp = (char *)p->cmd; + MKCOL(q->maxcmdln, q->maxcmdln, cp); } break; case P_COD: @@ -2351,9 +2355,10 @@ static void task_show (const WIN_t *restrict q, const proc_t *restrict p) break; case P_FLG: { char tmp[TNYBUFSIZ]; - snprintf(tmp, sizeof(tmp), "%08x", (unsigned)p->flags); + snprintf(tmp, sizeof(tmp), f, (long)p->flags); for (j = 0; tmp[j]; j++) if ('0' == tmp[j]) tmp[j] = '.'; - MKCOL(tmp); + f = tmp; + MKCOL(); } break; case P_FLT: @@ -2378,13 +2383,11 @@ static void task_show (const WIN_t *restrict q, const proc_t *restrict p) MKCOL((unsigned)p->ppid); break; case P_PRI: - { char tmp[TNYBUFSIZ]; - snprintf(tmp, sizeof(tmp), "%3d", (int)(p->priority)); - if (-99 > p->priority || 999 < p->priority) { - memcpy(tmp, " RT", 4); - } - MKCOL(tmp); - } + if (-99 > p->priority || +99 < p->priority) { + f = " RT "; + MKCOL(); + } else + MKCOL((int)p->priority); break; case P_RES: MKCOL(scale_num(PAGES_2K(p->resident), w, s)); @@ -2427,9 +2430,12 @@ static void task_show (const WIN_t *restrict q, const proc_t *restrict p) break; case P_WCH: if (No_ksyms) { - char tmp[TNYBUFSIZ]; - snprintf(tmp, sizeof(tmp), "%08lx ", (unsigned long)p->wchan); - MKCOL(tmp); +#ifdef CASEUP_HEXES + f = "%08lX "; +#else + f = "%08lx "; +#endif + MKCOL((long)p->wchan); } else { MKCOL(wchan(p->wchan)); } diff --git a/top.h b/top.h index 3c48b4f8..f9ff5d99 100644 --- a/top.h +++ b/top.h @@ -108,24 +108,23 @@ static int sort_ ## f (const proc_t **P, const proc_t **Q) { \ return Frame_srtflg * strcmp((*Q)->s, (*P)->s); } - /* Used in the following ways, to 'inline' those portions of the - display requiring formatting while protecting against potential - embedded 'millesecond delay' escape sequences. - PUTT - Put to Tty - . for temporary interactive 'REPLACEMENT' output + /* The following two macros are used to 'inline' those portions of the + * display process requiring formatting, while protecting against any + * potential embedded 'millesecond delay' escape sequences. */ + /** PUTT - Put to Tty (used in many places) + . for temporary, possibly interactive, 'replacement' output . may contain ANY valid terminfo escape sequences - . need NOT represent an entire screen row - PUFF - Put for Frame - . for more permanent frame-oriented 'UPDATE' output - . may NOT contain cursor motion terminfo escapes - . represents a complete screen ROW - . subject to optimization, thus MAY be discarded - . when discarded, replaced by a NEWLINE */ + . need NOT represent an entire screen row */ #define PUTT(fmt,arg...) do { \ char _str[ROWBUFSIZ]; \ snprintf(_str, sizeof(_str), fmt, ## arg); \ putp(_str); \ } while (0) + /** PUFF - Put for Frame (used in only 3 places) + . for more permanent frame-oriented 'update' output + . may NOT contain cursor motion terminfo escapes + . assumed to represent a complete screen ROW + . subject to optimization, thus MAY be discarded */ #define PUFF(fmt,arg...) do { \ char _str[ROWBUFSIZ]; \ char *_ptr = &Pseudo_scrn[Pseudo_row++ * Pseudo_cols]; \ @@ -189,10 +188,8 @@ typedef struct { calculations. It exists primarily for SMP support but serves all environments. */ typedef struct { - // ticks count as represented in /proc/stat - TICS_t u, n, s, i, w; - // tics count in the order of our display - TICS_t u_sav, s_sav, n_sav, i_sav, w_sav; + TICS_t u, n, s, i, w; // as represented in /proc/stat + TICS_t u_sav, s_sav, n_sav, i_sav, w_sav; // in the order of our display } CPUS_t; /* The scaling 'type' used with scale_num() -- this is how @@ -512,6 +509,20 @@ typedef struct win { "commands plus the 'G' sub-commands NOW. Press to make 'Current' " \ "" + +/*###### For Piece of mind and/or backward compatability ################*/ + + /* just sanity check(s)... */ +#if USRNAMSIZ < GETBUFSIZ +# error "Jeeze, USRNAMSIZ Must NOT be less than GETBUFSIZ !" +#endif +#ifndef MALLOC +# define MALLOC +#endif +#ifndef restrict +# define restrict +#endif + /*###### Some Prototypes (ha!) #########################################*/ @@ -521,9 +532,9 @@ typedef struct win { * source code navigation, which often influences the identifers. */ /*------ Sort callbacks ------------------------------------------------*/ /* for each possible field, in the form of: */ -/*atic int sort_P_XXX (const proc_t **P, const proc_t **Q); */ +/*atic int sort_P_XXX (const proc_t **P, const proc_t **Q); */ /* additional specialized sort callback(s) */ -//atic int sort_HIST_t (const HIST_t *P, const HIST_t *Q); +/*atic int sort_HIST_t (const HIST_t *P, const HIST_t *Q); */ /*------ Tiny useful routine(s) ----------------------------------------*/ //atic int chin (int ech, char *buf, unsigned cnt); //atic const char *fmtmk (const char *fmts, ...); @@ -550,7 +561,7 @@ typedef struct win { /*------ Library Alternatives ------------------------------------------*/ //atic void *alloc_c (unsigned numb) MALLOC; //atic void *alloc_r (void *q, unsigned numb) MALLOC; -//atic CPUS_t *cpus_refresh (CPUS_t *restrict cpus); +//atic CPUS_t *cpus_refresh (CPUS_t *cpus); //atic void prochlp (proc_t *this); //atic proc_t **procs_refresh (proc_t **table, int flags); /*------ Startup routines ----------------------------------------------*/ @@ -559,7 +570,7 @@ typedef struct win { //atic void parse_args (char **args); //atic void whack_terminal (void); /*------ Field Selection/Ordering routines -----------------------------*/ -/*atic FTAB_t Fieldstab[] = { ... } */ +/*atic FTAB_t Fieldstab[] = { ... } */ //atic void display_fields (const char *fields, const char *xtra); //atic void fields_reorder (void); //atic void fields_sort (void); @@ -577,19 +588,14 @@ typedef struct win { //atic void windows_stage2 (void); /*------ Main Screen routines ------------------------------------------*/ //atic void do_key (unsigned c); -//atic void summaryhlp (CPUS_t *restrict const cpu, const char *restrict const pfx); +//atic void summaryhlp (CPUS_t *cpu, const char *pfx); //atic proc_t **summary_show (void); -//atic void task_show (const WIN_t *restrict q, const proc_t *restrict p); +//atic void task_show (const WIN_t *q, const proc_t *p); //atic void window_show (proc_t **ppt, WIN_t *q, int *lscr); /*------ Entry point plus two ------------------------------------------*/ //atic void framehlp (int wix, int max); //atic void frame_make (void); // int main (int dont_care_argc, char **argv); - /* just sanity check(s)... */ -#if USRNAMSIZ < GETBUFSIZ -# error "Jeeze, USRNAMSIZ Must NOT be less than GETBUFSIZ !" -#endif - #endif /* _Itop */ diff --git a/watch.c b/watch.c index 5a6df452..41445ade 100644 --- a/watch.c +++ b/watch.c @@ -8,7 +8,6 @@ * Mike Coleman . */ - #define VERSION "0.2.0" #include @@ -23,263 +22,252 @@ #include #include -static struct option longopts[] = - { - { "differences", optional_argument, 0, 'd' }, - { "help", no_argument, 0, 'h' }, - { "interval", required_argument, 0, 'n' }, - { "version", no_argument, 0, 'v' }, - { 0, 0, 0, 0 } - }; - -static char usage[] = "Usage: %s [-dhnv] [--differences[=cumulative]] [--help] [--interval=] [--version] \n"; +static struct option longopts[] = { + {"differences", optional_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {"interval", required_argument, 0, 'n'}, + {"version", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; +static char usage[] = + "Usage: %s [-dhnv] [--differences[=cumulative]] [--help] [--interval=] [--version] \n"; static char *progname; static int curses_started = 0; -static int height=24, width=80; -static int screen_size_changed=0; -static int first_screen=1; - +static int height = 24, width = 80; +static int screen_size_changed = 0; +static int first_screen = 1; #define min(x,y) ((x) > (y) ? (y) : (x)) - static void do_usage(void) { - fprintf(stderr, usage, progname); - exit(1); + fprintf(stderr, usage, progname); + exit(1); } - static void -do_exit(int status) { - if (curses_started) - endwin(); - exit(status); +do_exit(int status) +{ + if (curses_started) + endwin(); + exit(status); } - /* signal handler */ static void die(int notused) { - (void)notused; - do_exit(0); + (void) notused; + do_exit(0); } - static void winch_handler(int notused) { - (void)notused; - screen_size_changed = 1; + (void) notused; + screen_size_changed = 1; } - static void get_terminal_size(void) { - struct winsize w; - if (ioctl(2, TIOCGWINSZ, &w) == 0) - { - if (w.ws_row > 0) - height = w.ws_row; - if (w.ws_col > 0) - width = w.ws_col; - } + struct winsize w; + if (ioctl(2, TIOCGWINSZ, &w) == 0) { + if (w.ws_row > 0) + height = w.ws_row; + if (w.ws_col > 0) + width = w.ws_col; + } } - int main(int argc, char *argv[]) { - int optc; - int option_differences=0, - option_differences_cumulative=0, - option_help=0, - option_version=0; - int interval=2; - char *command; - int command_length=0; /* not including final \0 */ + int optc; + int option_differences = 0, + option_differences_cumulative = 0, + option_help = 0, option_version = 0; + int interval = 2; + char *command; + int command_length = 0; /* not including final \0 */ - setlocale(LC_ALL,""); - progname = argv[0]; + setlocale(LC_ALL, ""); + progname = argv[0]; - while ((optc = getopt_long(argc, argv, "+d::hn:v", longopts, (int *) 0)) - != EOF) - { - switch (optc) - { - case 'd': - option_differences = 1; - if (optarg) - option_differences_cumulative = 1; - break; - case 'h': - option_help = 1; - break; - case 'n': - { - char *str; - interval = strtol(optarg, &str, 10); - if (!*optarg || *str) - do_usage(); - } - break; - case 'v': - option_version = 1; - break; - default: - do_usage(); - break; - } - } - - if (option_version) - { - fprintf (stderr, "%s\n", VERSION); - if (!option_help) - exit(0); - } - - if (option_help) - { - fprintf(stderr, usage, progname); - fputs(" -d, --differences[=cumulative]\thighlight changes between updates\n", stderr); - fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr); - fputs(" -h, --help\t\t\t\tprint a summary of the options\n", stderr); - fputs(" -n, --interval=\t\tseconds to wait between updates\n", stderr); - fputs(" -v, --version\t\t\t\tprint the version number\n", stderr); - exit(0); - } - - if (optind >= argc) - do_usage(); - - command = strdup(argv[optind++]); - command_length = strlen(command); - for (;optind (size_t)(width - tsl - 1)) - mvaddstr(0, width - tsl - 4, "... "); - mvaddstr(0, width - tsl + 1, ts); - free(header); - - if (!(p = popen(command, "r"))) - { - perror("popen"); - do_exit(2); - } - - for (y=2; y\t\tseconds to wait between updates\n", + stderr); + fputs(" -v, --version\t\t\t\tprint the version number\n", + stderr); + exit(0); + } - endwin(); + if (optind >= argc) + do_usage(); - return 0; + command = strdup(argv[optind++]); + command_length = strlen(command); + for (; optind < argc; optind++) { + char *endp; + int s = strlen(argv[optind]); + command = realloc(command, command_length + s + 2); /* space and \0 */ + endp = command + command_length; + *endp = ' '; + memcpy(endp + 1, argv[optind], s); + command_length += 1 + s; /* space then string length */ + command[command_length] = '\0'; + } + + get_terminal_size(); + + /* Catch keyboard interrupts so we can put tty back in a sane state. */ + signal(SIGINT, die); + signal(SIGTERM, die); + signal(SIGHUP, die); + signal(SIGWINCH, winch_handler); + + /* Set up tty for curses use. */ + curses_started = 1; + initscr(); + nonl(); + noecho(); + cbreak(); + + for (;;) { + time_t t = time(NULL); + char *ts = ctime(&t); + int tsl = strlen(ts); + char *header; + FILE *p; + int x, y; + int oldeolseen = 1; + + if (screen_size_changed) { + get_terminal_size(); + resizeterm(height, width); + clear(); + /* redrawwin(stdscr); */ + screen_size_changed = 0; + first_screen = 1; + } + + /* left justify interval and command, right justify time, clipping all + to fit window width */ + asprintf(&header, "Every %ds: %.*s", + interval, min(width - 1, command_length), command); + mvaddstr(0, 0, header); + if (strlen(header) > (size_t) (width - tsl - 1)) + mvaddstr(0, width - tsl - 4, "... "); + mvaddstr(0, width - tsl + 1, ts); + free(header); + + if (!(p = popen(command, "r"))) { + perror("popen"); + do_exit(2); + } + + for (y = 2; y < height; y++) { + int eolseen = 0, tabpending = 0; + for (x = 0; x < width; x++) { + int c = ' '; + int attr = 0; + + if (!eolseen) { + /* if there is a tab pending, just spit spaces until the + next stop instead of reading characters */ + if (!tabpending) + do + c = getc(p); + while (c != EOF && !isprint(c) + && c != '\n' + && c != '\t'); + if (c == '\n') + if (!oldeolseen && x == 0) { + x = -1; + continue; + } else + eolseen = 1; + else if (c == '\t') + tabpending = 1; + if (c == EOF || c == '\n' || c == '\t') + c = ' '; + if (tabpending && (((x + 1) % 8) == 0)) + tabpending = 0; + } + move(y, x); + if (option_differences) { + int oldch = inch(); + char oldc = oldch & A_CHARTEXT; + attr = !first_screen + && (c != oldc + || + (option_differences_cumulative + && (oldch & A_ATTRIBUTES))); + } + if (attr) + standout(); + addch(c); + if (attr) + standend(); + } + oldeolseen = eolseen; + } + + pclose(p); + + first_screen = 0; + refresh(); + sleep(interval); + } + + endwin(); + + return 0; }