version 1.24, 2007/03/30 19:21:19 |
version 1.25, 2007/05/29 00:56:56 |
|
|
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/sched.h> |
#include <sys/sched.h> |
|
#include <curses.h> |
|
#include <errno.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <ctype.h> |
#include <ctype.h> |
#include <err.h> |
#include <err.h> |
|
#include <signal.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <signal.h> |
|
#include <term.h> |
|
#include <unistd.h> |
#include <unistd.h> |
#include <stdarg.h> |
|
|
|
#include "screen.h" /* interface to screen package */ |
#include "screen.h" /* interface to screen package */ |
#include "layout.h" /* defines for screen position layout */ |
#include "layout.h" /* defines for screen position layout */ |
|
|
#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 lastline = 0; |
|
static int display_width = MAX_COLS; |
static int display_width = MAX_COLS; |
|
|
static char *cpustates_tag(int); |
static char *cpustates_tag(int); |
static int string_count(char **); |
static int string_count(char **); |
static void summary_format(char *, size_t, int *, char **); |
static void summary_format(char *, size_t, int *, char **); |
static void line_update(char *, char *, int, int); |
static int readlinedumb(char *, int, int); |
|
|
#define lineindex(l) ((l)*display_width) |
#define lineindex(l) ((l)*display_width) |
|
|
|
|
OFF, ON, ERASE |
OFF, ON, ERASE |
} header_status = ON; |
} header_status = ON; |
|
|
|
static int |
|
empty(void) |
|
{ |
|
return OK; |
|
} |
|
|
|
static int |
|
myfputs(const char *s) |
|
{ |
|
return fputs(s, stdout); |
|
} |
|
|
|
static int (*addstrp)(const char *); |
|
static int (*printwp)(const char *, ...); |
|
static int (*standoutp)(void); |
|
static int (*standendp)(void); |
|
|
int |
int |
display_resize(void) |
display_resize(void) |
{ |
{ |
int display_lines; |
int display_lines; |
|
|
/* first, deallocate any previous buffer that may have been there */ |
|
if (screenbuf != NULL) |
|
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; |
|
|
if (display_width >= MAX_COLS) |
if (display_width >= MAX_COLS) |
display_width = MAX_COLS - 1; |
display_width = MAX_COLS - 1; |
|
|
/* now, allocate space for the screen buffer */ |
|
screenbuf = malloc(display_lines * display_width + 1); |
|
if (screenbuf == NULL) |
|
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 display_lines, *ip, i, cpu; |
int display_lines, *ip, i, cpu; |
char **pp; |
char **pp; |
|
|
|
if (smart_terminal) { |
|
addstrp = addstr; |
|
printwp = (int(*)(const char *, ...))printw; |
|
standoutp = standout; |
|
standendp = standend; |
|
} else { |
|
addstrp = myfputs; |
|
printwp = printf; |
|
standoutp = empty; |
|
standendp = empty; |
|
} |
|
|
y_mem = 2 + ncpu; |
y_mem = 2 + ncpu; |
y_message = 3 + ncpu; |
y_message = 3 + ncpu; |
y_header = 4 + ncpu; |
y_header = 4 + ncpu; |
|
|
{ |
{ |
int i; |
int i; |
|
|
/* i_loadave also clears the screen, since it is first */ |
move(0, 0); |
clear(); |
clrtoeol(); |
|
|
/* 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); |
printwp("last pid: %5ld; ", (long) mpid); |
|
|
printf("load averages"); |
addstrp("load averages"); |
|
|
for (i = 0; i < 3; i++) |
for (i = 0; i < 3; i++) |
printf("%c %5.2f", i == 0 ? ':' : ',', avenrun[i]); |
printwp("%c %5.2f", i == 0 ? ':' : ',', avenrun[i]); |
|
|
lmpid = mpid; |
lmpid = mpid; |
} |
} |
|
|
void |
|
u_loadave(pid_t mpid, double *avenrun) |
|
{ |
|
int i; |
|
|
|
if (mpid != -1) { |
|
/* change screen only when value has really changed */ |
|
if (mpid != lmpid) { |
|
Move_to(x_lastpid, y_lastpid); |
|
printf("%5ld", (long) mpid); |
|
lmpid = mpid; |
|
} |
|
/* i remembers x coordinate to move to */ |
|
i = x_loadave; |
|
} else |
|
i = x_loadave_nompid; |
|
|
|
/* move into position for load averages */ |
|
Move_to(i, y_loadave); |
|
|
|
/* display new load averages */ |
|
/* 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. |
* Display the current time. |
* "ctime" always returns a string that looks like this: |
* "ctime" always returns a string that looks like this: |
|
|
{ |
{ |
|
|
if (smart_terminal) { |
if (smart_terminal) { |
Move_to(screen_width - 8, 0); |
move(0, screen_width - 8); |
} else { |
} else { |
if (fputs(" ", stdout) == EOF) |
if (fputs(" ", stdout) == EOF) |
exit(1); |
exit(1); |
|
|
{ |
{ |
char *foo; |
char *foo; |
foo = ctime(tod); |
foo = ctime(tod); |
if (fputs(foo, stdout) == EOF) |
addstrp(foo); |
exit(1); |
|
} |
} |
#endif |
#endif |
printf("%-8.8s\n", &(ctime(tod)[11])); |
printwp("%-8.8s", &(ctime(tod)[11])); |
lastline = 1; |
putn(); |
} |
} |
|
|
static int ltotal = 0; |
|
static char procstates_buffer[MAX_COLS]; |
|
|
|
/* |
/* |
* *_procstates(total, brkdn, names) - print the process summary line |
* *_procstates(total, brkdn, names) - print the process summary line |
* |
* |
|
|
i_procstates(int total, int *brkdn) |
i_procstates(int total, int *brkdn) |
{ |
{ |
int i; |
int i; |
|
char procstates_buffer[MAX_COLS]; |
|
|
|
move(1, 0); |
|
clrtoeol(); |
/* write current number of processes and remember the value */ |
/* write current number of processes and remember the value */ |
printf("%d processes:", total); |
printwp("%d processes:", total); |
ltotal = total; |
|
|
|
/* put out enough spaces to get to column 15 */ |
if (smart_terminal) |
i = digits(total); |
move(1, 15); |
while (i++ < 4) { |
else { |
if (putchar(' ') == EOF) |
/* put out enough spaces to get to column 15 */ |
exit(1); |
i = digits(total); |
|
while (i++ < 4) { |
|
if (putchar(' ') == EOF) |
|
exit(1); |
|
} |
} |
} |
|
|
/* format and print the process state summary */ |
/* format and print the process state summary */ |
summary_format(procstates_buffer, sizeof(procstates_buffer), brkdn, |
summary_format(procstates_buffer, sizeof(procstates_buffer), brkdn, |
procstate_names); |
procstate_names); |
if (fputs(procstates_buffer, stdout) == EOF) |
|
exit(1); |
|
|
|
/* save the numbers for next time */ |
addstrp(procstates_buffer); |
memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); |
putn(); |
} |
} |
|
|
void |
|
u_procstates(int total, int *brkdn) |
|
{ |
|
static char new[MAX_COLS]; |
|
int i; |
|
|
|
/* update number of processes only if it has changed */ |
|
if (ltotal != total) { |
|
/* move and overwrite */ |
|
#if (x_procstate == 0) |
|
Move_to(x_procstate, y_procstate); |
|
#else |
|
/* cursor is already there...no motion needed */ |
|
/* assert(lastline == 1); */ |
|
#endif |
|
printf("%d", total); |
|
|
|
/* if number of digits differs, rewrite the label */ |
|
if (digits(total) != digits(ltotal)) { |
|
if (fputs(" processes:", stdout) == EOF) |
|
exit(1); |
|
/* put out enough spaces to get to column 15 */ |
|
i = digits(total); |
|
while (i++ < 4) { |
|
if (putchar(' ') == EOF) |
|
exit(1); |
|
} |
|
/* cursor may end up right where we want it!!! */ |
|
} |
|
/* save new total */ |
|
ltotal = total; |
|
} |
|
/* see if any of the state numbers has changed */ |
|
if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) { |
|
/* format and update the line */ |
|
summary_format(new, sizeof(new), brkdn, procstate_names); |
|
line_update(procstates_buffer, new, x_brkdn, y_brkdn); |
|
memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); |
|
} |
|
} |
|
|
|
/* |
/* |
* *_cpustates(states, names) - print the cpu state percentages |
* *_cpustates(states, names) - print the cpu state percentages |
* |
* |
* Assumptions: cursor is on the PREVIOUS line |
* Assumptions: cursor is on the PREVIOUS line |
*/ |
*/ |
|
|
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 * |
|
|
i = asprintf(&tag, "CPU%.*d states: ", cpulen, cpu); |
i = asprintf(&tag, "CPU%.*d states: ", cpulen, cpu); |
if (i == -1) |
if (i == -1) |
tag = NULL; |
tag = NULL; |
else { |
else |
cpustates_column = strlen(tag); |
|
old_width = screen_width; |
old_width = screen_width; |
} |
|
} |
} |
return (tag); |
return (tag); |
} |
} |
|
|
char **names = cpustate_names, *thisname; |
char **names = cpustate_names, *thisname; |
|
|
for (cpu = 0; cpu < ncpu; cpu++) { |
for (cpu = 0; cpu < ncpu; cpu++) { |
|
move(2 + cpu, 0); |
|
clrtoeol(); |
/* print tag and bump lastline */ |
/* print tag and bump lastline */ |
printf("\n%s", cpustates_tag(cpu)); |
addstrp(cpustates_tag(cpu)); |
lastline++; |
|
|
|
/* now walk thru the names and print the line */ |
/* now walk thru the names and print the line */ |
names = cpustate_names; |
names = cpustate_names; |
|
|
value = *states++; |
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" : |
printwp((value >= 1000 ? "%s%4.0f%% %s" : |
"%s%4.1f%% %s"), i++ == 0 ? "" : ", ", |
"%s%4.1f%% %s"), i++ == 0 ? "" : ", ", |
((float) value) / 10., thisname); |
((float) value) / 10., thisname); |
} |
} |
} |
} |
|
putn(); |
/* copy over values into "last" array */ |
|
memcpy(lcpustates[cpu], ostates, num_cpustates * sizeof(int64_t)); |
|
} |
} |
} |
} |
|
|
void |
|
u_cpustates(int64_t *ostates) |
|
{ |
|
char **names, *thisname; |
|
int cpu, value, *colp; |
|
int64_t *lp, *states; |
|
|
|
for (cpu = 0; cpu < ncpu; cpu++) { |
|
lastline = y_cpustates + cpu; |
|
states = ostates + (CPUSTATES * cpu); |
|
Move_to(cpustates_column, lastline); |
|
lp = lcpustates[cpu]; |
|
colp = cpustate_columns; |
|
|
|
/* we could be much more optimal about this */ |
|
names = cpustate_names; |
|
while ((thisname = *names++) != NULL) { |
|
if (*thisname != '\0') { |
|
/* did the value change since last time? */ |
|
if (*lp != *states) { |
|
/* yes, move and change */ |
|
lastline = y_cpustates + cpu; |
|
Move_to(cpustates_column + *colp, |
|
lastline); |
|
|
|
/* retrieve value and remember it */ |
|
value = *states; |
|
|
|
/* if percentage is >= 1000, |
|
* print it as 100% |
|
*/ |
|
printf((value >= 1000 ? "%4.0f" : |
|
"%4.1f"), ((double) value) / 10.); |
|
|
|
/* remember it for next time */ |
|
*lp = *states; |
|
} |
|
} |
|
/* increment and move on */ |
|
lp++; |
|
states++; |
|
colp++; |
|
} |
|
} |
|
} |
|
|
|
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 |
* |
* |
|
|
void |
void |
i_memory(int *stats) |
i_memory(int *stats) |
{ |
{ |
if (fputs("\nMemory: ", stdout) == EOF) |
char memory_buffer[MAX_COLS]; |
exit(1); |
|
lastline++; |
|
|
|
|
move(y_mem, 0); |
|
clrtoeol(); |
|
addstrp("Memory: "); |
|
|
/* format and print the memory summary */ |
/* format and print the memory summary */ |
summary_format(memory_buffer, sizeof(memory_buffer), stats, |
summary_format(memory_buffer, sizeof(memory_buffer), stats, |
memory_names); |
memory_names); |
if (fputs(memory_buffer, stdout) == EOF) |
addstrp(memory_buffer); |
exit(1); |
putn(); |
} |
} |
|
|
void |
|
u_memory(int *stats) |
|
{ |
|
static char new[MAX_COLS]; |
|
|
|
/* format the new line */ |
|
summary_format(new, sizeof(new), stats, memory_names); |
|
line_update(memory_buffer, new, x_mem, y_mem); |
|
} |
|
|
|
/* |
/* |
* *_message() - print the next pending message line, or erase the one |
* *_message() - print the next pending message line, or erase the one |
* that is there. |
* that is there. |
|
|
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++; |
} |
} |
|
*/ |
|
move(y_message, 0); |
if (next_msg[0] != '\0') { |
if (next_msg[0] != '\0') { |
standout(next_msg); |
standoutp(); |
|
addstrp(next_msg); |
|
standendp(); |
|
clrtoeol(); |
msglen = strlen(next_msg); |
msglen = strlen(next_msg); |
next_msg[0] = '\0'; |
next_msg[0] = '\0'; |
} else if (msglen > 0) { |
} else if (msglen > 0) { |
(void) clear_eol(msglen); |
clrtoeol(); |
msglen = 0; |
msglen = 0; |
} |
} |
} |
} |
|
|
void |
|
u_message(void) |
|
{ |
|
i_message(); |
|
} |
|
|
|
static int header_length; |
static int header_length; |
|
|
/* |
/* |
|
|
{ |
{ |
header_length = strlen(text); |
header_length = strlen(text); |
if (header_status == ON) { |
if (header_status == ON) { |
if (putchar('\n') == EOF) |
if (!smart_terminal) { |
exit(1); |
putn(); |
if (fputs(text, stdout) == EOF) |
if (fputs(text, stdout) == EOF) |
exit(1); |
exit(1); |
lastline++; |
putn(); |
|
} else { |
|
move(y_header, 0); |
|
clrtoeol(); |
|
addstrp(text); |
|
} |
} else if (header_status == ERASE) { |
} else if (header_status == ERASE) { |
header_status = OFF; |
header_status = OFF; |
} |
} |
} |
} |
|
|
/* ARGSUSED */ |
|
void |
|
u_header(char *text) |
|
{ |
|
if (header_status == ERASE) { |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
lastline++; |
|
clear_eol(header_length); |
|
header_status = OFF; |
|
} |
|
} |
|
|
|
/* |
/* |
* *_process(line, thisline) - print one process line |
* *_process(line, thisline) - print one process line |
* |
* |
|
|
*/ |
*/ |
|
|
void |
void |
i_process(int line, char *thisline) |
i_process(int line, char *thisline, int hl) |
{ |
{ |
char *base; |
|
size_t len; |
|
|
|
/* make sure we are on the correct line */ |
/* make sure we are on the correct line */ |
while (lastline < y_procs + line) { |
move(y_procs + line, 0); |
if (putchar('\n') == EOF) |
|
exit(1); |
|
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 (hl && smart_terminal) |
exit(1); |
standoutp(); |
|
addstrp(thisline); |
/* copy it in to our buffer */ |
if (hl && smart_terminal) |
base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; |
standendp(); |
len = strlcpy(base, thisline, display_width); |
putn(); |
if (len < (size_t)display_width) { |
clrtoeol(); |
/* zero fill the rest of it */ |
|
memset(base + len, 0, display_width - len); |
|
} |
|
} |
} |
|
|
void |
void |
u_process(int linenum, char *linebuf) |
|
{ |
|
int screen_line = linenum + Header_lines; |
|
char *bufferline; |
|
size_t len; |
|
|
|
/* remember a pointer to the current line in the screen buffer */ |
|
bufferline = &screenbuf[lineindex(linenum)]; |
|
|
|
/* truncate the line to conform to our current screen width */ |
|
linebuf[display_width] = '\0'; |
|
bufferline[display_width] = '\0'; |
|
|
|
/* is line higher than we went on the last display? */ |
|
if (linenum >= last_hi) { |
|
/* yes, just ignore screenbuf and write it out directly */ |
|
/* get positioned on the correct line */ |
|
if (screen_line - lastline == 1) { |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
lastline++; |
|
} else { |
|
Move_to(0, screen_line); |
|
lastline = screen_line; |
|
} |
|
|
|
/* now write the line */ |
|
if (fputs(linebuf, stdout) == EOF) |
|
exit(1); |
|
|
|
/* copy it in to the buffer */ |
|
len = strlcpy(bufferline, linebuf, display_width); |
|
if (len < (size_t)display_width) { |
|
/* zero fill the rest of it */ |
|
memset(bufferline + len, 0, display_width - len); |
|
} |
|
} else { |
|
line_update(bufferline, linebuf, 0, linenum + Header_lines); |
|
} |
|
} |
|
|
|
void |
|
u_endscreen(int hi) |
u_endscreen(int hi) |
{ |
{ |
int screen_line = hi + Header_lines, i; |
|
|
|
if (smart_terminal) { |
if (smart_terminal) { |
if (hi < last_hi) { |
clrtobot(); |
/* need to blank the remainder of the screen */ |
|
/* |
|
* but only if there is any screen left below this |
|
* line |
|
*/ |
|
if (lastline + 1 < screen_length) { |
|
/* |
|
* efficiently move to the end of currently |
|
* displayed info |
|
*/ |
|
if (screen_line - lastline < 5) { |
|
while (lastline < screen_line) { |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
lastline++; |
|
} |
|
} else { |
|
Move_to(0, screen_line); |
|
lastline = screen_line; |
|
} |
|
|
|
if (clear_to_end) { |
|
/* we can do this the easy way */ |
|
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); |
|
} |
|
} |
|
} |
|
} |
|
last_hi = hi; |
|
|
|
/* move the cursor to a pleasant place */ |
/* move the cursor to a pleasant place */ |
Move_to(x_idlecursor, y_idlecursor); |
move(y_idlecursor, x_idlecursor); |
lastline = y_idlecursor; |
|
} else { |
} else { |
/* |
/* |
* separate this display from the next with some vertical |
* separate this display from the next with some vertical |
|
|
|
|
if (msglen > 0) { |
if (msglen > 0) { |
/* message there already -- can we clear it? */ |
/* message there already -- can we clear it? */ |
if (!overstrike) { |
/* yes -- write it and clear to end */ |
/* yes -- write it and clear to end */ |
i = strlen(next_msg); |
i = strlen(next_msg); |
if ((type & MT_delayed) == 0) { |
if ((type & MT_delayed) == 0) { |
move(y_message, 0); |
if (type & MT_standout) |
if (type & MT_standout) |
standout(next_msg); |
standoutp(); |
else { |
addstrp(next_msg); |
if (fputs(next_msg, stdout) == EOF) |
if (type & MT_standout) |
exit(1); |
standendp(); |
} |
clrtoeol(); |
(void) clear_eol(msglen - i); |
msglen = i; |
msglen = i; |
next_msg[0] = '\0'; |
next_msg[0] = '\0'; |
|
} |
|
} |
} |
} else { |
} else { |
if ((type & MT_delayed) == 0) { |
if ((type & MT_delayed) == 0) { |
|
move(y_message, 0); |
if (type & MT_standout) |
if (type & MT_standout) |
standout(next_msg); |
standoutp(); |
else { |
addstrp(next_msg); |
if (fputs(next_msg, stdout) == EOF) |
if (type & MT_standout) |
exit(1); |
standendp(); |
} |
clrtoeol(); |
msglen = strlen(next_msg); |
msglen = strlen(next_msg); |
next_msg[0] = '\0'; |
next_msg[0] = '\0'; |
} |
} |
} |
} |
|
if (smart_terminal) |
|
refresh(); |
} |
} |
|
|
void |
void |
clear_message(void) |
clear_message(void) |
{ |
{ |
if (clear_eol(msglen) == 1) { |
move(y_message, 0); |
if (putchar('\r') == EOF) |
clrtoeol(); |
exit(1); |
|
} |
|
} |
} |
|
|
int |
|
readline(char *buffer, int size, int numeric) |
static int |
|
readlinedumb(char *buffer, int size, int numeric) |
{ |
{ |
char *ptr = buffer, ch, cnt = 0, maxcnt = 0; |
char *ptr = buffer, ch, cnt = 0, maxcnt = 0; |
extern volatile sig_atomic_t leaveflag; |
extern volatile sig_atomic_t leaveflag; |
|
|
|
|
/* handle special editing characters */ |
/* handle special editing characters */ |
if (ch == ch_kill) { |
if (ch == ch_kill) { |
/* kill line -- account for overstriking */ |
|
if (overstrike) |
|
msglen += maxcnt; |
|
|
|
/* return null string */ |
/* return null string */ |
*buffer = '\0'; |
*buffer = '\0'; |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
return (-1); |
return (-1); |
} else if (ch == ch_erase) { |
} else if (ch == ch_erase) { |
/* erase previous character */ |
/* erase previous character */ |
|
|
*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) */ |
msglen += cnt; |
msglen += overstrike ? maxcnt : cnt; |
|
|
|
/* return either inputted number or string length */ |
/* return either inputted number or string length */ |
if (putchar('\r') == EOF) |
putr(); |
exit(1); |
|
return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); |
return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); |
} |
} |
|
|
|
int |
|
readline(char *buffer, int size, int numeric) |
|
{ |
|
size_t cnt; |
|
|
|
/* allow room for null terminator */ |
|
size -= 1; |
|
|
|
if (smart_terminal) |
|
getnstr(buffer, size); |
|
else |
|
return readlinedumb(buffer, size, numeric); |
|
|
|
cnt = strlen(buffer); |
|
if (cnt > 0 && buffer[cnt - 1] == '\n') |
|
buffer[cnt - 1] = '\0'; |
|
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) |
|
|
*p = '\0'; |
*p = '\0'; |
} |
} |
|
|
static void |
|
line_update(char *old, char *new, int start, int line) |
|
{ |
|
int ch, diff, newcol = start + 1, lastcol = start; |
|
char cursor_on_line = No, *current; |
|
|
|
/* compare the two strings and only rewrite what has changed */ |
|
current = old; |
|
#ifdef DEBUG |
|
fprintf(debug, "line_update, starting at %d\n", start); |
|
fputs(old, debug); |
|
fputc('\n', debug); |
|
fputs(new, debug); |
|
fputs("\n-\n", debug); |
|
#endif |
|
|
|
/* start things off on the right foot */ |
|
/* this is to make sure the invariants get set up right */ |
|
if ((ch = *new++) != *old) { |
|
if (line - lastline == 1 && start == 0) { |
|
if (putchar('\n') == EOF) |
|
exit(1); |
|
} else |
|
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 { |
|
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) |
|
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; |
|
} |
|
|
|
/* |
/* |
* printable(str) - make the string pointed to by "str" into one that is |
* printable(str) - make the string pointed to by "str" into one that is |
* printable (i.e.: all ascii), by converting all non-printable |
* printable (i.e.: all ascii), by converting all non-printable |
|
|
ptr++; |
ptr++; |
} |
} |
return (str); |
return (str); |
|
} |
|
|
|
|
|
/* |
|
* show_help() - display the help screen; invoked in response to |
|
* either 'h' or '?'. |
|
*/ |
|
void |
|
show_help(void) |
|
{ |
|
if (smart_terminal) { |
|
clear(); |
|
nl(); |
|
} |
|
printwp("These single-character commands are available:\n" |
|
"\n" |
|
"^L - redraw screen\n" |
|
"+ - reset any g, p, or u filters\n" |
|
"C - toggle the display of command line arguments\n" |
|
"d count - show `count' displays, then exit\n" |
|
"e - list errors generated by last \"kill\" or \"renice\" command\n" |
|
"h | ? - help; show this text\n" |
|
"g string - filter on command name (g+ selects all commands)\n" |
|
"I | i - toggle the display of idle processes\n" |
|
"k [-sig] pid - send signal `-sig' to process `pid'\n" |
|
"n|# count - show `count' processes\n" |
|
"o field - specify sort order (size, res, cpu, time, pri)\n" |
|
"P pid - highlight process `pid' (P+ switches highlighting off)\n" |
|
"p pid - display process by `pid' (p+ selects all processes)\n" |
|
"q - quit\n" |
|
"r count pid - renice process `pid' to nice value `count'\n" |
|
"S - toggle the display of system processes\n" |
|
"s time - change delay between displays to `time' seconds\n" |
|
"T - toggle the display of threads\n" |
|
"u user - display processes for `user' (u+ selects all users)\n" |
|
"\n"); |
|
|
|
if (smart_terminal) { |
|
nonl(); |
|
refresh(); |
|
} |
|
} |
|
|
|
/* |
|
* show_errors() - display on stdout the current log of errors. |
|
*/ |
|
void |
|
show_errors(void) |
|
{ |
|
struct errs *errp = errs; |
|
int cnt = 0; |
|
|
|
if (smart_terminal) { |
|
clear(); |
|
nl(); |
|
} |
|
printwp("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s"); |
|
while (cnt++ < errcnt) { |
|
printf("%5s: %s\n", errp->arg, |
|
errp->err == 0 ? "Not a number" : strerror(errp->err)); |
|
errp++; |
|
} |
|
if (smart_terminal) { |
|
nonl(); |
|
refresh(); |
|
} |
|
} |
|
|
|
void |
|
anykey(void) |
|
{ |
|
int ch; |
|
size_t len; |
|
|
|
standoutp(); |
|
addstrp("Hit any key to continue: "); |
|
standendp(); |
|
if (smart_terminal) |
|
refresh(); |
|
else |
|
fflush(stdout); |
|
while (1) { |
|
len = read(STDIN_FILENO, &ch, 1); |
|
if (len == -1 && errno == EINTR) |
|
continue; |
|
if (len == 0) |
|
exit(1); |
|
break; |
|
} |
} |
} |