version 1.13, 2003/06/13 04:29:59 |
version 1.14, 2003/06/13 21:52:24 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/* |
/* |
* Top users/processes display for Unix |
* Top users/processes display for Unix |
|
|
#include "utils.h" |
#include "utils.h" |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
FILE *debug; |
FILE *debug; |
#endif |
#endif |
|
|
static pid_t lmpid = 0; |
static pid_t lmpid = 0; |
static int last_hi = 0; /* used in u_process and u_endscreen */ |
static int last_hi = 0; /* used in u_process and u_endscreen */ |
static int lastline = 0; |
static int lastline = 0; |
static int display_width = MAX_COLS; |
static int display_width = MAX_COLS; |
|
|
static char *cpustates_tag(void); |
static char *cpustates_tag(void); |
static int string_count(char **); |
static int string_count(char **); |
static void summary_format(char *, int *, char **); |
static void summary_format(char *, int *, char **); |
static void line_update(char *, char *, int, int); |
static void line_update(char *, char *, int, int); |
|
|
#define lineindex(l) ((l)*display_width) |
#define lineindex(l) ((l)*display_width) |
|
|
/* things initialized by display_init and used thruout */ |
/* things initialized by display_init and used thruout */ |
|
|
/* buffer of proc information lines for display updating */ |
/* buffer of proc information lines for display updating */ |
char *screenbuf = NULL; |
char *screenbuf = NULL; |
|
|
static char **procstate_names; |
static char **procstate_names; |
static char **cpustate_names; |
static char **cpustate_names; |
static char **memory_names; |
static char **memory_names; |
|
|
static int num_procstates; |
static int num_procstates; |
static int num_cpustates; |
static int num_cpustates; |
static int num_memory; |
static int num_memory; |
|
|
static int *lprocstates; |
static int *lprocstates; |
static int *lcpustates; |
static int *lcpustates; |
static int *lmemory; |
static int *lmemory; |
|
|
static int *cpustate_columns; |
static int *cpustate_columns; |
static int cpustate_total_length; |
static int cpustate_total_length; |
|
|
static enum { OFF, ON, ERASE } header_status = ON; |
static enum { |
|
OFF, ON, ERASE |
|
} header_status = ON; |
|
|
static int string_count(); |
|
static void summary_format(); |
|
static void line_update(); |
|
|
|
int |
int |
display_resize(void) |
display_resize(void) |
{ |
{ |
int display_lines; |
int display_lines; |
|
|
/* first, deallocate any previous buffer that may have been there */ |
/* first, deallocate any previous buffer that may have been there */ |
if (screenbuf != NULL) |
if (screenbuf != NULL) |
{ |
free(screenbuf); |
free(screenbuf); |
|
} |
|
|
|
/* calculate the current dimensions */ |
/* calculate the current dimensions */ |
/* if operating in "dumb" mode, we only need one line */ |
/* if operating in "dumb" mode, we only need one line */ |
display_lines = smart_terminal ? screen_length - Header_lines : 1; |
display_lines = smart_terminal ? screen_length - Header_lines : 1; |
|
|
/* we don't want more than MAX_COLS columns, since the machine-dependent |
/* |
modules make static allocations based on MAX_COLS and we don't want |
* we don't want more than MAX_COLS columns, since the |
to run off the end of their buffers */ |
* machine-dependent modules make static allocations based on |
display_width = screen_width; |
* MAX_COLS and we don't want to run off the end of their buffers |
if (display_width >= MAX_COLS) |
*/ |
{ |
display_width = screen_width; |
display_width = MAX_COLS - 1; |
if (display_width >= MAX_COLS) |
} |
display_width = MAX_COLS - 1; |
|
|
/* now, allocate space for the screen buffer */ |
/* now, allocate space for the screen buffer */ |
screenbuf = (char *)malloc(display_lines * display_width); |
screenbuf = (char *) malloc(display_lines * display_width); |
if (screenbuf == (char *)NULL) |
if (screenbuf == (char *) NULL) |
{ |
return (-1); |
/* oops! */ |
|
return(-1); |
|
} |
|
|
|
/* return number of lines available */ |
/* return number of lines available */ |
/* for dumb terminals, pretend like we can show any amount */ |
/* for dumb terminals, pretend like we can show any amount */ |
return(smart_terminal ? display_lines : Largest); |
return (smart_terminal ? display_lines : Largest); |
} |
} |
|
|
int |
int |
display_init(struct statics *statics) |
display_init(struct statics * statics) |
{ |
{ |
int display_lines; |
int display_lines, *ip, i; |
char **pp; |
char **pp; |
int *ip; |
|
int i; |
|
|
|
/* call resize to do the dirty work */ |
/* call resize to do the dirty work */ |
display_lines = display_resize(); |
display_lines = display_resize(); |
|
|
/* only do the rest if we need to */ |
/* only do the rest if we need to */ |
if (display_lines > -1) |
if (display_lines > -1) { |
{ |
/* save pointers and allocate space for names */ |
/* save pointers and allocate space for names */ |
procstate_names = statics->procstate_names; |
procstate_names = statics->procstate_names; |
num_procstates = string_count(procstate_names); |
num_procstates = string_count(procstate_names); |
lprocstates = (int *) malloc(num_procstates * sizeof(int)); |
lprocstates = (int *)malloc(num_procstates * sizeof(int)); |
|
|
|
cpustate_names = statics->cpustate_names; |
cpustate_names = statics->cpustate_names; |
num_cpustates = string_count(cpustate_names); |
num_cpustates = string_count(cpustate_names); |
lcpustates = (int *)malloc(num_cpustates * sizeof(int)); |
lcpustates = (int *) malloc(num_cpustates * sizeof(int)); |
cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); |
cpustate_columns = (int *) malloc(num_cpustates * sizeof(int)); |
|
|
memory_names = statics->memory_names; |
memory_names = statics->memory_names; |
num_memory = string_count(memory_names); |
num_memory = string_count(memory_names); |
lmemory = (int *)malloc(num_memory * sizeof(int)); |
lmemory = (int *) malloc(num_memory * sizeof(int)); |
|
|
/* calculate starting columns where needed */ |
/* calculate starting columns where needed */ |
cpustate_total_length = 0; |
cpustate_total_length = 0; |
pp = cpustate_names; |
pp = cpustate_names; |
ip = cpustate_columns; |
ip = cpustate_columns; |
while (*pp != NULL) |
while (*pp != NULL) { |
{ |
if ((i = strlen(*pp++)) > 0) { |
if ((i = strlen(*pp++)) > 0) |
*ip++ = cpustate_total_length; |
{ |
cpustate_total_length += i + 8; |
*ip++ = cpustate_total_length; |
} |
cpustate_total_length += i + 8; |
} |
} |
|
} |
} |
} |
/* return number of lines available */ |
|
return (display_lines); |
/* return number of lines available */ |
|
return(display_lines); |
|
} |
} |
|
|
void |
void |
i_loadave(pid_t mpid, double *avenrun) |
i_loadave(pid_t mpid, double *avenrun) |
{ |
{ |
int i; |
int i; |
|
|
/* i_loadave also clears the screen, since it is first */ |
/* i_loadave also clears the screen, since it is first */ |
clear(); |
clear(); |
|
|
/* mpid == -1 implies this system doesn't have an _mpid */ |
/* mpid == -1 implies this system doesn't have an _mpid */ |
if (mpid != -1) |
if (mpid != -1) |
{ |
printf("last pid: %5ld; ", (long) mpid); |
printf("last pid: %5ld; ", (long)mpid); |
|
} |
|
|
|
printf("load averages"); |
printf("load averages"); |
|
|
for (i = 0; i < 3; i++) |
for (i = 0; i < 3; i++) |
{ |
printf("%c %5.2f", i == 0 ? ':' : ',', avenrun[i]); |
printf("%c %5.2f", |
|
i == 0 ? ':' : ',', |
lmpid = mpid; |
avenrun[i]); |
|
} |
|
lmpid = mpid; |
|
} |
} |
|
|
void |
void |
u_loadave(pid_t mpid, double *avenrun) |
u_loadave(pid_t mpid, double *avenrun) |
{ |
{ |
int i; |
int i; |
|
|
if (mpid != -1) |
if (mpid != -1) { |
{ |
/* change screen only when value has really changed */ |
/* change screen only when value has really changed */ |
if (mpid != lmpid) { |
if (mpid != lmpid) |
Move_to(x_lastpid, y_lastpid); |
{ |
printf("%5ld", (long) mpid); |
Move_to(x_lastpid, y_lastpid); |
lmpid = mpid; |
printf("%5ld", (long)mpid); |
} |
lmpid = mpid; |
/* i remembers x coordinate to move to */ |
} |
i = x_loadave; |
|
} else |
|
i = x_loadave_nompid; |
|
|
/* i remembers x coordinate to move to */ |
/* move into position for load averages */ |
i = x_loadave; |
Move_to(i, y_loadave); |
} |
|
else |
|
{ |
|
i = x_loadave_nompid; |
|
} |
|
|
|
/* move into position for load averages */ |
/* display new load averages */ |
Move_to(i, y_loadave); |
/* we should optimize this and only display changes */ |
|
for (i = 0; i < 3; i++) |
/* display new load averages */ |
printf("%s%5.2f", i == 0 ? "" : ", ", avenrun[i]); |
/* we should optimize this and only display changes */ |
|
for (i = 0; i < 3; i++) |
|
{ |
|
printf("%s%5.2f", |
|
i == 0 ? "" : ", ", |
|
avenrun[i]); |
|
} |
|
} |
} |
|
|
|
/* |
|
* Display the current time. |
|
* "ctime" always returns a string that looks like this: |
|
* |
|
* Sun Sep 16 01:03:52 1973 |
|
* 012345678901234567890123 |
|
* 1 2 |
|
* |
|
* We want indices 11 thru 18 (length 8). |
|
*/ |
|
|
void |
void |
i_timeofday(time_t *tod) |
i_timeofday(time_t * tod) |
{ |
{ |
/* |
|
* Display the current time. |
|
* "ctime" always returns a string that looks like this: |
|
* |
|
* Sun Sep 16 01:03:52 1973 |
|
* 012345678901234567890123 |
|
* 1 2 |
|
* |
|
* We want indices 11 thru 18 (length 8). |
|
*/ |
|
|
|
if (smart_terminal) |
if (smart_terminal) { |
{ |
Move_to(screen_width - 8, 0); |
Move_to(screen_width - 8, 0); |
} else { |
} |
if (fputs(" ", stdout) == EOF) |
else |
exit(1); |
{ |
} |
if (fputs(" ", stdout) == EOF) |
|
exit(1); |
|
} |
|
#ifdef DEBUG |
#ifdef DEBUG |
{ |
{ |
char *foo; |
char *foo; |
foo = ctime(tod); |
foo = ctime(tod); |
if (fputs(foo, stdout) == EOF) |
if (fputs(foo, stdout) == EOF) |
exit(1); |
exit(1); |
} |
} |
#endif |
#endif |
printf("%-8.8s\n", &(ctime(tod)[11])); |
printf("%-8.8s\n", &(ctime(tod)[11])); |
lastline = 1; |
lastline = 1; |
} |
} |
|
|
static int ltotal = 0; |
static int ltotal = 0; |
static char procstates_buffer[128]; |
static char procstates_buffer[128]; |
|
|
/* |
/* |
* *_procstates(total, brkdn, names) - print the process summary line |
* *_procstates(total, brkdn, names) - print the process summary line |
|
|
* Assumptions: cursor is at the beginning of the line on entry |
* Assumptions: cursor is at the beginning of the line on entry |
* lastline is valid |
* lastline is valid |
*/ |
*/ |
|
|
void |
void |
i_procstates(int total, int *brkdn) |
i_procstates(int total, int *brkdn) |
{ |
{ |
int i; |
int i; |
|
|
/* write current number of processes and remember the value */ |
/* write current number of processes and remember the value */ |
printf("%d processes:", total); |
printf("%d processes:", total); |
ltotal = total; |
ltotal = total; |
|
|
/* put out enough spaces to get to column 15 */ |
/* put out enough spaces to get to column 15 */ |
i = digits(total); |
i = digits(total); |
while (i++ < 4) |
while (i++ < 4) { |
{ |
if (putchar(' ') == EOF) |
if (putchar(' ') == EOF) |
exit(1); |
|
} |
|
|
|
/* format and print the process state summary */ |
|
summary_format(procstates_buffer, brkdn, procstate_names); |
|
if (fputs(procstates_buffer, stdout) == EOF) |
exit(1); |
exit(1); |
} |
|
|
|
/* format and print the process state summary */ |
/* save the numbers for next time */ |
summary_format(procstates_buffer, brkdn, procstate_names); |
memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); |
if (fputs(procstates_buffer, stdout) == EOF) |
|
exit(1); |
|
|
|
/* save the numbers for next time */ |
|
memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); |
|
} |
} |
|
|
void |
void |
u_procstates(int total, int *brkdn) |
u_procstates(int total, int *brkdn) |
{ |
{ |
static char new[128]; |
static char new[128]; |
int i; |
int i; |
|
|
/* update number of processes only if it has changed */ |
/* update number of processes only if it has changed */ |
if (ltotal != total) |
if (ltotal != total) { |
{ |
/* move and overwrite */ |
/* move and overwrite */ |
|
#if (x_procstate == 0) |
#if (x_procstate == 0) |
Move_to(x_procstate, y_procstate); |
Move_to(x_procstate, y_procstate); |
#else |
#else |
/* cursor is already there...no motion needed */ |
/* cursor is already there...no motion needed */ |
/* assert(lastline == 1); */ |
/* assert(lastline == 1); */ |
#endif |
#endif |
printf("%d", total); |
printf("%d", total); |
|
|
/* if number of digits differs, rewrite the label */ |
/* if number of digits differs, rewrite the label */ |
if (digits(total) != digits(ltotal)) |
if (digits(total) != digits(ltotal)) { |
{ |
if (fputs(" processes:", stdout) == EOF) |
if (fputs(" processes:", stdout) == EOF) |
exit(1); |
exit(1); |
/* put out enough spaces to get to column 15 */ |
/* put out enough spaces to get to column 15 */ |
i = digits(total); |
i = digits(total); |
while (i++ < 4) { |
while (i++ < 4) |
if (putchar(' ') == EOF) |
{ |
exit(1); |
if (putchar(' ') == EOF) |
} |
exit(1); |
/* cursor may end up right where we want it!!! */ |
} |
} |
/* cursor may end up right where we want it!!! */ |
/* save new total */ |
|
ltotal = total; |
} |
} |
|
/* see if any of the state numbers has changed */ |
/* save new total */ |
if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) { |
ltotal = total; |
/* format and update the line */ |
} |
summary_format(new, brkdn, procstate_names); |
|
line_update(procstates_buffer, new, x_brkdn, y_brkdn); |
/* see if any of the state numbers has changed */ |
memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); |
if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) |
} |
{ |
|
/* format and update the line */ |
|
summary_format(new, brkdn, procstate_names); |
|
line_update(procstates_buffer, new, x_brkdn, y_brkdn); |
|
memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); |
|
} |
|
} |
} |
|
|
/* |
/* |
|
|
* Assumptions: cursor is on the PREVIOUS line |
* Assumptions: cursor is on the PREVIOUS line |
*/ |
*/ |
|
|
static int cpustates_column; |
static int cpustates_column; |
|
|
/* cpustates_tag() calculates the correct tag to use to label the line */ |
/* cpustates_tag() calculates the correct tag to use to label the line */ |
|
|
static char * |
static char * |
cpustates_tag(void) |
cpustates_tag(void) |
{ |
{ |
char *use; |
static char *short_tag = "CPU: "; |
|
static char *long_tag = "CPU states: "; |
|
char *use; |
|
|
static char *short_tag = "CPU: "; |
/* |
static char *long_tag = "CPU states: "; |
* if length + strlen(long_tag) >= screen_width, then we have to use |
|
* the shorter tag (we subtract 2 to account for ": ") |
|
*/ |
|
if (cpustate_total_length + (int) strlen(long_tag) - 2 >= screen_width) |
|
use = short_tag; |
|
else |
|
use = long_tag; |
|
|
/* if length + strlen(long_tag) >= screen_width, then we have to |
/* set cpustates_column accordingly then return result */ |
use the shorter tag (we subtract 2 to account for ": ") */ |
cpustates_column = strlen(use); |
if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) |
return (use); |
{ |
|
use = short_tag; |
|
} |
|
else |
|
{ |
|
use = long_tag; |
|
} |
|
|
|
/* set cpustates_column accordingly then return result */ |
|
cpustates_column = strlen(use); |
|
return(use); |
|
} |
} |
|
|
void |
void |
i_cpustates(int *states) |
i_cpustates(int *states) |
{ |
{ |
int i = 0; |
int i = 0, value; |
int value; |
char **names = cpustate_names, *thisname; |
char **names = cpustate_names; |
|
char *thisname; |
|
|
|
/* print tag and bump lastline */ |
/* print tag and bump lastline */ |
printf("\n%s", cpustates_tag()); |
printf("\n%s", cpustates_tag()); |
lastline++; |
lastline++; |
|
|
/* now walk thru the names and print the line */ |
/* now walk thru the names and print the line */ |
while ((thisname = *names++) != NULL) |
while ((thisname = *names++) != NULL) { |
{ |
if (*thisname != '\0') { |
if (*thisname != '\0') |
/* retrieve the value and remember it */ |
{ |
value = *states++; |
/* retrieve the value and remember it */ |
|
value = *states++; |
|
|
|
/* if percentage is >= 1000, print it as 100% */ |
/* if percentage is >= 1000, print it as 100% */ |
printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), |
printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), |
i++ == 0 ? "" : ", ", |
i++ == 0 ? "" : ", ", |
((float)value)/10., |
((float) value) / 10., |
thisname); |
thisname); |
|
} |
} |
} |
} |
|
|
|
/* copy over values into "last" array */ |
/* copy over values into "last" array */ |
memcpy(lcpustates, states, num_cpustates * sizeof(int)); |
memcpy(lcpustates, states, num_cpustates * sizeof(int)); |
} |
} |
|
|
void |
void |
u_cpustates(int *states) |
u_cpustates(int *states) |
{ |
{ |
int value; |
char **names = cpustate_names, *thisname; |
char **names = cpustate_names; |
int value, *lp, *colp; |
char *thisname; |
|
int *lp; |
|
int *colp; |
|
|
|
Move_to(cpustates_column, y_cpustates); |
Move_to(cpustates_column, y_cpustates); |
lastline = y_cpustates; |
lastline = y_cpustates; |
lp = lcpustates; |
lp = lcpustates; |
colp = cpustate_columns; |
colp = cpustate_columns; |
|
|
/* we could be much more optimal about this */ |
/* we could be much more optimal about this */ |
while ((thisname = *names++) != NULL) |
while ((thisname = *names++) != NULL) { |
{ |
if (*thisname != '\0') { |
if (*thisname != '\0') |
/* did the value change since last time? */ |
{ |
if (*lp != *states) { |
/* did the value change since last time? */ |
/* yes, move and change */ |
if (*lp != *states) |
Move_to(cpustates_column + *colp, y_cpustates); |
{ |
lastline = y_cpustates; |
/* yes, move and change */ |
|
Move_to(cpustates_column + *colp, y_cpustates); |
|
lastline = y_cpustates; |
|
|
|
/* retrieve value and remember it */ |
/* retrieve value and remember it */ |
value = *states; |
value = *states; |
|
|
/* if percentage is >= 1000, print it as 100% */ |
/* if percentage is >= 1000, print it as 100% */ |
printf((value >= 1000 ? "%4.0f" : "%4.1f"), |
printf((value >= 1000 ? "%4.0f" : "%4.1f"), |
((double)value)/10.); |
((double) value) / 10.); |
|
|
/* remember it for next time */ |
/* remember it for next time */ |
*lp = *states; |
*lp = *states; |
} |
} |
|
} |
|
/* increment and move on */ |
|
lp++; |
|
states++; |
|
colp++; |
} |
} |
|
|
/* increment and move on */ |
|
lp++; |
|
states++; |
|
colp++; |
|
} |
|
} |
} |
|
|
void |
void |
z_cpustates(void) |
z_cpustates(void) |
{ |
{ |
int i = 0; |
char **names = cpustate_names, *thisname; |
char **names = cpustate_names; |
int i = 0, *lp; |
char *thisname; |
|
int *lp; |
|
|
|
/* show tag and bump lastline */ |
/* show tag and bump lastline */ |
printf("\n%s", cpustates_tag()); |
printf("\n%s", cpustates_tag()); |
lastline++; |
lastline++; |
|
|
while ((thisname = *names++) != NULL) |
while ((thisname = *names++) != NULL) { |
{ |
if (*thisname != '\0') |
if (*thisname != '\0') |
printf("%s %% %s", i++ == 0 ? "" : ", ", thisname); |
{ |
|
printf("%s %% %s", i++ == 0 ? "" : ", ", thisname); |
|
} |
} |
} |
|
|
|
/* fill the "last" array with all -1s, to insure correct updating */ |
/* fill the "last" array with all -1s, to insure correct updating */ |
lp = lcpustates; |
lp = lcpustates; |
i = num_cpustates; |
i = num_cpustates; |
while (--i >= 0) |
while (--i >= 0) |
{ |
*lp++ = -1; |
*lp++ = -1; |
|
} |
|
} |
} |
|
|
|
static char memory_buffer[MAX_COLS]; |
|
|
/* |
/* |
* *_memory(stats) - print "Memory: " followed by the memory summary string |
* *_memory(stats) - print "Memory: " followed by the memory summary string |
* |
* |
* Assumptions: cursor is on "lastline" |
* Assumptions: cursor is on "lastline" |
* for i_memory ONLY: cursor is on the previous line |
* for i_memory ONLY: cursor is on the previous line |
*/ |
*/ |
|
|
static char memory_buffer[MAX_COLS]; |
|
|
|
void |
void |
i_memory(int *stats) |
i_memory(int *stats) |
{ |
{ |
if (fputs("\nMemory: ", stdout) == EOF) |
if (fputs("\nMemory: ", stdout) == EOF) |
exit(1); |
exit(1); |
lastline++; |
lastline++; |
|
|
/* format and print the memory summary */ |
/* format and print the memory summary */ |
summary_format(memory_buffer, stats, memory_names); |
summary_format(memory_buffer, stats, memory_names); |
if (fputs(memory_buffer, stdout) == EOF) |
if (fputs(memory_buffer, stdout) == EOF) |
exit(1); |
exit(1); |
} |
} |
|
|
void |
void |
u_memory(int *stats) |
u_memory(int *stats) |
{ |
{ |
static char new[MAX_COLS]; |
static char new[MAX_COLS]; |
|
|
/* format the new line */ |
/* format the new line */ |
summary_format(new, stats, memory_names); |
summary_format(new, stats, memory_names); |
line_update(memory_buffer, new, x_mem, y_mem); |
line_update(memory_buffer, new, x_mem, y_mem); |
} |
} |
|
|
/* |
/* |
|
|
* respect to screen updates). |
* respect to screen updates). |
*/ |
*/ |
|
|
static char next_msg[MAX_COLS + 5]; |
static char next_msg[MAX_COLS + 5]; |
static int msglen = 0; |
static int msglen = 0; |
/* Invariant: msglen is always the length of the message currently displayed |
/* |
on the screen (even when next_msg doesn't contain that message). */ |
* Invariant: msglen is always the length of the message currently displayed |
|
* on the screen (even when next_msg doesn't contain that message). |
|
*/ |
|
|
void |
void |
i_message(void) |
i_message(void) |
{ |
{ |
while (lastline < y_message) |
while (lastline < y_message) { |
{ |
if (fputc('\n', stdout) == EOF) |
if (fputc('\n', stdout) == EOF) |
exit(1); |
exit(1); |
lastline++; |
lastline++; |
} |
} |
if (next_msg[0] != '\0') { |
if (next_msg[0] != '\0') |
standout(next_msg); |
{ |
msglen = strlen(next_msg); |
standout(next_msg); |
next_msg[0] = '\0'; |
msglen = strlen(next_msg); |
} else if (msglen > 0) { |
next_msg[0] = '\0'; |
(void) clear_eol(msglen); |
} |
msglen = 0; |
else if (msglen > 0) |
} |
{ |
|
(void) clear_eol(msglen); |
|
msglen = 0; |
|
} |
|
} |
} |
|
|
void |
void |
u_message(void) |
u_message(void) |
{ |
{ |
i_message(); |
i_message(); |
} |
} |
|
|
static int header_length; |
static int header_length; |
|
|
/* |
/* |
* *_header(text) - print the header for the process area |
* *_header(text) - print the header for the process area |
|
|
void |
void |
i_header(char *text) |
i_header(char *text) |
{ |
{ |
header_length = strlen(text); |
header_length = strlen(text); |
if (header_status == ON) |
if (header_status == ON) { |
{ |
if (putchar('\n') == EOF) |
if (putchar('\n') == EOF) |
exit(1); |
exit(1); |
if (fputs(text, stdout) == EOF) |
if (fputs(text, stdout) == EOF) |
exit(1); |
exit(1); |
lastline++; |
lastline++; |
} else if (header_status == ERASE) { |
} |
header_status = OFF; |
else if (header_status == ERASE) |
} |
{ |
|
header_status = OFF; |
|
} |
|
} |
} |
|
|
/*ARGSUSED*/ |
/* ARGSUSED */ |
void |
void |
u_header(char *text) |
u_header(char *text) |
{ |
{ |
if (header_status == ERASE) |
if (header_status == ERASE) { |
{ |
if (putchar('\n') == EOF) |
if (putchar('\n') == EOF) |
exit(1); |
exit(1); |
lastline++; |
lastline++; |
clear_eol(header_length); |
clear_eol(header_length); |
header_status = OFF; |
header_status = OFF; |
} |
} |
|
} |
} |
|
|
/* |
/* |
|
|
void |
void |
i_process(int line, char *thisline) |
i_process(int line, char *thisline) |
{ |
{ |
char *p; |
char *p, *base; |
char *base; |
|
|
|
/* make sure we are on the correct line */ |
/* make sure we are on the correct line */ |
while (lastline < y_procs + line) |
while (lastline < y_procs + line) { |
{ |
if (putchar('\n') == EOF) |
if (putchar('\n') == EOF) |
exit(1); |
exit(1); |
lastline++; |
lastline++; |
} |
} |
|
|
|
/* truncate the line to conform to our current screen width */ |
/* truncate the line to conform to our current screen width */ |
thisline[display_width] = '\0'; |
thisline[display_width] = '\0'; |
|
|
/* write the line out */ |
/* write the line out */ |
if (fputs(thisline, stdout) == EOF) |
if (fputs(thisline, stdout) == EOF) |
exit(1); |
exit(1); |
|
|
/* copy it in to our buffer */ |
/* copy it in to our buffer */ |
base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; |
base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; |
p = strecpy(base, thisline); |
p = strecpy(base, thisline); |
|
|
/* zero fill the rest of it */ |
/* zero fill the rest of it */ |
memset(p, 0, display_width - (p - base)); |
memset(p, 0, display_width - (p - base)); |
} |
} |
|
|
void |
void |
u_process(int linenum, char *linebuf) |
u_process(int linenum, char *linebuf) |
{ |
{ |
char *optr; |
int screen_line = linenum + Header_lines; |
int screen_line = linenum + Header_lines; |
char *optr, *bufferline; |
char *bufferline; |
|
|
|
/* remember a pointer to the current line in the screen buffer */ |
/* remember a pointer to the current line in the screen buffer */ |
bufferline = &screenbuf[lineindex(linenum)]; |
bufferline = &screenbuf[lineindex(linenum)]; |
|
|
/* truncate the line to conform to our current screen width */ |
/* truncate the line to conform to our current screen width */ |
linebuf[display_width] = '\0'; |
linebuf[display_width] = '\0'; |
|
|
/* is line higher than we went on the last display? */ |
/* is line higher than we went on the last display? */ |
if (linenum >= last_hi) |
if (linenum >= last_hi) { |
{ |
/* yes, just ignore screenbuf and write it out directly */ |
/* yes, just ignore screenbuf and write it out directly */ |
/* get positioned on the correct line */ |
/* get positioned on the correct line */ |
if (screen_line - lastline == 1) { |
if (screen_line - lastline == 1) |
if (putchar('\n') == EOF) |
{ |
exit(1); |
if (putchar('\n') == EOF) |
lastline++; |
exit(1); |
} else { |
lastline++; |
Move_to(0, screen_line); |
} |
lastline = screen_line; |
else |
} |
{ |
|
Move_to(0, screen_line); |
|
lastline = screen_line; |
|
} |
|
|
|
/* now write the line */ |
/* now write the line */ |
if (fputs(linebuf, stdout) == EOF) |
if (fputs(linebuf, stdout) == EOF) |
exit(1); |
exit(1); |
|
|
/* copy it in to the buffer */ |
/* copy it in to the buffer */ |
optr = strecpy(bufferline, linebuf); |
optr = strecpy(bufferline, linebuf); |
|
|
/* zero fill the rest of it */ |
/* zero fill the rest of it */ |
memset(optr, 0, display_width - (optr - bufferline)); |
memset(optr, 0, display_width - (optr - bufferline)); |
} |
} else { |
else |
line_update(bufferline, linebuf, 0, linenum + Header_lines); |
{ |
} |
line_update(bufferline, linebuf, 0, linenum + Header_lines); |
|
} |
|
} |
} |
|
|
void |
void |
u_endscreen(int hi) |
u_endscreen(int hi) |
{ |
{ |
int screen_line = hi + Header_lines; |
int screen_line = hi + Header_lines, i; |
int i; |
|
|
|
if (smart_terminal) |
if (smart_terminal) { |
{ |
if (hi < last_hi) { |
if (hi < last_hi) |
/* need to blank the remainder of the screen */ |
{ |
/* |
/* need to blank the remainder of the screen */ |
* but only if there is any screen left below this |
/* but only if there is any screen left below this line */ |
* line |
if (lastline + 1 < screen_length) |
*/ |
{ |
if (lastline + 1 < screen_length) { |
/* efficiently move to the end of currently displayed info */ |
/* |
if (screen_line - lastline < 5) |
* efficiently move to the end of currently |
{ |
* displayed info |
while (lastline < screen_line) |
*/ |
{ |
if (screen_line - lastline < 5) { |
if (putchar('\n') == EOF) |
while (lastline < screen_line) { |
exit(1); |
if (putchar('\n') == EOF) |
lastline++; |
exit(1); |
} |
lastline++; |
} |
} |
else |
} else { |
{ |
Move_to(0, screen_line); |
Move_to(0, screen_line); |
lastline = screen_line; |
lastline = screen_line; |
} |
} |
|
|
|
if (clear_to_end) |
if (clear_to_end) { |
{ |
/* we can do this the easy way */ |
/* we can do this the easy way */ |
putcap(clear_to_end); |
putcap(clear_to_end); |
} else { |
|
/* use clear_eol on each line */ |
|
i = hi; |
|
while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) { |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
} |
|
} |
|
} |
} |
} |
else |
last_hi = hi; |
{ |
|
/* use clear_eol on each line */ |
|
i = hi; |
|
while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) |
|
{ |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
} |
|
} |
|
} |
|
} |
|
last_hi = hi; |
|
|
|
/* move the cursor to a pleasant place */ |
/* move the cursor to a pleasant place */ |
Move_to(x_idlecursor, y_idlecursor); |
Move_to(x_idlecursor, y_idlecursor); |
lastline = y_idlecursor; |
lastline = y_idlecursor; |
} |
} else { |
else |
/* |
{ |
* separate this display from the next with some vertical |
/* separate this display from the next with some vertical room */ |
* room |
if (fputs("\n\n", stdout) == EOF) |
*/ |
exit(1); |
if (fputs("\n\n", stdout) == EOF) |
} |
exit(1); |
|
} |
} |
} |
|
|
void |
void |
display_header(int t) |
display_header(int t) |
{ |
{ |
if (t) |
if (t) { |
{ |
header_status = ON; |
header_status = ON; |
} else if (header_status == ON) { |
} |
header_status = ERASE; |
else if (header_status == ON) |
} |
{ |
|
header_status = ERASE; |
|
} |
|
} |
} |
|
|
void |
void |
new_message(int type, const char *msgfmt, ...) |
new_message(int type, const char *msgfmt,...) |
{ |
{ |
int i; |
va_list ap; |
va_list ap; |
int i; |
|
|
va_start(ap, msgfmt); |
va_start(ap, msgfmt); |
/* first, format the message */ |
/* first, format the message */ |
vsnprintf(next_msg, sizeof(next_msg), msgfmt, ap); |
vsnprintf(next_msg, sizeof(next_msg), msgfmt, ap); |
va_end(ap); |
va_end(ap); |
|
|
if (msglen > 0) |
if (msglen > 0) { |
{ |
/* message there already -- can we clear it? */ |
/* message there already -- can we clear it? */ |
if (!overstrike) { |
if (!overstrike) |
/* yes -- write it and clear to end */ |
{ |
i = strlen(next_msg); |
/* yes -- write it and clear to end */ |
if ((type & MT_delayed) == 0) { |
i = strlen(next_msg); |
if (type & MT_standout) |
if ((type & MT_delayed) == 0) |
standout(next_msg); |
{ |
else { |
if (type & MT_standout) |
if (fputs(next_msg, stdout) == EOF) |
standout(next_msg); |
exit(1); |
else { |
} |
if (fputs(next_msg, stdout) == EOF) |
(void) clear_eol(msglen - i); |
exit(1); |
msglen = i; |
|
next_msg[0] = '\0'; |
|
} |
} |
} |
(void) clear_eol(msglen - i); |
} else { |
msglen = i; |
if ((type & MT_delayed) == 0) { |
next_msg[0] = '\0'; |
if (type & MT_standout) |
} |
standout(next_msg); |
|
else { |
|
if (fputs(next_msg, stdout) == EOF) |
|
exit(1); |
|
} |
|
msglen = strlen(next_msg); |
|
next_msg[0] = '\0'; |
|
} |
} |
} |
} |
|
else |
|
{ |
|
if ((type & MT_delayed) == 0) |
|
{ |
|
if (type & MT_standout) |
|
standout(next_msg); |
|
else { |
|
if (fputs(next_msg, stdout) == EOF) |
|
exit(1); |
|
} |
|
msglen = strlen(next_msg); |
|
next_msg[0] = '\0'; |
|
} |
|
} |
|
} |
} |
|
|
void |
void |
clear_message(void) |
clear_message(void) |
{ |
{ |
if (clear_eol(msglen) == 1) |
if (clear_eol(msglen) == 1) { |
{ |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
} |
} |
|
} |
} |
|
|
int |
int |
readline(char *buffer, int size, int numeric) |
readline(char *buffer, int size, int numeric) |
{ |
{ |
char *ptr = buffer; |
char *ptr = buffer, ch, cnt = 0, maxcnt = 0; |
char ch; |
|
char cnt = 0; |
|
char maxcnt = 0; |
|
|
|
/* allow room for null terminator */ |
/* allow room for null terminator */ |
size -= 1; |
size -= 1; |
|
|
/* read loop */ |
/* read loop */ |
while ((fflush(stdout), read(0, ptr, 1) > 0)) |
while ((fflush(stdout), read(0, ptr, 1) > 0)) { |
{ |
/* newline means we are done */ |
/* newline means we are done */ |
if ((ch = *ptr) == '\n') |
if ((ch = *ptr) == '\n') |
break; |
{ |
|
break; |
|
} |
|
|
|
/* handle special editing characters */ |
/* handle special editing characters */ |
if (ch == ch_kill) |
if (ch == ch_kill) { |
{ |
/* kill line -- account for overstriking */ |
/* kill line -- account for overstriking */ |
if (overstrike) |
if (overstrike) |
msglen += maxcnt; |
{ |
|
msglen += maxcnt; |
|
} |
|
|
|
/* return null string */ |
/* return null string */ |
*buffer = '\0'; |
*buffer = '\0'; |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
return(-1); |
return (-1); |
|
} else if (ch == ch_erase) { |
|
/* erase previous character */ |
|
if (cnt <= 0) { |
|
/* none to erase! */ |
|
if (putchar('\7') == EOF) |
|
exit(1); |
|
} else { |
|
if (fputs("\b \b", stdout) == EOF) |
|
exit(1); |
|
ptr--; |
|
cnt--; |
|
} |
|
} |
|
/* check for character validity and buffer overflow */ |
|
else if (cnt == size || (numeric && !isdigit(ch)) || |
|
!isprint(ch)) { |
|
/* not legal */ |
|
if (putchar('\7') == EOF) |
|
exit(1); |
|
} else { |
|
/* echo it and store it in the buffer */ |
|
if (putchar(ch) == EOF) |
|
exit(1); |
|
ptr++; |
|
cnt++; |
|
if (cnt > maxcnt) |
|
maxcnt = cnt; |
|
} |
} |
} |
else if (ch == ch_erase) |
|
{ |
|
/* erase previous character */ |
|
if (cnt <= 0) |
|
{ |
|
/* none to erase! */ |
|
if (putchar('\7') == EOF) |
|
exit(1); |
|
} |
|
else |
|
{ |
|
if (fputs("\b \b", stdout) == EOF) |
|
exit(1); |
|
ptr--; |
|
cnt--; |
|
} |
|
} |
|
/* check for character validity and buffer overflow */ |
|
else if (cnt == size || (numeric && !isdigit(ch)) || |
|
!isprint(ch)) |
|
{ |
|
/* not legal */ |
|
if (putchar('\7') == EOF) |
|
exit(1); |
|
} |
|
else |
|
{ |
|
/* echo it and store it in the buffer */ |
|
if (putchar(ch) == EOF) |
|
exit(1); |
|
ptr++; |
|
cnt++; |
|
if (cnt > maxcnt) |
|
{ |
|
maxcnt = cnt; |
|
} |
|
} |
|
} |
|
|
|
/* all done -- null terminate the string */ |
/* all done -- null terminate the string */ |
*ptr = '\0'; |
*ptr = '\0'; |
|
|
/* account for the extra characters in the message area */ |
/* account for the extra characters in the message area */ |
/* (if terminal overstrikes, remember the furthest they went) */ |
/* (if terminal overstrikes, remember the furthest they went) */ |
msglen += overstrike ? maxcnt : cnt; |
msglen += overstrike ? maxcnt : cnt; |
|
|
/* return either inputted number or string length */ |
/* return either inputted number or string length */ |
if (putchar('\r') == EOF) |
if (putchar('\r') == EOF) |
exit(1); |
exit(1); |
return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); |
return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); |
} |
} |
|
|
/* internal support routines */ |
/* internal support routines */ |
|
|
static int |
static int |
string_count(char **pp) |
string_count(char **pp) |
{ |
{ |
int cnt; |
int cnt; |
|
|
cnt = 0; |
cnt = 0; |
while (*pp++ != NULL) |
while (*pp++ != NULL) |
{ |
cnt++; |
cnt++; |
return (cnt); |
} |
|
return(cnt); |
|
} |
} |
|
|
static void |
static void |
summary_format(char *str, int *numbers, char **names) |
summary_format(char *str, int *numbers, char **names) |
{ |
{ |
char *p; |
char *p, *thisname; |
int num; |
int num; |
char *thisname; |
|
|
|
/* format each number followed by its string */ |
/* format each number followed by its string */ |
p = str; |
p = str; |
while ((thisname = *names++) != NULL) |
while ((thisname = *names++) != NULL) { |
{ |
/* get the number to format */ |
/* get the number to format */ |
num = *numbers++; |
num = *numbers++; |
|
|
|
if (num >= 0) |
if (num >= 0) { |
{ |
/* is this number in kilobytes? */ |
/* is this number in kilobytes? */ |
if (thisname[0] == 'K') { |
if (thisname[0] == 'K') |
/* yes: format it as a memory value */ |
{ |
p = strecpy(p, format_k(num)); |
/* yes: format it as a memory value */ |
|
p = strecpy(p, format_k(num)); |
|
|
|
/* skip over the K, since it was included by format_k */ |
/* |
p = strecpy(p, thisname+1); |
* skip over the K, since it was included by |
} |
* format_k |
else if (num > 0) |
*/ |
{ |
p = strecpy(p, thisname + 1); |
p = strecpy(p, itoa(num)); |
} else if (num > 0) { |
p = strecpy(p, thisname); |
p = strecpy(p, itoa(num)); |
} |
p = strecpy(p, thisname); |
|
} |
|
} |
|
/* ignore negative numbers, but display corresponding string */ |
|
else |
|
p = strecpy(p, thisname); |
} |
} |
|
|
/* ignore negative numbers, but display corresponding string */ |
/* if the last two characters in the string are ", ", delete them */ |
else |
p -= 2; |
{ |
if (p >= str && p[0] == ',' && p[1] == ' ') |
p = strecpy(p, thisname); |
*p = '\0'; |
} |
|
} |
|
|
|
/* if the last two characters in the string are ", ", delete them */ |
|
p -= 2; |
|
if (p >= str && p[0] == ',' && p[1] == ' ') |
|
{ |
|
*p = '\0'; |
|
} |
|
} |
} |
|
|
static void |
static void |
line_update(char *old, char *new, int start, int line) |
line_update(char *old, char *new, int start, int line) |
{ |
{ |
int ch; |
int ch, diff, newcol = start + 1, lastcol = start; |
int diff; |
char cursor_on_line = No, *current; |
int newcol = start + 1; |
|
int lastcol = start; |
|
char cursor_on_line = No; |
|
char *current; |
|
|
|
/* compare the two strings and only rewrite what has changed */ |
/* compare the two strings and only rewrite what has changed */ |
current = old; |
current = old; |
#ifdef DEBUG |
#ifdef DEBUG |
fprintf(debug, "line_update, starting at %d\n", start); |
fprintf(debug, "line_update, starting at %d\n", start); |
fputs(old, debug); |
fputs(old, debug); |
fputc('\n', debug); |
fputc('\n', debug); |
fputs(new, debug); |
fputs(new, debug); |
fputs("\n-\n", debug); |
fputs("\n-\n", debug); |
#endif |
#endif |
|
|
/* start things off on the right foot */ |
/* start things off on the right foot */ |
/* this is to make sure the invariants get set up right */ |
/* this is to make sure the invariants get set up right */ |
if ((ch = *new++) != *old) |
if ((ch = *new++) != *old) { |
{ |
if (line - lastline == 1 && start == 0) { |
if (line - lastline == 1 && start == 0) |
if (putchar('\n') == EOF) |
{ |
exit(1); |
if (putchar('\n') == EOF) |
} else |
exit(1); |
Move_to(start, line); |
} |
|
else |
cursor_on_line = Yes; |
{ |
|
Move_to(start, line); |
|
} |
|
cursor_on_line = Yes; |
|
if (putchar(ch) == EOF) |
|
exit(1); |
|
*old = ch; |
|
lastcol = 1; |
|
} |
|
old++; |
|
|
|
/* |
|
* main loop -- check each character. If the old and new aren't the |
|
* same, then update the display. When the distance from the |
|
* current cursor position to the new change is small enough, |
|
* the characters that belong there are written to move the |
|
* cursor over. |
|
* |
|
* Invariants: |
|
* lastcol is the column where the cursor currently is sitting |
|
* (always one beyond the end of the last mismatch). |
|
*/ |
|
do /* yes, a do...while */ |
|
{ |
|
if ((ch = *new++) != *old) |
|
{ |
|
/* new character is different from old */ |
|
/* make sure the cursor is on top of this character */ |
|
diff = newcol - lastcol; |
|
if (diff > 0) |
|
{ |
|
/* some motion is required--figure out which is shorter */ |
|
if (diff < 6 && cursor_on_line) |
|
{ |
|
/* overwrite old stuff--get it out of the old buffer */ |
|
printf("%.*s", diff, ¤t[lastcol-start]); |
|
} |
|
else |
|
{ |
|
/* use cursor addressing */ |
|
Move_to(newcol, line); |
|
cursor_on_line = Yes; |
|
} |
|
/* remember where the cursor is */ |
|
lastcol = newcol + 1; |
|
} |
|
else |
|
{ |
|
/* already there, update position */ |
|
lastcol++; |
|
} |
|
|
|
/* write what we need to */ |
|
if (ch == '\0') |
|
{ |
|
/* at the end--terminate with a clear-to-end-of-line */ |
|
(void) clear_eol(strlen(old)); |
|
} |
|
else |
|
{ |
|
/* write the new character */ |
|
if (putchar(ch) == EOF) |
if (putchar(ch) == EOF) |
exit(1); |
exit(1); |
} |
*old = ch; |
/* put the new character in the screen buffer */ |
lastcol = 1; |
*old = ch; |
|
} |
} |
|
|
/* update working column and screen buffer pointer */ |
|
newcol++; |
|
old++; |
old++; |
|
|
} while (ch != '\0'); |
|
|
|
/* zero out the rest of the line buffer -- MUST BE DONE! */ |
/* |
diff = display_width - newcol; |
* main loop -- check each character. If the old and new aren't the |
if (diff > 0) |
* same, then update the display. When the distance from the |
{ |
* current cursor position to the new change is small enough, |
memset(old, 0, diff); |
* the characters that belong there are written to move the |
} |
* cursor over. |
|
* |
|
* Invariants: |
|
* lastcol is the column where the cursor currently is sitting |
|
* (always one beyond the end of the last mismatch). |
|
*/ |
|
do { |
|
if ((ch = *new++) != *old) { |
|
/* new character is different from old */ |
|
/* make sure the cursor is on top of this character */ |
|
diff = newcol - lastcol; |
|
if (diff > 0) { |
|
/* |
|
* some motion is required--figure out which |
|
* is shorter |
|
*/ |
|
if (diff < 6 && cursor_on_line) { |
|
/* |
|
* overwrite old stuff--get it out of |
|
* the old buffer |
|
*/ |
|
printf("%.*s", diff, ¤t[lastcol - start]); |
|
} else { |
|
/* use cursor addressing */ |
|
Move_to(newcol, line); |
|
cursor_on_line = Yes; |
|
} |
|
/* remember where the cursor is */ |
|
lastcol = newcol + 1; |
|
} else { |
|
/* already there, update position */ |
|
lastcol++; |
|
} |
|
|
/* remember where the current line is */ |
/* write what we need to */ |
if (cursor_on_line) |
if (ch == '\0') { |
{ |
/* |
lastline = line; |
* at the end--terminate with a |
} |
* clear-to-end-of-line |
|
*/ |
|
(void) clear_eol(strlen(old)); |
|
} else { |
|
/* write the new character */ |
|
if (putchar(ch) == EOF) |
|
exit(1); |
|
} |
|
/* put the new character in the screen buffer */ |
|
*old = ch; |
|
} |
|
/* update working column and screen buffer pointer */ |
|
newcol++; |
|
old++; |
|
} while (ch != '\0'); |
|
|
|
/* zero out the rest of the line buffer -- MUST BE DONE! */ |
|
diff = display_width - newcol; |
|
if (diff > 0) |
|
memset(old, 0, diff); |
|
|
|
/* remember where the current line is */ |
|
if (cursor_on_line) |
|
lastline = line; |
} |
} |
|
|
/* |
/* |
|
|
* characters into '?'. Replacements are done in place and a pointer |
* characters into '?'. Replacements are done in place and a pointer |
* to the original buffer is returned. |
* to the original buffer is returned. |
*/ |
*/ |
|
|
char * |
char * |
printable(char *str) |
printable(char *str) |
{ |
{ |
char *ptr; |
char *ptr, ch; |
char ch; |
|
|
|
ptr = str; |
ptr = str; |
while ((ch = *ptr) != '\0') |
while ((ch = *ptr) != '\0') { |
{ |
if (!isprint(ch)) |
if (!isprint(ch)) |
*ptr = '?'; |
{ |
ptr++; |
*ptr = '?'; |
|
} |
} |
ptr++; |
return (str); |
} |
|
return(str); |
|
} |
} |