diff options
Diffstat (limited to 'commands.c')
-rw-r--r-- | commands.c | 970 |
1 files changed, 747 insertions, 223 deletions
diff --git a/commands.c b/commands.c index a852a4752b57..e93fb54646c1 100644 --- a/commands.c +++ b/commands.c @@ -1,12 +1,38 @@ /* + * Copyright (c) 1984 through 2008, William LeFebvre + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of William LeFebvre nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* * Top users/processes display for Unix * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University */ /* @@ -19,134 +45,51 @@ #include "os.h" #include <ctype.h> #include <signal.h> +#include <stdarg.h> +#include <unistd.h> +#include <color.h> #include <errno.h> -#include <sys/time.h> +#ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> +#endif + +#if defined(HAVE_DECL_SYS_SIGLIST) & defined(HAVE_STRCASECMP) +#define USE_SYS_SIGLIST +#endif +#ifdef USE_SYS_SIGLIST +extern const char * const sys_siglist[]; +extern const char * const sys_signame[]; +#else #include "sigdesc.h" /* generated automatically */ +#endif #include "top.h" +#include "machine.h" +#include "globalstate.h" #include "boolean.h" +#include "color.h" +#include "commands.h" +#include "display.h" +#include "screen.h" +#include "username.h" #include "utils.h" +#include "version.h" extern int errno; extern char *copyright; -/* imported from screen.c */ -extern int overstrike; - -int err_compar(); -char *err_string(); - -/* - * show_help() - display the help screen; invoked in response to - * either 'h' or '?'. - */ - -show_help() - -{ - printf("Top version %s, %s\n", version_string(), copyright); - fputs("\n\n\ -A top users display for Unix\n\ -\n\ -These single-character commands are available:\n\ -\n\ -^L - redraw screen\n\ -q - quit\n\ -h or ? - help; show this text\n", stdout); - - /* not all commands are availalbe with overstrike terminals */ - if (overstrike) - { - fputs("\n\ -Other commands are also available, but this terminal is not\n\ -sophisticated enough to handle those commands gracefully.\n\n", stdout); - } - else - { - fputs("\ -d - change number of displays to show\n\ -e - list errors generated by last \"kill\" or \"renice\" command\n\ -i - toggle the displaying of idle processes\n\ -I - same as 'i'\n\ -k - kill processes; send a signal to a list of processes\n\ -n or # - change number of processes to display\n", stdout); -#ifdef ORDER - fputs("\ -o - specify sort order (size, res, cpu, time)\n", stdout); -#endif - fputs("\ -r - renice a process\n\ -s - change number of seconds to delay between updates\n\ -u - display processes for only one user (+ selects all users)\n\ -\n\ -\n", stdout); - } -} - -/* - * Utility routines that help with some of the commands. - */ - -char *next_field(str) - -register char *str; - -{ - if ((str = strchr(str, ' ')) == NULL) - { - return(NULL); - } - *str = '\0'; - while (*++str == ' ') /* loop */; - - /* if there is nothing left of the string, return NULL */ - /* This fix is dedicated to Greg Earle */ - return(*str == '\0' ? NULL : str); -} - -scanint(str, intp) - -char *str; -int *intp; - -{ - register int val = 0; - register char ch; - - /* if there is nothing left of the string, flag it as an error */ - /* This fix is dedicated to Greg Earle */ - if (*str == '\0') - { - return(-1); - } - - while ((ch = *str++) != '\0') - { - if (isdigit(ch)) - { - val = val * 10 + (ch - '0'); - } - else if (isspace(ch)) - { - break; - } - else - { - return(-1); - } - } - *intp = val; - return(0); -} +typedef struct command { + int ch; + int (*cmd_func)(globalstate *); + char *help; +} command; /* * Some of the commands make system calls that could generate errors. * These errors are collected up in an array of structures for later * contemplation and display. Such routines return a string containing an - * error message, or NULL if no errors occurred. The next few routines are - * for manipulating and displaying these errors. We need an upper limit on + * error message, or NULL if no errors occurred. We need an upper limit on * the number of errors, so we arbitrarily choose 20. */ @@ -160,96 +103,43 @@ struct errs /* structure for a system-call error */ static struct errs errs[ERRMAX]; static int errcnt; -static char *err_toomany = " too many errors occurred"; -static char *err_listem = - " Many errors occurred. Press `e' to display the list of errors."; /* These macros get used to reset and log the errors */ #define ERR_RESET errcnt = 0 -#define ERROR(p, e) if (errcnt >= ERRMAX) \ - { \ - return(err_toomany); \ - } \ - else \ +#define ERROR(p, e) if (errcnt < ERRMAX) \ { \ errs[errcnt].arg = (p); \ errs[errcnt++].errnum = (e); \ } /* - * err_string() - return an appropriate error string. This is what the - * command will return for displaying. If no errors were logged, then - * return NULL. The maximum length of the error string is defined by - * "STRMAX". + * err_compar(p1, p2) - comparison routine used by "qsort" + * for sorting errors. */ -#define STRMAX 80 - -char *err_string() +int +err_compar(const void *p1, const void *p2) { - register struct errs *errp; - register int cnt = 0; - register int first = Yes; - register int currerr = -1; - int stringlen; /* characters still available in "string" */ - static char string[STRMAX]; - - /* if there are no errors, return NULL */ - if (errcnt == 0) - { - return(NULL); - } - - /* sort the errors */ - qsort((char *)errs, errcnt, sizeof(struct errs), err_compar); - - /* need a space at the front of the error string */ - string[0] = ' '; - string[1] = '\0'; - stringlen = STRMAX - 2; + register int result; - /* loop thru the sorted list, building an error string */ - while (cnt < errcnt) + if ((result = ((struct errs *)p1)->errnum - + ((struct errs *)p2)->errnum) == 0) { - errp = &(errs[cnt++]); - if (errp->errnum != currerr) - { - if (currerr != -1) - { - if ((stringlen = str_adderr(string, stringlen, currerr)) < 2) - { - return(err_listem); - } - (void) strcat(string, "; "); /* we know there's more */ - } - currerr = errp->errnum; - first = Yes; - } - if ((stringlen = str_addarg(string, stringlen, errp->arg, first)) ==0) - { - return(err_listem); - } - first = No; + return(strcmp(((struct errs *)p1)->arg, + ((struct errs *)p2)->arg)); } - - /* add final message */ - stringlen = str_adderr(string, stringlen, currerr); - - /* return the error string */ - return(stringlen == 0 ? err_listem : string); + return(result); } /* * str_adderr(str, len, err) - add an explanation of error "err" to - * the string "str". + * the string "str" without overflowing length "len". return + * number of characters remaining in str, or 0 if overflowed. */ -str_adderr(str, len, err) - -char *str; -int len; -int err; +int +str_adderr(char *str, int len, int err) { register char *msg; @@ -268,16 +158,14 @@ int err; /* * str_addarg(str, len, arg, first) - add the string argument "arg" to - * the string "str". This is the first in the group when "first" - * is set (indicating that a comma should NOT be added to the front). + * the string "str" without overflowing length "len". This is the + * first in the group when "first" is set (indicating that a comma + * should NOT be added to the front). Return number of characters + * remaining in str, or 0 if overflowed. */ -str_addarg(str, len, arg, first) - -char *str; -int len; -char *arg; -int first; +int +str_addarg(char *str, int len, char *arg, int first) { register int arglen; @@ -300,28 +188,139 @@ int first; } /* - * err_compar(p1, p2) - comparison routine used by "qsort" - * for sorting errors. + * void err_string() + * + * Use message_error to log errors in the errs array. This function + * will combine identical errors to make the message short, but if + * there is more than one type of error it will call message_error + * for each one. */ -err_compar(p1, p2) +#define STRMAX 80 -register struct errs *p1, *p2; +void +err_string() { - register int result; + register struct errs *errp; + register int cnt = 0; + register int first = Yes; + register int currerr = -1; + int stringlen = 0; /* characters still available in "string" */ + char string[STRMAX]; - if ((result = p1->errnum - p2->errnum) == 0) + /* if there are no errors, our job is easy */ + if (errcnt == 0) { - return(strcmp(p1->arg, p2->arg)); + return; } - return(result); + + /* sort the errors */ + qsort((char *)errs, errcnt, sizeof(struct errs), err_compar); + + /* initialize the buffer (probably not necessary) */ + string[0] = '\0'; + stringlen = STRMAX - 1; + + /* loop thru the sorted list, logging errors */ + while (cnt < errcnt) + { + /* point to the current error */ + errp = &(errs[cnt++]); + + /* note that on overflow "stringlen" will become 0 and all + subsequent calls to str_addarg or str_adderr will return 0 */ + + /* if the error number is different then add the error string */ + if (errp->errnum != currerr) + { + if (currerr != -1) + { + /* add error string and log the error */ + stringlen = str_adderr(string, stringlen, currerr); + message_error(" %s", string); + + } + /* reset the buffer */ + string[0] = '\0'; + stringlen = STRMAX - 1; + + /* move to next error num */ + currerr = errp->errnum; + first = Yes; + } + + /* add this arg */ + stringlen = str_addarg(string, stringlen, errp->arg, first); + first = No; + } + + /* add final message */ + stringlen = str_adderr(string, stringlen, currerr); + + /* write the error string */ + message_error(" %s", string); +} + +/* + * Utility routines that help with some of the commands. + */ + +char * +next_field(char *str) + + +{ + if ((str = strchr(str, ' ')) == NULL) + { + return(NULL); + } + *str = '\0'; + while (*++str == ' ') /* loop */; + + /* if there is nothing left of the string, return NULL */ + /* This fix is dedicated to Greg Earle */ + return(*str == '\0' ? NULL : str); +} + +int +scanint(char *str, int *intp) + +{ + register int val = 0; + register int ch; + + /* if there is nothing left of the string, flag it as an error */ + /* This fix is dedicated to Greg Earle */ + if (*str == '\0') + { + return(-1); + } + + while ((ch = *str++) != '\0') + { + if (isdigit(ch)) + { + val = val * 10 + (ch - '0'); + } + else if (isspace(ch)) + { + break; + } + else + { + return(-1); + } + } + *intp = val; + return(0); } /* * error_count() - return the number of errors currently logged. */ +int error_count() { @@ -332,6 +331,7 @@ error_count() * show_errors() - display on stdout the current log of errors. */ +void show_errors() { @@ -352,16 +352,18 @@ show_errors() * command does; invoked in response to 'k'. */ -char *kill_procs(str) - -char *str; +void +kill_procs(char *str) { register char *nptr; int signum = SIGTERM; /* default */ int procnum; - struct sigdesc *sigp; int uid; + int owner; +#ifndef USE_SYS_SIGLIST + struct sigdesc *sigp; +#endif /* reset error array */ ERR_RESET; @@ -370,30 +372,51 @@ char *str; uid = getuid(); /* skip over leading white space */ - while (isspace(*str)) str++; + while (isspace((int)*str)) str++; if (str[0] == '-') { /* explicit signal specified */ if ((nptr = next_field(str)) == NULL) { - return(" kill: no processes specified"); + message_error(" kill: no processes specified"); + return; } - if (isdigit(str[1])) + str++; + if (isdigit((int)str[0])) { - (void) scanint(str + 1, &signum); + (void) scanint(str, &signum); if (signum <= 0 || signum >= NSIG) { - return(" invalid signal number"); + message_error(" kill: invalid signal number"); + return; } } else { /* translate the name into a number */ +#ifdef USE_SYS_SIGLIST + for (signum = 1; signum < NSIG; signum++) + { + if (strcasecmp(sys_signame[signum], str) == 0) + { + break; + } + } + if (signum == NSIG) + { + message_error(" kill: bad signal name"); + return; + } +#else for (sigp = sigdesc; sigp->name != NULL; sigp++) { - if (strcmp(sigp->name, str + 1) == 0) +#ifdef HAVE_STRCASECMP + if (strcasecmp(sigp->name, str) == 0) +#else + if (strcmp(sigp->name, str) == 0) +#endif { signum = sigp->number; break; @@ -403,8 +426,10 @@ char *str; /* was it ever found */ if (sigp->name == NULL) { - return(" bad signal name"); + message_error(" kill: bad signal name"); + return; } +#endif } /* put the new pointer in place */ str = nptr; @@ -420,9 +445,10 @@ char *str; else { /* check process owner if we're not root */ - if (uid && (uid != proc_owner(procnum))) + owner = proc_owner(procnum); + if (uid && (uid != owner)) { - ERROR(str, EACCES); + ERROR(str, owner == -1 ? ESRCH : EACCES); } /* go in for the kill */ else if (kill(procnum, signum) == -1) @@ -433,8 +459,8 @@ char *str; } } while ((str = next_field(str)) != NULL); - /* return appropriate error string */ - return(err_string()); + /* process errors */ + err_string(); } /* @@ -442,9 +468,8 @@ char *str; * "renice" command does; invoked in response to 'r'. */ -char *renice_procs(str) - -char *str; +void +renice_procs(char *str) { register char negate; @@ -475,16 +500,17 @@ char *str; /* check for validity */ if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX) { - return(" bad priority value"); + message_error(" renice: bad priority value"); } #endif /* move to the first process number */ if ((str = next_field(str)) == NULL) { - return(" no processes specified"); + message_error(" remice: no processes specified"); } +#ifdef HAVE_SETPRIORITY /* loop thru the process numbers, renicing each one */ do { @@ -503,8 +529,506 @@ char *str; ERROR(str, errno); } } while ((str = next_field(str)) != NULL); + err_string(); +#else + message_error(" renice operation not supported"); +#endif +} - /* return appropriate error string */ - return(err_string()); +/* COMMAND ROUTINES */ + +/* + * Each command routine is called by command_process and is passed a + * pointer to the current global state. Command routines are free + * to change anything in the global state, although changes to the + * statics structure are discouraged. Whatever a command routine + * returns will be returned by command_process. + */ + +void +cmd_quit(globalstate *gstate) + +{ + quit(EX_OK); + /*NOTREACHED*/ +} + +int +cmd_update(globalstate *gstate) + +{ + /* go home for visual feedback */ + screen_home(); + fflush(stdout); + message_expire(); + return CMD_REFRESH; +} + +int +cmd_redraw(globalstate *gstate) + +{ + gstate->fulldraw = Yes; + return CMD_REFRESH; +} + +int +cmd_color(globalstate *gstate) + +{ + gstate->use_color = color_activate(-1); + gstate->fulldraw = Yes; + return CMD_REFRESH; +} + +int +cmd_number(globalstate *gstate) + +{ + int newval; + char tmpbuf[20]; + + message_prompt("Number of processes to show: "); + newval = readline(tmpbuf, 8, Yes); + if (newval > -1) + { + if (newval > gstate->max_topn) + { + message_error(" This terminal can only display %d processes", + gstate->max_topn); + } + + if (newval == 0) + { + /* inhibit the header */ + display_header(No); + } + + else if (gstate->topn == 0) + { + display_header(Yes); + } + + gstate->topn = newval; + } + return CMD_REFRESH; +} + +int +cmd_delay(globalstate *gstate) + +{ + int newval; + char tmpbuf[20]; + + message_prompt("Seconds to delay: "); + if ((newval = readline(tmpbuf, 8, Yes)) > -1) + { + if ((gstate->delay = newval) == 0 && getuid() != 0) + { + gstate->delay = 1; + } + } + return CMD_REFRESH; +} + +int +cmd_idle(globalstate *gstate) + +{ + gstate->pselect.idle = !gstate->pselect.idle; + message_error(" %sisplaying idle processes.", + gstate->pselect.idle ? "D" : "Not d"); + return CMD_REFRESH; +} + +int +cmd_displays(globalstate *gstate) + +{ + int i; + char tmpbuf[20]; + + message_prompt("Displays to show (currently %s): ", + gstate->displays == -1 ? "infinite" : + itoa(gstate->displays)); + + if ((i = readline(tmpbuf, 10, Yes)) > 0) + { + gstate->displays = i; + } + else if (i == 0) + { + quit(EX_OK); + /*NOTREACHED*/ + } + return CMD_OK; +} + +int +cmd_cmdline(globalstate *gstate) + +{ + if (gstate->statics->flags.fullcmds) + { + gstate->pselect.fullcmd = !gstate->pselect.fullcmd; + message_error(" %sisplaying full command lines.", + gstate->pselect.fullcmd ? "D" : "Not d"); + return CMD_REFRESH; + } + message_error(" Full command display not supported."); + return CMD_OK; } +int +cmd_order(globalstate *gstate) + +{ + char tmpbuf[MAX_COLS]; + int i; + + if (gstate->statics->order_names != NULL) + { + message_prompt("Column to sort: "); + if (readline(tmpbuf, sizeof(tmpbuf), No) > 0) + { + if ((i = string_index(tmpbuf, gstate->statics->order_names)) == -1) + { + message_error(" Sort order \"%s\" not recognized", tmpbuf); + } + else + { + gstate->order_index = i; + return CMD_REFRESH; + } + } + } + return CMD_OK; +} + +int +cmd_order_x(globalstate *gstate, char *name, ...) + +{ + va_list ap; + char *p; + char **names; + int i; + + names = gstate->statics->order_names; + if (names != NULL) + { + if ((i = string_index(name, names)) == -1) + { + /* check the alternate list */ + va_start(ap, name); + p = va_arg(ap, char *); + while (p != NULL) + { + if ((i = string_index(p, names)) != -1) + { + gstate->order_index = i; + return CMD_REFRESH; + } + p = va_arg(ap, char *); + } + message_error(" Sort order not recognized"); + } + else + { + gstate->order_index = i; + return CMD_REFRESH; + } + } + return CMD_OK; +} + +int +cmd_order_cpu(globalstate *gstate) + +{ + return cmd_order_x(gstate, "cpu", NULL); +} + +int +cmd_order_pid(globalstate *gstate) + +{ + return cmd_order_x(gstate, "pid", NULL); +} + +int +cmd_order_mem(globalstate *gstate) + +{ + return cmd_order_x(gstate, "mem", "size", NULL); +} + +int +cmd_order_time(globalstate *gstate) + +{ + return cmd_order_x(gstate, "time"); +} + +#ifdef ENABLE_KILL + +int +cmd_kill(globalstate *gstate) + +{ + char tmpbuf[MAX_COLS]; + + message_prompt_plain("kill "); + if (readline(tmpbuf, sizeof(tmpbuf), No) > 0) + { + kill_procs(tmpbuf); + } + return CMD_OK; +} + +int +cmd_renice(globalstate *gstate) + +{ + char tmpbuf[MAX_COLS]; + + message_prompt_plain("renice "); + if (readline(tmpbuf, sizeof(tmpbuf), No) > 0) + { + renice_procs(tmpbuf); + } + return CMD_OK; +} + +#endif + +int +cmd_user(globalstate *gstate) + +{ + char linebuf[MAX_COLS]; + int i; + int ret = CMD_OK; + + message_prompt("Username to show: "); + if (readline(linebuf, sizeof(linebuf), No) > 0) + { + if (linebuf[0] == '+' && + linebuf[1] == '\0') + { + gstate->pselect.uid = -1; + ret = CMD_REFRESH; + } + else if ((i = userid(linebuf)) == -1) + { + message_error(" %s: unknown user", linebuf); + } + else + { + gstate->pselect.uid = i; + ret = CMD_REFRESH; + } + } + return ret; +} + +int +cmd_command(globalstate *gstate) + +{ + char linebuf[MAX_COLS]; + + if (gstate->pselect.command != NULL) + { + free(gstate->pselect.command); + gstate->pselect.command = NULL; + } + + message_prompt("Command to show: "); + if (readline(linebuf, sizeof(linebuf), No) > 0) + { + if (linebuf[0] != '\0') + { + gstate->pselect.command = strdup(linebuf); + } + } + return CMD_REFRESH; +} + +int +cmd_useruid(globalstate *gstate) + +{ + gstate->pselect.usernames = !gstate->pselect.usernames; + display_header(2); + return CMD_REFRESH; +} + +int +cmd_mode(globalstate *gstate) + +{ + if (gstate->statics->modemax <= 1) + { + return CMD_NA; + } + gstate->pselect.mode = (gstate->pselect.mode + 1) % gstate->statics->modemax; + display_header(2); + return CMD_REFRESH; +} + +int +cmd_system(globalstate *gstate) + +{ + gstate->pselect.system = !gstate->pselect.system; + display_header(2); + return CMD_REFRESH; +} + +int +cmd_threads(globalstate *gstate) + +{ + if (gstate->statics->flags.threads) + { + gstate->pselect.threads = !gstate->pselect.threads; + display_header(2); + return CMD_REFRESH; + } + return CMD_NA; +} + +/* forward reference for cmd_help, as it needs to see the command_table */ +int cmd_help(globalstate *gstate); + +/* command table */ +command command_table[] = { + { '\014', cmd_redraw, "redraw screen" }, + { ' ', cmd_update, "update screen" }, + { '?', cmd_help, "help; show this text" }, + { 'h', cmd_help, NULL }, + { 'C', cmd_color, "toggle the use of color" }, + { 'H', cmd_threads, "toggle the display of individual threads" }, + { 't', cmd_threads, NULL }, + { 'M', cmd_order_mem, "sort by memory usage" }, + { 'N', cmd_order_pid, "sort by process id" }, + { 'P', cmd_order_cpu, "sort by CPU usage" }, + { 'S', cmd_system, "toggle the display of system processes" }, + { 'T', cmd_order_time, "sort by CPU time" }, + { 'U', cmd_useruid, "toggle the display of usernames or uids" }, + { 'c', cmd_command, "display processes by command name" }, + { 'd', cmd_displays, "change number of displays to show" }, + { 'f', cmd_cmdline, "toggle the display of full command paths" }, + { 'i', cmd_idle, "toggle the displaying of idle processes" }, + { 'I', cmd_idle, NULL }, +#ifdef ENABLE_KILL + { 'k', cmd_kill, "kill processes; send a signal to a list of processes" }, +#endif + { 'm', cmd_mode, "toggle between display modes" }, + { 'n', cmd_number, "change number of processes to display" }, + { '#', cmd_number, NULL }, + { 'o', cmd_order, "specify sort order (see below)" }, + { 'q', (int (*)(globalstate *))cmd_quit, "quit" }, +#ifdef ENABLE_KILL + { 'r', cmd_renice, "renice a process" }, +#endif + { 's', cmd_delay, "change number of seconds to delay between updates" }, + { 'u', cmd_user, "display processes for only one user (+ selects all users)" }, + { '\0', NULL, NULL }, +}; + +int +cmd_help(globalstate *gstate) + +{ + command *c; + char buf[12]; + char *p; + char *help; + + display_pagerstart(); + + display_pager("Top version %s, %s\n", version_string(), copyright); + display_pager("Platform module: %s\n\n", MODULE); + display_pager("A top users display for Unix\n\n"); + display_pager("These single-character commands are available:\n\n"); + + c = command_table; + while (c->cmd_func != NULL) + { + /* skip null help strings */ + if ((help = c->help) == NULL) + { + continue; + } + + /* translate character in to something readable */ + if (c->ch < ' ') + { + buf[0] = '^'; + buf[1] = c->ch + '@'; + buf[2] = '\0'; + } + else if (c->ch == ' ') + { + strcpy(buf, "<sp>"); + } + else + { + buf[0] = c->ch; + buf[1] = '\0'; + } + + /* if the next command is the same, fold them onto one line */ + if ((c+1)->cmd_func == c->cmd_func) + { + strcat(buf, " or "); + p = buf + strlen(buf); + *p++ = (c+1)->ch; + *p = '\0'; + c++; + } + + display_pager("%-7s - %s\n", buf, help); + c++; + } + + display_pager("\nNot all commands are available on all systems.\n\n"); + display_pager("Available sort orders: %s\n", gstate->order_namelist); + display_pagerend(); + gstate->fulldraw = Yes; + return CMD_REFRESH; +} + +/* + * int command_process(globalstate *gstate, int cmd) + * + * Process the single-character command "cmd". The global state may + * be modified by the command to alter the output. Returns CMD_ERROR + * if there was a serious error that requires an immediate exit, CMD_OK + * to indicate success, CMD_REFRESH to indicate that the screen needs + * to be refreshed immediately, CMD_UNKNOWN when the command is not known, + * and CMD_NA when the command is not available. Error messages for + * CMD_NA and CMD_UNKNOWN must be handled by the caller. + */ + +int +command_process(globalstate *gstate, int cmd) + +{ + command *c; + + c = command_table; + while (c->cmd_func != NULL) + { + if (c->ch == cmd) + { + return (c->cmd_func)(gstate); + } + c++; + } + + return CMD_UNKNOWN; +} |