124139Sjoerg/* 224139Sjoerg * Top users/processes display for Unix 324139Sjoerg * Version 3 424139Sjoerg * 524139Sjoerg * This program may be freely redistributed, 624139Sjoerg * but this entire comment MUST remain intact. 724139Sjoerg * 824139Sjoerg * Copyright (c) 1984, 1989, William LeFebvre, Rice University 924139Sjoerg * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 1066641Simp * 1166641Simp * $FreeBSD$ 1224139Sjoerg */ 1324139Sjoerg 1424139Sjoerg/* 1524139Sjoerg * This file contains the routines that display information on the screen. 1624139Sjoerg * Each section of the screen has two routines: one for initially writing 1724139Sjoerg * all constant and dynamic text, and one for only updating the text that 1824139Sjoerg * changes. The prefix "i_" is used on all the "initial" routines and the 1924139Sjoerg * prefix "u_" is used for all the "updating" routines. 2024139Sjoerg * 2124139Sjoerg * ASSUMPTIONS: 2224139Sjoerg * None of the "i_" routines use any of the termcap capabilities. 2324139Sjoerg * In this way, those routines can be safely used on terminals that 2424139Sjoerg * have minimal (or nonexistant) terminal capabilities. 2524139Sjoerg * 2624139Sjoerg * The routines are called in this order: *_loadave, i_timeofday, 2724139Sjoerg * *_procstates, *_cpustates, *_memory, *_message, *_header, 2824139Sjoerg * *_process, u_endscreen. 2924139Sjoerg */ 3024139Sjoerg 3124139Sjoerg#include "os.h" 3224139Sjoerg#include <ctype.h> 3324139Sjoerg#include <time.h> 3441943Sobrien#include <sys/time.h> 3524139Sjoerg 3624139Sjoerg#include "screen.h" /* interface to screen package */ 3724139Sjoerg#include "layout.h" /* defines for screen position layout */ 3824139Sjoerg#include "display.h" 3924139Sjoerg#include "top.h" 4024139Sjoerg#include "top.local.h" 4124139Sjoerg#include "boolean.h" 4224139Sjoerg#include "machine.h" /* we should eliminate this!!! */ 4324139Sjoerg#include "utils.h" 4424139Sjoerg 4524139Sjoerg#ifdef DEBUG 4624139SjoergFILE *debug; 4724139Sjoerg#endif 4824139Sjoerg 4924139Sjoerg/* imported from screen.c */ 5024139Sjoergextern int overstrike; 5124139Sjoerg 5224139Sjoergstatic int lmpid = 0; 5324139Sjoergstatic int last_hi = 0; /* used in u_process and u_endscreen */ 5424139Sjoergstatic int lastline = 0; 5524139Sjoergstatic int display_width = MAX_COLS; 5624139Sjoerg 5724139Sjoerg#define lineindex(l) ((l)*display_width) 5824139Sjoerg 5924139Sjoergchar *printable(); 6024139Sjoerg 6124139Sjoerg/* things initialized by display_init and used thruout */ 6224139Sjoerg 6324139Sjoerg/* buffer of proc information lines for display updating */ 6424139Sjoergchar *screenbuf = NULL; 6524139Sjoerg 6624139Sjoergstatic char **procstate_names; 6724139Sjoergstatic char **cpustate_names; 6824139Sjoergstatic char **memory_names; 69239750Sjhbstatic char **arc_names; 7024142Sjoergstatic char **swap_names; 7124139Sjoerg 7224139Sjoergstatic int num_procstates; 7324139Sjoergstatic int num_cpustates; 7424139Sjoergstatic int num_memory; 7524142Sjoergstatic int num_swap; 7624139Sjoerg 7724139Sjoergstatic int *lprocstates; 7824139Sjoergstatic int *lcpustates; 7924139Sjoergstatic int *lmemory; 8024142Sjoergstatic int *lswap; 8124139Sjoerg 82175420Speterstatic int num_cpus; 8324139Sjoergstatic int *cpustate_columns; 8424139Sjoergstatic int cpustate_total_length; 85175420Speterstatic int cpustates_column; 8624139Sjoerg 8724139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON; 8824139Sjoerg 8924139Sjoergstatic int string_count(); 9024139Sjoergstatic void summary_format(); 9124139Sjoergstatic void line_update(); 9224139Sjoerg 93175420Speterint x_lastpid = 10; 94175420Speterint y_lastpid = 0; 95175420Speterint x_loadave = 33; 96175420Speterint x_loadave_nompid = 15; 97175420Speterint y_loadave = 0; 98175420Speterint x_procstate = 0; 99175420Speterint y_procstate = 1; 100175420Speterint x_brkdn = 15; 101175420Speterint y_brkdn = 1; 102175420Speterint x_mem = 5; 103175420Speterint y_mem = 3; 104239750Sjhbint x_arc = 5; 105239750Sjhbint y_arc = 4; 106175420Speterint x_swap = 6; 107175420Speterint y_swap = 4; 108175420Speterint y_message = 5; 109175420Speterint x_header = 0; 110175420Speterint y_header = 6; 111175420Speterint x_idlecursor = 0; 112175420Speterint y_idlecursor = 5; 113175420Speterint y_procs = 7; 114175420Speter 115175420Speterint y_cpustates = 2; 116175420Speterint Header_lines = 7; 117175420Speter 11824139Sjoergint display_resize() 11924139Sjoerg 12024139Sjoerg{ 12124139Sjoerg register int lines; 12224139Sjoerg 12324139Sjoerg /* first, deallocate any previous buffer that may have been there */ 12424139Sjoerg if (screenbuf != NULL) 12524139Sjoerg { 12624139Sjoerg free(screenbuf); 12724139Sjoerg } 12824139Sjoerg 12924139Sjoerg /* calculate the current dimensions */ 13024139Sjoerg /* if operating in "dumb" mode, we only need one line */ 13124139Sjoerg lines = smart_terminal ? screen_length - Header_lines : 1; 13224139Sjoerg 133101692Sdwmalone if (lines < 0) 134101692Sdwmalone lines = 0; 13524139Sjoerg /* we don't want more than MAX_COLS columns, since the machine-dependent 13624139Sjoerg modules make static allocations based on MAX_COLS and we don't want 13724139Sjoerg to run off the end of their buffers */ 13824139Sjoerg display_width = screen_width; 13924139Sjoerg if (display_width >= MAX_COLS) 14024139Sjoerg { 14124139Sjoerg display_width = MAX_COLS - 1; 14224139Sjoerg } 14324139Sjoerg 14424139Sjoerg /* now, allocate space for the screen buffer */ 14524139Sjoerg screenbuf = (char *)malloc(lines * display_width); 14624139Sjoerg if (screenbuf == (char *)NULL) 14724139Sjoerg { 14824139Sjoerg /* oops! */ 14924139Sjoerg return(-1); 15024139Sjoerg } 15124139Sjoerg 15224139Sjoerg /* return number of lines available */ 15324139Sjoerg /* for dumb terminals, pretend like we can show any amount */ 15424139Sjoerg return(smart_terminal ? lines : Largest); 15524139Sjoerg} 15624139Sjoerg 157223936Sjhbint display_updatecpus(statics) 15824139Sjoerg 15924139Sjoergstruct statics *statics; 16024139Sjoerg 16124139Sjoerg{ 162224205Sjhb register int *lp; 16324139Sjoerg register int lines; 16424139Sjoerg register int i; 165223936Sjhb 16624139Sjoerg /* call resize to do the dirty work */ 16724139Sjoerg lines = display_resize(); 168224205Sjhb if (pcpu_stats) 169224205Sjhb num_cpus = statics->ncpus; 170224205Sjhb else 171224205Sjhb num_cpus = 1; 172175420Speter cpustates_column = 5; /* CPU: */ 173175420Speter if (num_cpus != 1) 174175420Speter cpustates_column += 2; /* CPU 0: */ 175175420Speter for (i = num_cpus; i > 9; i /= 10) 176175420Speter cpustates_column++; 17724139Sjoerg 178224205Sjhb /* fill the "last" array with all -1s, to insure correct updating */ 179224205Sjhb lp = lcpustates; 180224205Sjhb i = num_cpustates * num_cpus; 181224205Sjhb while (--i >= 0) 182224205Sjhb { 183224205Sjhb *lp++ = -1; 184224205Sjhb } 185224205Sjhb 186223936Sjhb return(lines); 187223936Sjhb} 188223936Sjhb 189223936Sjhbint display_init(statics) 190223936Sjhb 191223936Sjhbstruct statics *statics; 192223936Sjhb 193223936Sjhb{ 194223936Sjhb register int lines; 195223936Sjhb register char **pp; 196223936Sjhb register int *ip; 197223936Sjhb register int i; 198223936Sjhb 199223936Sjhb lines = display_updatecpus(statics); 200223936Sjhb 20124139Sjoerg /* only do the rest if we need to */ 20224139Sjoerg if (lines > -1) 20324139Sjoerg { 20424139Sjoerg /* save pointers and allocate space for names */ 20524139Sjoerg procstate_names = statics->procstate_names; 20624139Sjoerg num_procstates = string_count(procstate_names); 20724139Sjoerg lprocstates = (int *)malloc(num_procstates * sizeof(int)); 20824139Sjoerg 20924139Sjoerg cpustate_names = statics->cpustate_names; 21024142Sjoerg 21124142Sjoerg swap_names = statics->swap_names; 21224142Sjoerg num_swap = string_count(swap_names); 21324142Sjoerg lswap = (int *)malloc(num_swap * sizeof(int)); 21424139Sjoerg num_cpustates = string_count(cpustate_names); 215224205Sjhb lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus); 21624139Sjoerg cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); 21724139Sjoerg 21824139Sjoerg memory_names = statics->memory_names; 21924139Sjoerg num_memory = string_count(memory_names); 22024139Sjoerg lmemory = (int *)malloc(num_memory * sizeof(int)); 22124139Sjoerg 222239750Sjhb arc_names = statics->arc_names; 223239750Sjhb 22424139Sjoerg /* calculate starting columns where needed */ 22524139Sjoerg cpustate_total_length = 0; 22624139Sjoerg pp = cpustate_names; 22724139Sjoerg ip = cpustate_columns; 22824139Sjoerg while (*pp != NULL) 22924139Sjoerg { 23089758Sdwmalone *ip++ = cpustate_total_length; 23124139Sjoerg if ((i = strlen(*pp++)) > 0) 23224139Sjoerg { 23324139Sjoerg cpustate_total_length += i + 8; 23424139Sjoerg } 23524139Sjoerg } 23624139Sjoerg } 23724139Sjoerg 23824139Sjoerg /* return number of lines available */ 23924139Sjoerg return(lines); 24024139Sjoerg} 24124139Sjoerg 24224139Sjoergi_loadave(mpid, avenrun) 24324139Sjoerg 24424139Sjoergint mpid; 24524139Sjoergdouble *avenrun; 24624139Sjoerg 24724139Sjoerg{ 24824139Sjoerg register int i; 24924139Sjoerg 25024139Sjoerg /* i_loadave also clears the screen, since it is first */ 25124139Sjoerg clear(); 25224139Sjoerg 25324139Sjoerg /* mpid == -1 implies this system doesn't have an _mpid */ 25424139Sjoerg if (mpid != -1) 25524139Sjoerg { 25624139Sjoerg printf("last pid: %5d; ", mpid); 25724139Sjoerg } 25824139Sjoerg 25924139Sjoerg printf("load averages"); 26024139Sjoerg 26124139Sjoerg for (i = 0; i < 3; i++) 26224139Sjoerg { 26324139Sjoerg printf("%c %5.2f", 26424139Sjoerg i == 0 ? ':' : ',', 26524139Sjoerg avenrun[i]); 26624139Sjoerg } 26724139Sjoerg lmpid = mpid; 26824139Sjoerg} 26924139Sjoerg 27024139Sjoergu_loadave(mpid, avenrun) 27124139Sjoerg 27224139Sjoergint mpid; 27324139Sjoergdouble *avenrun; 27424139Sjoerg 27524139Sjoerg{ 27624139Sjoerg register int i; 27724139Sjoerg 27824139Sjoerg if (mpid != -1) 27924139Sjoerg { 28024139Sjoerg /* change screen only when value has really changed */ 28124139Sjoerg if (mpid != lmpid) 28224139Sjoerg { 28324139Sjoerg Move_to(x_lastpid, y_lastpid); 28424139Sjoerg printf("%5d", mpid); 28524139Sjoerg lmpid = mpid; 28624139Sjoerg } 28724139Sjoerg 28824139Sjoerg /* i remembers x coordinate to move to */ 28924139Sjoerg i = x_loadave; 29024139Sjoerg } 29124139Sjoerg else 29224139Sjoerg { 29324139Sjoerg i = x_loadave_nompid; 29424139Sjoerg } 29524139Sjoerg 29624139Sjoerg /* move into position for load averages */ 29724139Sjoerg Move_to(i, y_loadave); 29824139Sjoerg 29924139Sjoerg /* display new load averages */ 30024139Sjoerg /* we should optimize this and only display changes */ 30124139Sjoerg for (i = 0; i < 3; i++) 30224139Sjoerg { 30324139Sjoerg printf("%s%5.2f", 30424139Sjoerg i == 0 ? "" : ", ", 30524139Sjoerg avenrun[i]); 30624139Sjoerg } 30724139Sjoerg} 30824139Sjoerg 30924139Sjoergi_timeofday(tod) 31024139Sjoerg 31124139Sjoergtime_t *tod; 31224139Sjoerg 31324139Sjoerg{ 31424139Sjoerg /* 31524139Sjoerg * Display the current time. 31624139Sjoerg * "ctime" always returns a string that looks like this: 31724139Sjoerg * 31824139Sjoerg * Sun Sep 16 01:03:52 1973 31924139Sjoerg * 012345678901234567890123 32024139Sjoerg * 1 2 32124139Sjoerg * 32224139Sjoerg * We want indices 11 thru 18 (length 8). 32324139Sjoerg */ 32424139Sjoerg 32524139Sjoerg if (smart_terminal) 32624139Sjoerg { 32724139Sjoerg Move_to(screen_width - 8, 0); 32824139Sjoerg } 32924139Sjoerg else 33024139Sjoerg { 33124139Sjoerg fputs(" ", stdout); 33224139Sjoerg } 33324139Sjoerg#ifdef DEBUG 33424139Sjoerg { 33524139Sjoerg char *foo; 33624139Sjoerg foo = ctime(tod); 33724139Sjoerg fputs(foo, stdout); 33824139Sjoerg } 33924139Sjoerg#endif 34024139Sjoerg printf("%-8.8s\n", &(ctime(tod)[11])); 34124139Sjoerg lastline = 1; 34224139Sjoerg} 34324139Sjoerg 34424139Sjoergstatic int ltotal = 0; 34589758Sdwmalonestatic char procstates_buffer[MAX_COLS]; 34624139Sjoerg 34724139Sjoerg/* 34824139Sjoerg * *_procstates(total, brkdn, names) - print the process summary line 34924139Sjoerg * 35024139Sjoerg * Assumptions: cursor is at the beginning of the line on entry 35124139Sjoerg * lastline is valid 35224139Sjoerg */ 35324139Sjoerg 35424139Sjoergi_procstates(total, brkdn) 35524139Sjoerg 35624139Sjoergint total; 35724139Sjoergint *brkdn; 35824139Sjoerg 35924139Sjoerg{ 36024139Sjoerg register int i; 36124139Sjoerg 36224139Sjoerg /* write current number of processes and remember the value */ 36324139Sjoerg printf("%d processes:", total); 36424139Sjoerg ltotal = total; 36524139Sjoerg 36624139Sjoerg /* put out enough spaces to get to column 15 */ 36724139Sjoerg i = digits(total); 36824139Sjoerg while (i++ < 4) 36924139Sjoerg { 37024139Sjoerg putchar(' '); 37124139Sjoerg } 37224139Sjoerg 37324139Sjoerg /* format and print the process state summary */ 37424139Sjoerg summary_format(procstates_buffer, brkdn, procstate_names); 37524139Sjoerg fputs(procstates_buffer, stdout); 37624139Sjoerg 37724139Sjoerg /* save the numbers for next time */ 37824139Sjoerg memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 37924139Sjoerg} 38024139Sjoerg 38124139Sjoergu_procstates(total, brkdn) 38224139Sjoerg 38324139Sjoergint total; 38424139Sjoergint *brkdn; 38524139Sjoerg 38624139Sjoerg{ 38789758Sdwmalone static char new[MAX_COLS]; 38824139Sjoerg register int i; 38924139Sjoerg 39024139Sjoerg /* update number of processes only if it has changed */ 39124139Sjoerg if (ltotal != total) 39224139Sjoerg { 39324139Sjoerg /* move and overwrite */ 39424139Sjoerg#if (x_procstate == 0) 39524139Sjoerg Move_to(x_procstate, y_procstate); 39624139Sjoerg#else 39724139Sjoerg /* cursor is already there...no motion needed */ 39824139Sjoerg /* assert(lastline == 1); */ 39924139Sjoerg#endif 40024139Sjoerg printf("%d", total); 40124139Sjoerg 40224139Sjoerg /* if number of digits differs, rewrite the label */ 40324139Sjoerg if (digits(total) != digits(ltotal)) 40424139Sjoerg { 40524139Sjoerg fputs(" processes:", stdout); 40624139Sjoerg /* put out enough spaces to get to column 15 */ 40724139Sjoerg i = digits(total); 40824139Sjoerg while (i++ < 4) 40924139Sjoerg { 41024139Sjoerg putchar(' '); 41124139Sjoerg } 41224139Sjoerg /* cursor may end up right where we want it!!! */ 41324139Sjoerg } 41424139Sjoerg 41524139Sjoerg /* save new total */ 41624139Sjoerg ltotal = total; 41724139Sjoerg } 41824139Sjoerg 41924139Sjoerg /* see if any of the state numbers has changed */ 42024139Sjoerg if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) 42124139Sjoerg { 42224139Sjoerg /* format and update the line */ 42324139Sjoerg summary_format(new, brkdn, procstate_names); 42424139Sjoerg line_update(procstates_buffer, new, x_brkdn, y_brkdn); 42524139Sjoerg memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 42624139Sjoerg } 42724139Sjoerg} 42824139Sjoerg 429175420Speter#ifdef no_more 43024139Sjoerg/* 43124139Sjoerg * *_cpustates(states, names) - print the cpu state percentages 43224139Sjoerg * 43324139Sjoerg * Assumptions: cursor is on the PREVIOUS line 43424139Sjoerg */ 43524139Sjoerg 43624139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */ 43724139Sjoerg 43824139Sjoergchar *cpustates_tag() 43924139Sjoerg 44024139Sjoerg{ 44124139Sjoerg register char *use; 44224139Sjoerg 44324139Sjoerg static char *short_tag = "CPU: "; 44424139Sjoerg static char *long_tag = "CPU states: "; 44524139Sjoerg 44624139Sjoerg /* if length + strlen(long_tag) >= screen_width, then we have to 44724139Sjoerg use the shorter tag (we subtract 2 to account for ": ") */ 44824139Sjoerg if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) 44924139Sjoerg { 45024139Sjoerg use = short_tag; 45124139Sjoerg } 45224139Sjoerg else 45324139Sjoerg { 45424139Sjoerg use = long_tag; 45524139Sjoerg } 45624139Sjoerg 45724139Sjoerg /* set cpustates_column accordingly then return result */ 45824139Sjoerg cpustates_column = strlen(use); 45924139Sjoerg return(use); 46024139Sjoerg} 461175420Speter#endif 46224139Sjoerg 46324139Sjoergi_cpustates(states) 46424139Sjoerg 46524139Sjoergregister int *states; 46624139Sjoerg 46724139Sjoerg{ 46824139Sjoerg register int i = 0; 46924139Sjoerg register int value; 470175420Speter register char **names; 47124139Sjoerg register char *thisname; 472175420Speter int cpu; 47324139Sjoerg 474175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) { 475175420Speter names = cpustate_names; 476175420Speter 47724139Sjoerg /* print tag and bump lastline */ 478175420Speter if (num_cpus == 1) 479175420Speter printf("\nCPU: "); 480218171Sjhb else { 481218171Sjhb value = printf("\nCPU %d: ", cpu); 482218171Sjhb while (value++ <= cpustates_column) 483218171Sjhb printf(" "); 484218171Sjhb } 48524139Sjoerg lastline++; 48624139Sjoerg 48724139Sjoerg /* now walk thru the names and print the line */ 48824139Sjoerg while ((thisname = *names++) != NULL) 48924139Sjoerg { 49024139Sjoerg if (*thisname != '\0') 49124139Sjoerg { 49224139Sjoerg /* retrieve the value and remember it */ 49324139Sjoerg value = *states++; 49424139Sjoerg 49524139Sjoerg /* if percentage is >= 1000, print it as 100% */ 49624139Sjoerg printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), 497175420Speter (i++ % num_cpustates) == 0 ? "" : ", ", 49824139Sjoerg ((float)value)/10., 49924139Sjoerg thisname); 50024139Sjoerg } 50124139Sjoerg } 502175420Speter} 50324139Sjoerg 50424139Sjoerg /* copy over values into "last" array */ 505175420Speter memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus); 50624139Sjoerg} 50724139Sjoerg 50824139Sjoergu_cpustates(states) 50924139Sjoerg 51024139Sjoergregister int *states; 51124139Sjoerg 51224139Sjoerg{ 51324139Sjoerg register int value; 514175420Speter register char **names; 51524139Sjoerg register char *thisname; 51624139Sjoerg register int *lp; 51724139Sjoerg register int *colp; 518175420Speter int cpu; 51924139Sjoerg 520175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) { 521175420Speter names = cpustate_names; 522175420Speter 523175420Speter Move_to(cpustates_column, y_cpustates + cpu); 524175420Speter lastline = y_cpustates + cpu; 525175420Speter lp = lcpustates + (cpu * num_cpustates); 52624139Sjoerg colp = cpustate_columns; 52724139Sjoerg 52824139Sjoerg /* we could be much more optimal about this */ 52924139Sjoerg while ((thisname = *names++) != NULL) 53024139Sjoerg { 53124139Sjoerg if (*thisname != '\0') 53224139Sjoerg { 53324139Sjoerg /* did the value change since last time? */ 53424139Sjoerg if (*lp != *states) 53524139Sjoerg { 53624139Sjoerg /* yes, move and change */ 537175420Speter Move_to(cpustates_column + *colp, y_cpustates + cpu); 538175420Speter lastline = y_cpustates + cpu; 53924139Sjoerg 54024139Sjoerg /* retrieve value and remember it */ 54124139Sjoerg value = *states; 54224139Sjoerg 54324139Sjoerg /* if percentage is >= 1000, print it as 100% */ 54424139Sjoerg printf((value >= 1000 ? "%4.0f" : "%4.1f"), 54524139Sjoerg ((double)value)/10.); 54624139Sjoerg 54724139Sjoerg /* remember it for next time */ 54889758Sdwmalone *lp = value; 54924139Sjoerg } 55024139Sjoerg } 55124139Sjoerg 55224139Sjoerg /* increment and move on */ 55324139Sjoerg lp++; 55424139Sjoerg states++; 55524139Sjoerg colp++; 55624139Sjoerg } 55724139Sjoerg} 558175420Speter} 55924139Sjoerg 56024139Sjoergz_cpustates() 56124139Sjoerg 56224139Sjoerg{ 56324139Sjoerg register int i = 0; 564175420Speter register char **names; 56524139Sjoerg register char *thisname; 56624139Sjoerg register int *lp; 567218171Sjhb int cpu, value; 56824139Sjoerg 569175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) { 570175420Speter names = cpustate_names; 571175420Speter 57224139Sjoerg /* show tag and bump lastline */ 573175420Speter if (num_cpus == 1) 574175420Speter printf("\nCPU: "); 575218171Sjhb else { 576218171Sjhb value = printf("\nCPU %d: ", cpu); 577218171Sjhb while (value++ <= cpustates_column) 578218171Sjhb printf(" "); 579218171Sjhb } 58024139Sjoerg lastline++; 58124139Sjoerg 58224139Sjoerg while ((thisname = *names++) != NULL) 58324139Sjoerg { 58424139Sjoerg if (*thisname != '\0') 58524139Sjoerg { 586175420Speter printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname); 58724139Sjoerg } 58824139Sjoerg } 589175420Speter} 59024139Sjoerg 59124139Sjoerg /* fill the "last" array with all -1s, to insure correct updating */ 59224139Sjoerg lp = lcpustates; 593175420Speter i = num_cpustates * num_cpus; 59424139Sjoerg while (--i >= 0) 59524139Sjoerg { 59624139Sjoerg *lp++ = -1; 59724139Sjoerg } 59824139Sjoerg} 59924139Sjoerg 60024139Sjoerg/* 60124139Sjoerg * *_memory(stats) - print "Memory: " followed by the memory summary string 60224139Sjoerg * 60324139Sjoerg * Assumptions: cursor is on "lastline" 60424139Sjoerg * for i_memory ONLY: cursor is on the previous line 60524139Sjoerg */ 60624139Sjoerg 60724139Sjoergchar memory_buffer[MAX_COLS]; 60824139Sjoerg 60924139Sjoergi_memory(stats) 61024139Sjoerg 61124139Sjoergint *stats; 61224139Sjoerg 61324139Sjoerg{ 61424142Sjoerg fputs("\nMem: ", stdout); 61524139Sjoerg lastline++; 61624139Sjoerg 61724139Sjoerg /* format and print the memory summary */ 61824139Sjoerg summary_format(memory_buffer, stats, memory_names); 61924139Sjoerg fputs(memory_buffer, stdout); 62024139Sjoerg} 62124139Sjoerg 62224139Sjoergu_memory(stats) 62324139Sjoerg 62424139Sjoergint *stats; 62524139Sjoerg 62624139Sjoerg{ 62724139Sjoerg static char new[MAX_COLS]; 62824139Sjoerg 62924139Sjoerg /* format the new line */ 63024139Sjoerg summary_format(new, stats, memory_names); 63124139Sjoerg line_update(memory_buffer, new, x_mem, y_mem); 63224139Sjoerg} 63324139Sjoerg 63424139Sjoerg/* 635239750Sjhb * *_arc(stats) - print "ARC: " followed by the ARC summary string 636239750Sjhb * 637239750Sjhb * Assumptions: cursor is on "lastline" 638239750Sjhb * for i_arc ONLY: cursor is on the previous line 639239750Sjhb */ 640239750Sjhbchar arc_buffer[MAX_COLS]; 641239750Sjhb 642239750Sjhbi_arc(stats) 643239750Sjhb 644239750Sjhbint *stats; 645239750Sjhb 646239750Sjhb{ 647239750Sjhb if (arc_names == NULL) 648239750Sjhb return (0); 649239750Sjhb 650239750Sjhb fputs("\nARC: ", stdout); 651239750Sjhb lastline++; 652239750Sjhb 653239750Sjhb /* format and print the memory summary */ 654239750Sjhb summary_format(arc_buffer, stats, arc_names); 655239750Sjhb fputs(arc_buffer, stdout); 656239750Sjhb} 657239750Sjhb 658239750Sjhbu_arc(stats) 659239750Sjhb 660239750Sjhbint *stats; 661239750Sjhb 662239750Sjhb{ 663239750Sjhb static char new[MAX_COLS]; 664239750Sjhb 665239750Sjhb if (arc_names == NULL) 666239750Sjhb return (0); 667239750Sjhb 668239750Sjhb /* format the new line */ 669239750Sjhb summary_format(new, stats, arc_names); 670239750Sjhb line_update(arc_buffer, new, x_arc, y_arc); 671239750Sjhb} 672239750Sjhb 673239750Sjhb 674239750Sjhb/* 67524142Sjoerg * *_swap(stats) - print "Swap: " followed by the swap summary string 67624142Sjoerg * 67724142Sjoerg * Assumptions: cursor is on "lastline" 67824142Sjoerg * for i_swap ONLY: cursor is on the previous line 67924142Sjoerg */ 68024142Sjoerg 68124142Sjoergchar swap_buffer[MAX_COLS]; 68224142Sjoerg 68324142Sjoergi_swap(stats) 68424142Sjoerg 68524142Sjoergint *stats; 68624142Sjoerg 68724142Sjoerg{ 68824142Sjoerg fputs("\nSwap: ", stdout); 68924142Sjoerg lastline++; 69024142Sjoerg 69124142Sjoerg /* format and print the swap summary */ 69224142Sjoerg summary_format(swap_buffer, stats, swap_names); 69324142Sjoerg fputs(swap_buffer, stdout); 69424142Sjoerg} 69524142Sjoerg 69624142Sjoergu_swap(stats) 69724142Sjoerg 69824142Sjoergint *stats; 69924142Sjoerg 70024142Sjoerg{ 70124142Sjoerg static char new[MAX_COLS]; 70224142Sjoerg 70324142Sjoerg /* format the new line */ 70424142Sjoerg summary_format(new, stats, swap_names); 70524142Sjoerg line_update(swap_buffer, new, x_swap, y_swap); 70624142Sjoerg} 70724142Sjoerg 70824142Sjoerg/* 70924139Sjoerg * *_message() - print the next pending message line, or erase the one 71024139Sjoerg * that is there. 71124139Sjoerg * 71224139Sjoerg * Note that u_message is (currently) the same as i_message. 71324139Sjoerg * 71424139Sjoerg * Assumptions: lastline is consistent 71524139Sjoerg */ 71624139Sjoerg 71724139Sjoerg/* 71824139Sjoerg * i_message is funny because it gets its message asynchronously (with 71924139Sjoerg * respect to screen updates). 72024139Sjoerg */ 72124139Sjoerg 72224139Sjoergstatic char next_msg[MAX_COLS + 5]; 72324139Sjoergstatic int msglen = 0; 72424139Sjoerg/* Invariant: msglen is always the length of the message currently displayed 72524139Sjoerg on the screen (even when next_msg doesn't contain that message). */ 72624139Sjoerg 72724139Sjoergi_message() 72824139Sjoerg 72924139Sjoerg{ 73024139Sjoerg while (lastline < y_message) 73124139Sjoerg { 73224139Sjoerg fputc('\n', stdout); 73324139Sjoerg lastline++; 73424139Sjoerg } 73524139Sjoerg if (next_msg[0] != '\0') 73624139Sjoerg { 73724139Sjoerg standout(next_msg); 73824139Sjoerg msglen = strlen(next_msg); 73924139Sjoerg next_msg[0] = '\0'; 74024139Sjoerg } 74124139Sjoerg else if (msglen > 0) 74224139Sjoerg { 74324139Sjoerg (void) clear_eol(msglen); 74424139Sjoerg msglen = 0; 74524139Sjoerg } 74624139Sjoerg} 74724139Sjoerg 74824139Sjoergu_message() 74924139Sjoerg 75024139Sjoerg{ 75124139Sjoerg i_message(); 75224139Sjoerg} 75324139Sjoerg 75424139Sjoergstatic int header_length; 75524139Sjoerg 75624139Sjoerg/* 757146344Skeramida * Trim a header string to the current display width and return a newly 758146344Skeramida * allocated area with the trimmed header. 759146344Skeramida */ 760146344Skeramida 761146344Skeramidachar * 762146344Skeramidatrim_header(text) 763146344Skeramida 764146344Skeramidachar *text; 765146344Skeramida 766146344Skeramida{ 767146344Skeramida char *s; 768146344Skeramida int width; 769146344Skeramida 770146344Skeramida s = NULL; 771223342Sdelphij width = display_width; 772146344Skeramida header_length = strlen(text); 773146344Skeramida if (header_length >= width) { 774146344Skeramida s = malloc((width + 1) * sizeof(char)); 775146344Skeramida if (s == NULL) 776146344Skeramida return (NULL); 777146344Skeramida strncpy(s, text, width); 778146344Skeramida s[width] = '\0'; 779146344Skeramida } 780146344Skeramida return (s); 781146344Skeramida} 782146344Skeramida 783146344Skeramida/* 78424139Sjoerg * *_header(text) - print the header for the process area 78524139Sjoerg * 78624139Sjoerg * Assumptions: cursor is on the previous line and lastline is consistent 78724139Sjoerg */ 78824139Sjoerg 78924139Sjoergi_header(text) 79024139Sjoerg 79124139Sjoergchar *text; 79224139Sjoerg 79324139Sjoerg{ 794146344Skeramida char *s; 795146344Skeramida 796146344Skeramida s = trim_header(text); 797146344Skeramida if (s != NULL) 798146344Skeramida text = s; 799146344Skeramida 80024139Sjoerg if (header_status == ON) 80124139Sjoerg { 80224139Sjoerg putchar('\n'); 803223342Sdelphij fputs(text, stdout); 80424139Sjoerg lastline++; 80524139Sjoerg } 80624139Sjoerg else if (header_status == ERASE) 80724139Sjoerg { 80824139Sjoerg header_status = OFF; 80924139Sjoerg } 810146344Skeramida free(s); 81124139Sjoerg} 81224139Sjoerg 81324139Sjoerg/*ARGSUSED*/ 81424139Sjoergu_header(text) 81524139Sjoerg 81624139Sjoergchar *text; /* ignored */ 81724139Sjoerg 81824139Sjoerg{ 819146344Skeramida 82024139Sjoerg if (header_status == ERASE) 82124139Sjoerg { 82224139Sjoerg putchar('\n'); 82324139Sjoerg lastline++; 82424139Sjoerg clear_eol(header_length); 82524139Sjoerg header_status = OFF; 82624139Sjoerg } 82724139Sjoerg} 82824139Sjoerg 82924139Sjoerg/* 83024139Sjoerg * *_process(line, thisline) - print one process line 83124139Sjoerg * 83224139Sjoerg * Assumptions: lastline is consistent 83324139Sjoerg */ 83424139Sjoerg 83524139Sjoergi_process(line, thisline) 83624139Sjoerg 83724139Sjoergint line; 83824139Sjoergchar *thisline; 83924139Sjoerg 84024139Sjoerg{ 84124139Sjoerg register char *p; 84224139Sjoerg register char *base; 84324139Sjoerg 84424139Sjoerg /* make sure we are on the correct line */ 84524139Sjoerg while (lastline < y_procs + line) 84624139Sjoerg { 84724139Sjoerg putchar('\n'); 84824139Sjoerg lastline++; 84924139Sjoerg } 85024139Sjoerg 85124139Sjoerg /* truncate the line to conform to our current screen width */ 85224139Sjoerg thisline[display_width] = '\0'; 85324139Sjoerg 85424139Sjoerg /* write the line out */ 85524139Sjoerg fputs(thisline, stdout); 85624139Sjoerg 85724139Sjoerg /* copy it in to our buffer */ 85824139Sjoerg base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; 85924139Sjoerg p = strecpy(base, thisline); 86024139Sjoerg 86124139Sjoerg /* zero fill the rest of it */ 86224139Sjoerg memzero(p, display_width - (p - base)); 86324139Sjoerg} 86424139Sjoerg 86524139Sjoergu_process(line, newline) 86624139Sjoerg 86724139Sjoergint line; 86824139Sjoergchar *newline; 86924139Sjoerg 87024139Sjoerg{ 87124139Sjoerg register char *optr; 87224139Sjoerg register int screen_line = line + Header_lines; 87324139Sjoerg register char *bufferline; 87424139Sjoerg 87524139Sjoerg /* remember a pointer to the current line in the screen buffer */ 87624139Sjoerg bufferline = &screenbuf[lineindex(line)]; 87724139Sjoerg 87824139Sjoerg /* truncate the line to conform to our current screen width */ 87924139Sjoerg newline[display_width] = '\0'; 88024139Sjoerg 88124139Sjoerg /* is line higher than we went on the last display? */ 88224139Sjoerg if (line >= last_hi) 88324139Sjoerg { 88424139Sjoerg /* yes, just ignore screenbuf and write it out directly */ 88524139Sjoerg /* get positioned on the correct line */ 88624139Sjoerg if (screen_line - lastline == 1) 88724139Sjoerg { 88824139Sjoerg putchar('\n'); 88924139Sjoerg lastline++; 89024139Sjoerg } 89124139Sjoerg else 89224139Sjoerg { 89324139Sjoerg Move_to(0, screen_line); 89424139Sjoerg lastline = screen_line; 89524139Sjoerg } 89624139Sjoerg 89724139Sjoerg /* now write the line */ 89824139Sjoerg fputs(newline, stdout); 89924139Sjoerg 90024139Sjoerg /* copy it in to the buffer */ 90124139Sjoerg optr = strecpy(bufferline, newline); 90224139Sjoerg 90324139Sjoerg /* zero fill the rest of it */ 90424139Sjoerg memzero(optr, display_width - (optr - bufferline)); 90524139Sjoerg } 90624139Sjoerg else 90724139Sjoerg { 90824139Sjoerg line_update(bufferline, newline, 0, line + Header_lines); 90924139Sjoerg } 91024139Sjoerg} 91124139Sjoerg 91224139Sjoergu_endscreen(hi) 91324139Sjoerg 91424139Sjoergregister int hi; 91524139Sjoerg 91624139Sjoerg{ 91724139Sjoerg register int screen_line = hi + Header_lines; 91824139Sjoerg register int i; 91924139Sjoerg 92024139Sjoerg if (smart_terminal) 92124139Sjoerg { 92224139Sjoerg if (hi < last_hi) 92324139Sjoerg { 92424139Sjoerg /* need to blank the remainder of the screen */ 92524139Sjoerg /* but only if there is any screen left below this line */ 92624139Sjoerg if (lastline + 1 < screen_length) 92724139Sjoerg { 92824139Sjoerg /* efficiently move to the end of currently displayed info */ 92924139Sjoerg if (screen_line - lastline < 5) 93024139Sjoerg { 93124139Sjoerg while (lastline < screen_line) 93224139Sjoerg { 93324139Sjoerg putchar('\n'); 93424139Sjoerg lastline++; 93524139Sjoerg } 93624139Sjoerg } 93724139Sjoerg else 93824139Sjoerg { 93924139Sjoerg Move_to(0, screen_line); 94024139Sjoerg lastline = screen_line; 94124139Sjoerg } 94224139Sjoerg 94324139Sjoerg if (clear_to_end) 94424139Sjoerg { 94524139Sjoerg /* we can do this the easy way */ 94624139Sjoerg putcap(clear_to_end); 94724139Sjoerg } 94824139Sjoerg else 94924139Sjoerg { 95024139Sjoerg /* use clear_eol on each line */ 95124139Sjoerg i = hi; 95224139Sjoerg while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) 95324139Sjoerg { 95424139Sjoerg putchar('\n'); 95524139Sjoerg } 95624139Sjoerg } 95724139Sjoerg } 95824139Sjoerg } 95924139Sjoerg last_hi = hi; 96024139Sjoerg 96124139Sjoerg /* move the cursor to a pleasant place */ 96224139Sjoerg Move_to(x_idlecursor, y_idlecursor); 96324139Sjoerg lastline = y_idlecursor; 96424139Sjoerg } 96524139Sjoerg else 96624139Sjoerg { 96724139Sjoerg /* separate this display from the next with some vertical room */ 96824139Sjoerg fputs("\n\n", stdout); 96924139Sjoerg } 97024139Sjoerg} 97124139Sjoerg 97224139Sjoergdisplay_header(t) 97324139Sjoerg 97424139Sjoergint t; 97524139Sjoerg 97624139Sjoerg{ 97724139Sjoerg if (t) 97824139Sjoerg { 97924139Sjoerg header_status = ON; 98024139Sjoerg } 98124139Sjoerg else if (header_status == ON) 98224139Sjoerg { 98324139Sjoerg header_status = ERASE; 98424139Sjoerg } 98524139Sjoerg} 98624139Sjoerg 98724139Sjoerg/*VARARGS2*/ 98824139Sjoergnew_message(type, msgfmt, a1, a2, a3) 98924139Sjoerg 99024139Sjoergint type; 99124139Sjoergchar *msgfmt; 99224139Sjoergcaddr_t a1, a2, a3; 99324139Sjoerg 99424139Sjoerg{ 99524139Sjoerg register int i; 99624139Sjoerg 99724139Sjoerg /* first, format the message */ 99866641Simp (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3); 99924139Sjoerg 100024139Sjoerg if (msglen > 0) 100124139Sjoerg { 100224139Sjoerg /* message there already -- can we clear it? */ 100324139Sjoerg if (!overstrike) 100424139Sjoerg { 100524139Sjoerg /* yes -- write it and clear to end */ 100624139Sjoerg i = strlen(next_msg); 100724139Sjoerg if ((type & MT_delayed) == 0) 100824139Sjoerg { 100924139Sjoerg type & MT_standout ? standout(next_msg) : 101024139Sjoerg fputs(next_msg, stdout); 101124139Sjoerg (void) clear_eol(msglen - i); 101224139Sjoerg msglen = i; 101324139Sjoerg next_msg[0] = '\0'; 101424139Sjoerg } 101524139Sjoerg } 101624139Sjoerg } 101724139Sjoerg else 101824139Sjoerg { 101924139Sjoerg if ((type & MT_delayed) == 0) 102024139Sjoerg { 102124139Sjoerg type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout); 102224139Sjoerg msglen = strlen(next_msg); 102324139Sjoerg next_msg[0] = '\0'; 102424139Sjoerg } 102524139Sjoerg } 102624139Sjoerg} 102724139Sjoerg 102824139Sjoergclear_message() 102924139Sjoerg 103024139Sjoerg{ 103124139Sjoerg if (clear_eol(msglen) == 1) 103224139Sjoerg { 103324139Sjoerg putchar('\r'); 103424139Sjoerg } 103524139Sjoerg} 103624139Sjoerg 103724139Sjoergreadline(buffer, size, numeric) 103824139Sjoerg 103924139Sjoergchar *buffer; 104024139Sjoergint size; 104124139Sjoergint numeric; 104224139Sjoerg 104324139Sjoerg{ 104424139Sjoerg register char *ptr = buffer; 104524139Sjoerg register char ch; 104624139Sjoerg register char cnt = 0; 104724139Sjoerg register char maxcnt = 0; 104824139Sjoerg 104924139Sjoerg /* allow room for null terminator */ 105024139Sjoerg size -= 1; 105124139Sjoerg 105224139Sjoerg /* read loop */ 105324139Sjoerg while ((fflush(stdout), read(0, ptr, 1) > 0)) 105424139Sjoerg { 105524139Sjoerg /* newline means we are done */ 105624142Sjoerg if ((ch = *ptr) == '\n' || ch == '\r') 105724139Sjoerg { 105824139Sjoerg break; 105924139Sjoerg } 106024139Sjoerg 106124139Sjoerg /* handle special editing characters */ 106224139Sjoerg if (ch == ch_kill) 106324139Sjoerg { 106424139Sjoerg /* kill line -- account for overstriking */ 106524139Sjoerg if (overstrike) 106624139Sjoerg { 106724139Sjoerg msglen += maxcnt; 106824139Sjoerg } 106924139Sjoerg 107024139Sjoerg /* return null string */ 107124139Sjoerg *buffer = '\0'; 107224139Sjoerg putchar('\r'); 107324139Sjoerg return(-1); 107424139Sjoerg } 107524139Sjoerg else if (ch == ch_erase) 107624139Sjoerg { 107724139Sjoerg /* erase previous character */ 107824139Sjoerg if (cnt <= 0) 107924139Sjoerg { 108024139Sjoerg /* none to erase! */ 108124139Sjoerg putchar('\7'); 108224139Sjoerg } 108324139Sjoerg else 108424139Sjoerg { 108524139Sjoerg fputs("\b \b", stdout); 108624139Sjoerg ptr--; 108724139Sjoerg cnt--; 108824139Sjoerg } 108924139Sjoerg } 109024139Sjoerg /* check for character validity and buffer overflow */ 109124139Sjoerg else if (cnt == size || (numeric && !isdigit(ch)) || 109224139Sjoerg !isprint(ch)) 109324139Sjoerg { 109424139Sjoerg /* not legal */ 109524139Sjoerg putchar('\7'); 109624139Sjoerg } 109724139Sjoerg else 109824139Sjoerg { 109924139Sjoerg /* echo it and store it in the buffer */ 110024139Sjoerg putchar(ch); 110124139Sjoerg ptr++; 110224139Sjoerg cnt++; 110324139Sjoerg if (cnt > maxcnt) 110424139Sjoerg { 110524139Sjoerg maxcnt = cnt; 110624139Sjoerg } 110724139Sjoerg } 110824139Sjoerg } 110924139Sjoerg 111024139Sjoerg /* all done -- null terminate the string */ 111124139Sjoerg *ptr = '\0'; 111224139Sjoerg 111324139Sjoerg /* account for the extra characters in the message area */ 111424139Sjoerg /* (if terminal overstrikes, remember the furthest they went) */ 111524139Sjoerg msglen += overstrike ? maxcnt : cnt; 111624139Sjoerg 111724139Sjoerg /* return either inputted number or string length */ 111824139Sjoerg putchar('\r'); 111924139Sjoerg return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); 112024139Sjoerg} 112124139Sjoerg 112224139Sjoerg/* internal support routines */ 112324139Sjoerg 112424139Sjoergstatic int string_count(pp) 112524139Sjoerg 112624139Sjoergregister char **pp; 112724139Sjoerg 112824139Sjoerg{ 112924139Sjoerg register int cnt; 113024139Sjoerg 113124139Sjoerg cnt = 0; 113224139Sjoerg while (*pp++ != NULL) 113324139Sjoerg { 113424139Sjoerg cnt++; 113524139Sjoerg } 113624139Sjoerg return(cnt); 113724139Sjoerg} 113824139Sjoerg 113924139Sjoergstatic void summary_format(str, numbers, names) 114024139Sjoerg 114124139Sjoergchar *str; 114224139Sjoergint *numbers; 114324139Sjoergregister char **names; 114424139Sjoerg 114524139Sjoerg{ 114624139Sjoerg register char *p; 114724139Sjoerg register int num; 114824139Sjoerg register char *thisname; 114924139Sjoerg register int useM = No; 115024139Sjoerg 115124139Sjoerg /* format each number followed by its string */ 115224139Sjoerg p = str; 115324139Sjoerg while ((thisname = *names++) != NULL) 115424139Sjoerg { 115524139Sjoerg /* get the number to format */ 115624139Sjoerg num = *numbers++; 115724139Sjoerg 115824139Sjoerg /* display only non-zero numbers */ 115924139Sjoerg if (num > 0) 116024139Sjoerg { 116124139Sjoerg /* is this number in kilobytes? */ 116224139Sjoerg if (thisname[0] == 'K') 116324139Sjoerg { 116424139Sjoerg /* yes: format it as a memory value */ 116524139Sjoerg p = strecpy(p, format_k(num)); 116624139Sjoerg 116724139Sjoerg /* skip over the K, since it was included by format_k */ 116824139Sjoerg p = strecpy(p, thisname+1); 116924139Sjoerg } 117024139Sjoerg else 117124139Sjoerg { 117224139Sjoerg p = strecpy(p, itoa(num)); 117324139Sjoerg p = strecpy(p, thisname); 117424139Sjoerg } 117524139Sjoerg } 117624139Sjoerg 117724139Sjoerg /* ignore negative numbers, but display corresponding string */ 117824139Sjoerg else if (num < 0) 117924139Sjoerg { 118024139Sjoerg p = strecpy(p, thisname); 118124139Sjoerg } 118224139Sjoerg } 118324139Sjoerg 118424139Sjoerg /* if the last two characters in the string are ", ", delete them */ 118524139Sjoerg p -= 2; 118624139Sjoerg if (p >= str && p[0] == ',' && p[1] == ' ') 118724139Sjoerg { 118824139Sjoerg *p = '\0'; 118924139Sjoerg } 119024139Sjoerg} 119124139Sjoerg 119224139Sjoergstatic void line_update(old, new, start, line) 119324139Sjoerg 119424139Sjoergregister char *old; 119524139Sjoergregister char *new; 119624139Sjoergint start; 119724139Sjoergint line; 119824139Sjoerg 119924139Sjoerg{ 120024139Sjoerg register int ch; 120124139Sjoerg register int diff; 120224139Sjoerg register int newcol = start + 1; 120324139Sjoerg register int lastcol = start; 120424139Sjoerg char cursor_on_line = No; 120524139Sjoerg char *current; 120624139Sjoerg 120724139Sjoerg /* compare the two strings and only rewrite what has changed */ 120824139Sjoerg current = old; 120924139Sjoerg#ifdef DEBUG 121024139Sjoerg fprintf(debug, "line_update, starting at %d\n", start); 121124139Sjoerg fputs(old, debug); 121224139Sjoerg fputc('\n', debug); 121324139Sjoerg fputs(new, debug); 121424139Sjoerg fputs("\n-\n", debug); 121524139Sjoerg#endif 121624139Sjoerg 121724139Sjoerg /* start things off on the right foot */ 121824139Sjoerg /* this is to make sure the invariants get set up right */ 121924139Sjoerg if ((ch = *new++) != *old) 122024139Sjoerg { 122124139Sjoerg if (line - lastline == 1 && start == 0) 122224139Sjoerg { 122324139Sjoerg putchar('\n'); 122424139Sjoerg } 122524139Sjoerg else 122624139Sjoerg { 122724139Sjoerg Move_to(start, line); 122824139Sjoerg } 122924139Sjoerg cursor_on_line = Yes; 123024139Sjoerg putchar(ch); 123124139Sjoerg *old = ch; 123224139Sjoerg lastcol = 1; 123324139Sjoerg } 123424139Sjoerg old++; 123524139Sjoerg 123624139Sjoerg /* 123724139Sjoerg * main loop -- check each character. If the old and new aren't the 123824139Sjoerg * same, then update the display. When the distance from the 123924139Sjoerg * current cursor position to the new change is small enough, 124024139Sjoerg * the characters that belong there are written to move the 124124139Sjoerg * cursor over. 124224139Sjoerg * 124324139Sjoerg * Invariants: 124424139Sjoerg * lastcol is the column where the cursor currently is sitting 124524139Sjoerg * (always one beyond the end of the last mismatch). 124624139Sjoerg */ 124724139Sjoerg do /* yes, a do...while */ 124824139Sjoerg { 124924139Sjoerg if ((ch = *new++) != *old) 125024139Sjoerg { 125124139Sjoerg /* new character is different from old */ 125224139Sjoerg /* make sure the cursor is on top of this character */ 125324139Sjoerg diff = newcol - lastcol; 125424139Sjoerg if (diff > 0) 125524139Sjoerg { 125624139Sjoerg /* some motion is required--figure out which is shorter */ 125724139Sjoerg if (diff < 6 && cursor_on_line) 125824139Sjoerg { 125924139Sjoerg /* overwrite old stuff--get it out of the old buffer */ 126024139Sjoerg printf("%.*s", diff, ¤t[lastcol-start]); 126124139Sjoerg } 126224139Sjoerg else 126324139Sjoerg { 126424139Sjoerg /* use cursor addressing */ 126524139Sjoerg Move_to(newcol, line); 126624139Sjoerg cursor_on_line = Yes; 126724139Sjoerg } 126824139Sjoerg /* remember where the cursor is */ 126924139Sjoerg lastcol = newcol + 1; 127024139Sjoerg } 127124139Sjoerg else 127224139Sjoerg { 127324139Sjoerg /* already there, update position */ 127424139Sjoerg lastcol++; 127524139Sjoerg } 127624139Sjoerg 127724139Sjoerg /* write what we need to */ 127824139Sjoerg if (ch == '\0') 127924139Sjoerg { 128024139Sjoerg /* at the end--terminate with a clear-to-end-of-line */ 128124139Sjoerg (void) clear_eol(strlen(old)); 128224139Sjoerg } 128324139Sjoerg else 128424139Sjoerg { 128524139Sjoerg /* write the new character */ 128624139Sjoerg putchar(ch); 128724139Sjoerg } 128824139Sjoerg /* put the new character in the screen buffer */ 128924139Sjoerg *old = ch; 129024139Sjoerg } 129124139Sjoerg 129224139Sjoerg /* update working column and screen buffer pointer */ 129324139Sjoerg newcol++; 129424139Sjoerg old++; 129524139Sjoerg 129624139Sjoerg } while (ch != '\0'); 129724139Sjoerg 129824139Sjoerg /* zero out the rest of the line buffer -- MUST BE DONE! */ 129924139Sjoerg diff = display_width - newcol; 130024139Sjoerg if (diff > 0) 130124139Sjoerg { 130224139Sjoerg memzero(old, diff); 130324139Sjoerg } 130424139Sjoerg 130524139Sjoerg /* remember where the current line is */ 130624139Sjoerg if (cursor_on_line) 130724139Sjoerg { 130824139Sjoerg lastline = line; 130924139Sjoerg } 131024139Sjoerg} 131124139Sjoerg 131224139Sjoerg/* 131324139Sjoerg * printable(str) - make the string pointed to by "str" into one that is 131424139Sjoerg * printable (i.e.: all ascii), by converting all non-printable 131524139Sjoerg * characters into '?'. Replacements are done in place and a pointer 131624139Sjoerg * to the original buffer is returned. 131724139Sjoerg */ 131824139Sjoerg 131924139Sjoergchar *printable(str) 132024139Sjoerg 132124139Sjoergchar *str; 132224139Sjoerg 132324139Sjoerg{ 132424139Sjoerg register char *ptr; 132524139Sjoerg register char ch; 132624139Sjoerg 132724139Sjoerg ptr = str; 132824139Sjoerg while ((ch = *ptr) != '\0') 132924139Sjoerg { 133024139Sjoerg if (!isprint(ch)) 133124139Sjoerg { 133224139Sjoerg *ptr = '?'; 133324139Sjoerg } 133424139Sjoerg ptr++; 133524139Sjoerg } 133624139Sjoerg return(str); 133724139Sjoerg} 133842447Sobrien 133942447Sobrieni_uptime(bt, tod) 134042447Sobrien 134142447Sobrienstruct timeval* bt; 134242447Sobrientime_t *tod; 134342447Sobrien 134442447Sobrien{ 134542447Sobrien time_t uptime; 134642447Sobrien int days, hrs, mins, secs; 134742447Sobrien 134842447Sobrien if (bt->tv_sec != -1) { 134942447Sobrien uptime = *tod - bt->tv_sec; 135042447Sobrien days = uptime / 86400; 135142447Sobrien uptime %= 86400; 135242447Sobrien hrs = uptime / 3600; 135342447Sobrien uptime %= 3600; 135442447Sobrien mins = uptime / 60; 135542447Sobrien secs = uptime % 60; 135642447Sobrien 135742447Sobrien /* 135842447Sobrien * Display the uptime. 135942447Sobrien */ 136042447Sobrien 136142447Sobrien if (smart_terminal) 136242447Sobrien { 136342447Sobrien Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); 136442447Sobrien } 136542447Sobrien else 136642447Sobrien { 136742447Sobrien fputs(" ", stdout); 136842447Sobrien } 136942447Sobrien printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); 137042447Sobrien } 137142447Sobrien} 1372