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" 32301836Sngie 33301836Sngie#include <sys/time.h> 34301836Sngie 3524139Sjoerg#include <ctype.h> 3624139Sjoerg#include <time.h> 37301836Sngie#include <unistd.h> 3824139Sjoerg 3924139Sjoerg#include "screen.h" /* interface to screen package */ 4024139Sjoerg#include "layout.h" /* defines for screen position layout */ 4124139Sjoerg#include "display.h" 4224139Sjoerg#include "top.h" 4324139Sjoerg#include "top.local.h" 4424139Sjoerg#include "boolean.h" 4524139Sjoerg#include "machine.h" /* we should eliminate this!!! */ 4624139Sjoerg#include "utils.h" 4724139Sjoerg 4824139Sjoerg#ifdef DEBUG 4924139SjoergFILE *debug; 5024139Sjoerg#endif 5124139Sjoerg 5224139Sjoerg/* imported from screen.c */ 5324139Sjoergextern int overstrike; 5424139Sjoerg 5524139Sjoergstatic int lmpid = 0; 5624139Sjoergstatic int last_hi = 0; /* used in u_process and u_endscreen */ 5724139Sjoergstatic int lastline = 0; 5824139Sjoergstatic int display_width = MAX_COLS; 5924139Sjoerg 6024139Sjoerg#define lineindex(l) ((l)*display_width) 6124139Sjoerg 6224139Sjoerg 6324139Sjoerg/* things initialized by display_init and used thruout */ 6424139Sjoerg 6524139Sjoerg/* buffer of proc information lines for display updating */ 6624139Sjoergchar *screenbuf = NULL; 6724139Sjoerg 6824139Sjoergstatic char **procstate_names; 6924139Sjoergstatic char **cpustate_names; 7024139Sjoergstatic char **memory_names; 71237656Sjhbstatic char **arc_names; 7224142Sjoergstatic char **swap_names; 7324139Sjoerg 7424139Sjoergstatic int num_procstates; 7524139Sjoergstatic int num_cpustates; 7624139Sjoergstatic int num_memory; 7724142Sjoergstatic int num_swap; 7824139Sjoerg 7924139Sjoergstatic int *lprocstates; 8024139Sjoergstatic int *lcpustates; 8124139Sjoergstatic int *lmemory; 8224142Sjoergstatic int *lswap; 8324139Sjoerg 84175420Speterstatic int num_cpus; 8524139Sjoergstatic int *cpustate_columns; 8624139Sjoergstatic int cpustate_total_length; 87175420Speterstatic int cpustates_column; 8824139Sjoerg 8924139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON; 9024139Sjoerg 9124139Sjoergstatic int string_count(); 9224139Sjoergstatic void summary_format(); 9324139Sjoergstatic void line_update(); 9424139Sjoerg 95175420Speterint x_lastpid = 10; 96175420Speterint y_lastpid = 0; 97175420Speterint x_loadave = 33; 98175420Speterint x_loadave_nompid = 15; 99175420Speterint y_loadave = 0; 100175420Speterint x_procstate = 0; 101175420Speterint y_procstate = 1; 102175420Speterint x_brkdn = 15; 103175420Speterint y_brkdn = 1; 104175420Speterint x_mem = 5; 105175420Speterint y_mem = 3; 106237656Sjhbint x_arc = 5; 107237656Sjhbint y_arc = 4; 108175420Speterint x_swap = 6; 109175420Speterint y_swap = 4; 110175420Speterint y_message = 5; 111175420Speterint x_header = 0; 112175420Speterint y_header = 6; 113175420Speterint x_idlecursor = 0; 114175420Speterint y_idlecursor = 5; 115175420Speterint y_procs = 7; 116175420Speter 117175420Speterint y_cpustates = 2; 118175420Speterint Header_lines = 7; 119175420Speter 12024139Sjoergint display_resize() 12124139Sjoerg 12224139Sjoerg{ 12324139Sjoerg register int lines; 12424139Sjoerg 12524139Sjoerg /* first, deallocate any previous buffer that may have been there */ 12624139Sjoerg if (screenbuf != NULL) 12724139Sjoerg { 12824139Sjoerg free(screenbuf); 12924139Sjoerg } 13024139Sjoerg 13124139Sjoerg /* calculate the current dimensions */ 13224139Sjoerg /* if operating in "dumb" mode, we only need one line */ 13324139Sjoerg lines = smart_terminal ? screen_length - Header_lines : 1; 13424139Sjoerg 135101692Sdwmalone if (lines < 0) 136101692Sdwmalone lines = 0; 13724139Sjoerg /* we don't want more than MAX_COLS columns, since the machine-dependent 13824139Sjoerg modules make static allocations based on MAX_COLS and we don't want 13924139Sjoerg to run off the end of their buffers */ 14024139Sjoerg display_width = screen_width; 14124139Sjoerg if (display_width >= MAX_COLS) 14224139Sjoerg { 14324139Sjoerg display_width = MAX_COLS - 1; 14424139Sjoerg } 14524139Sjoerg 14624139Sjoerg /* now, allocate space for the screen buffer */ 14724139Sjoerg screenbuf = (char *)malloc(lines * display_width); 14824139Sjoerg if (screenbuf == (char *)NULL) 14924139Sjoerg { 15024139Sjoerg /* oops! */ 15124139Sjoerg return(-1); 15224139Sjoerg } 15324139Sjoerg 15424139Sjoerg /* return number of lines available */ 15524139Sjoerg /* for dumb terminals, pretend like we can show any amount */ 15624139Sjoerg return(smart_terminal ? lines : Largest); 15724139Sjoerg} 15824139Sjoerg 159223936Sjhbint display_updatecpus(statics) 16024139Sjoerg 16124139Sjoergstruct statics *statics; 16224139Sjoerg 16324139Sjoerg{ 164224205Sjhb register int *lp; 16524139Sjoerg register int lines; 16624139Sjoerg register int i; 167223936Sjhb 16824139Sjoerg /* call resize to do the dirty work */ 16924139Sjoerg lines = display_resize(); 170224205Sjhb if (pcpu_stats) 171224205Sjhb num_cpus = statics->ncpus; 172224205Sjhb else 173224205Sjhb num_cpus = 1; 174175420Speter cpustates_column = 5; /* CPU: */ 175175420Speter if (num_cpus != 1) 176175420Speter cpustates_column += 2; /* CPU 0: */ 177175420Speter for (i = num_cpus; i > 9; i /= 10) 178175420Speter cpustates_column++; 17924139Sjoerg 180224205Sjhb /* fill the "last" array with all -1s, to insure correct updating */ 181224205Sjhb lp = lcpustates; 182224205Sjhb i = num_cpustates * num_cpus; 183224205Sjhb while (--i >= 0) 184224205Sjhb { 185224205Sjhb *lp++ = -1; 186224205Sjhb } 187224205Sjhb 188223936Sjhb return(lines); 189223936Sjhb} 190223936Sjhb 191223936Sjhbint display_init(statics) 192223936Sjhb 193223936Sjhbstruct statics *statics; 194223936Sjhb 195223936Sjhb{ 196223936Sjhb register int lines; 197223936Sjhb register char **pp; 198223936Sjhb register int *ip; 199223936Sjhb register int i; 200223936Sjhb 201223936Sjhb lines = display_updatecpus(statics); 202223936Sjhb 20324139Sjoerg /* only do the rest if we need to */ 20424139Sjoerg if (lines > -1) 20524139Sjoerg { 20624139Sjoerg /* save pointers and allocate space for names */ 20724139Sjoerg procstate_names = statics->procstate_names; 20824139Sjoerg num_procstates = string_count(procstate_names); 20924139Sjoerg lprocstates = (int *)malloc(num_procstates * sizeof(int)); 21024139Sjoerg 21124139Sjoerg cpustate_names = statics->cpustate_names; 21224142Sjoerg 21324142Sjoerg swap_names = statics->swap_names; 21424142Sjoerg num_swap = string_count(swap_names); 21524142Sjoerg lswap = (int *)malloc(num_swap * sizeof(int)); 21624139Sjoerg num_cpustates = string_count(cpustate_names); 217224205Sjhb lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus); 21824139Sjoerg cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); 21924139Sjoerg 22024139Sjoerg memory_names = statics->memory_names; 22124139Sjoerg num_memory = string_count(memory_names); 22224139Sjoerg lmemory = (int *)malloc(num_memory * sizeof(int)); 22324139Sjoerg 224237656Sjhb arc_names = statics->arc_names; 225237656Sjhb 22624139Sjoerg /* calculate starting columns where needed */ 22724139Sjoerg cpustate_total_length = 0; 22824139Sjoerg pp = cpustate_names; 22924139Sjoerg ip = cpustate_columns; 23024139Sjoerg while (*pp != NULL) 23124139Sjoerg { 23289758Sdwmalone *ip++ = cpustate_total_length; 23324139Sjoerg if ((i = strlen(*pp++)) > 0) 23424139Sjoerg { 23524139Sjoerg cpustate_total_length += i + 8; 23624139Sjoerg } 23724139Sjoerg } 23824139Sjoerg } 23924139Sjoerg 24024139Sjoerg /* return number of lines available */ 24124139Sjoerg return(lines); 24224139Sjoerg} 24324139Sjoerg 244301836Sngievoid 24524139Sjoergi_loadave(mpid, avenrun) 24624139Sjoerg 24724139Sjoergint mpid; 24824139Sjoergdouble *avenrun; 24924139Sjoerg 25024139Sjoerg{ 25124139Sjoerg register int i; 25224139Sjoerg 25324139Sjoerg /* i_loadave also clears the screen, since it is first */ 25424139Sjoerg clear(); 25524139Sjoerg 25624139Sjoerg /* mpid == -1 implies this system doesn't have an _mpid */ 25724139Sjoerg if (mpid != -1) 25824139Sjoerg { 25924139Sjoerg printf("last pid: %5d; ", mpid); 26024139Sjoerg } 26124139Sjoerg 26224139Sjoerg printf("load averages"); 26324139Sjoerg 26424139Sjoerg for (i = 0; i < 3; i++) 26524139Sjoerg { 26624139Sjoerg printf("%c %5.2f", 26724139Sjoerg i == 0 ? ':' : ',', 26824139Sjoerg avenrun[i]); 26924139Sjoerg } 27024139Sjoerg lmpid = mpid; 27124139Sjoerg} 27224139Sjoerg 273301836Sngievoid 27424139Sjoergu_loadave(mpid, avenrun) 27524139Sjoerg 27624139Sjoergint mpid; 27724139Sjoergdouble *avenrun; 27824139Sjoerg 27924139Sjoerg{ 28024139Sjoerg register int i; 28124139Sjoerg 28224139Sjoerg if (mpid != -1) 28324139Sjoerg { 28424139Sjoerg /* change screen only when value has really changed */ 28524139Sjoerg if (mpid != lmpid) 28624139Sjoerg { 28724139Sjoerg Move_to(x_lastpid, y_lastpid); 28824139Sjoerg printf("%5d", mpid); 28924139Sjoerg lmpid = mpid; 29024139Sjoerg } 29124139Sjoerg 29224139Sjoerg /* i remembers x coordinate to move to */ 29324139Sjoerg i = x_loadave; 29424139Sjoerg } 29524139Sjoerg else 29624139Sjoerg { 29724139Sjoerg i = x_loadave_nompid; 29824139Sjoerg } 29924139Sjoerg 30024139Sjoerg /* move into position for load averages */ 30124139Sjoerg Move_to(i, y_loadave); 30224139Sjoerg 30324139Sjoerg /* display new load averages */ 30424139Sjoerg /* we should optimize this and only display changes */ 30524139Sjoerg for (i = 0; i < 3; i++) 30624139Sjoerg { 30724139Sjoerg printf("%s%5.2f", 30824139Sjoerg i == 0 ? "" : ", ", 30924139Sjoerg avenrun[i]); 31024139Sjoerg } 31124139Sjoerg} 31224139Sjoerg 313301836Sngievoid 31424139Sjoergi_timeofday(tod) 31524139Sjoerg 31624139Sjoergtime_t *tod; 31724139Sjoerg 31824139Sjoerg{ 31924139Sjoerg /* 32024139Sjoerg * Display the current time. 32124139Sjoerg * "ctime" always returns a string that looks like this: 32224139Sjoerg * 32324139Sjoerg * Sun Sep 16 01:03:52 1973 32424139Sjoerg * 012345678901234567890123 32524139Sjoerg * 1 2 32624139Sjoerg * 32724139Sjoerg * We want indices 11 thru 18 (length 8). 32824139Sjoerg */ 32924139Sjoerg 33024139Sjoerg if (smart_terminal) 33124139Sjoerg { 33224139Sjoerg Move_to(screen_width - 8, 0); 33324139Sjoerg } 33424139Sjoerg else 33524139Sjoerg { 33624139Sjoerg fputs(" ", stdout); 33724139Sjoerg } 33824139Sjoerg#ifdef DEBUG 33924139Sjoerg { 34024139Sjoerg char *foo; 34124139Sjoerg foo = ctime(tod); 34224139Sjoerg fputs(foo, stdout); 34324139Sjoerg } 34424139Sjoerg#endif 34524139Sjoerg printf("%-8.8s\n", &(ctime(tod)[11])); 34624139Sjoerg lastline = 1; 34724139Sjoerg} 34824139Sjoerg 34924139Sjoergstatic int ltotal = 0; 35089758Sdwmalonestatic char procstates_buffer[MAX_COLS]; 35124139Sjoerg 35224139Sjoerg/* 35324139Sjoerg * *_procstates(total, brkdn, names) - print the process summary line 35424139Sjoerg * 35524139Sjoerg * Assumptions: cursor is at the beginning of the line on entry 35624139Sjoerg * lastline is valid 35724139Sjoerg */ 35824139Sjoerg 359301836Sngievoid 36024139Sjoergi_procstates(total, brkdn) 36124139Sjoerg 36224139Sjoergint total; 36324139Sjoergint *brkdn; 36424139Sjoerg 36524139Sjoerg{ 36624139Sjoerg register int i; 36724139Sjoerg 36824139Sjoerg /* write current number of processes and remember the value */ 36924139Sjoerg printf("%d processes:", total); 37024139Sjoerg ltotal = total; 37124139Sjoerg 37224139Sjoerg /* put out enough spaces to get to column 15 */ 37324139Sjoerg i = digits(total); 37424139Sjoerg while (i++ < 4) 37524139Sjoerg { 37624139Sjoerg putchar(' '); 37724139Sjoerg } 37824139Sjoerg 37924139Sjoerg /* format and print the process state summary */ 38024139Sjoerg summary_format(procstates_buffer, brkdn, procstate_names); 38124139Sjoerg fputs(procstates_buffer, stdout); 38224139Sjoerg 38324139Sjoerg /* save the numbers for next time */ 38424139Sjoerg memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 38524139Sjoerg} 38624139Sjoerg 387301836Sngievoid 38824139Sjoergu_procstates(total, brkdn) 38924139Sjoerg 39024139Sjoergint total; 39124139Sjoergint *brkdn; 39224139Sjoerg 39324139Sjoerg{ 39489758Sdwmalone static char new[MAX_COLS]; 39524139Sjoerg register int i; 39624139Sjoerg 39724139Sjoerg /* update number of processes only if it has changed */ 39824139Sjoerg if (ltotal != total) 39924139Sjoerg { 40024139Sjoerg /* move and overwrite */ 40124139Sjoerg#if (x_procstate == 0) 40224139Sjoerg Move_to(x_procstate, y_procstate); 40324139Sjoerg#else 40424139Sjoerg /* cursor is already there...no motion needed */ 40524139Sjoerg /* assert(lastline == 1); */ 40624139Sjoerg#endif 40724139Sjoerg printf("%d", total); 40824139Sjoerg 40924139Sjoerg /* if number of digits differs, rewrite the label */ 41024139Sjoerg if (digits(total) != digits(ltotal)) 41124139Sjoerg { 41224139Sjoerg fputs(" processes:", stdout); 41324139Sjoerg /* put out enough spaces to get to column 15 */ 41424139Sjoerg i = digits(total); 41524139Sjoerg while (i++ < 4) 41624139Sjoerg { 41724139Sjoerg putchar(' '); 41824139Sjoerg } 41924139Sjoerg /* cursor may end up right where we want it!!! */ 42024139Sjoerg } 42124139Sjoerg 42224139Sjoerg /* save new total */ 42324139Sjoerg ltotal = total; 42424139Sjoerg } 42524139Sjoerg 42624139Sjoerg /* see if any of the state numbers has changed */ 42724139Sjoerg if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) 42824139Sjoerg { 42924139Sjoerg /* format and update the line */ 43024139Sjoerg summary_format(new, brkdn, procstate_names); 43124139Sjoerg line_update(procstates_buffer, new, x_brkdn, y_brkdn); 43224139Sjoerg memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 43324139Sjoerg } 43424139Sjoerg} 43524139Sjoerg 436175420Speter#ifdef no_more 43724139Sjoerg/* 43824139Sjoerg * *_cpustates(states, names) - print the cpu state percentages 43924139Sjoerg * 44024139Sjoerg * Assumptions: cursor is on the PREVIOUS line 44124139Sjoerg */ 44224139Sjoerg 44324139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */ 44424139Sjoerg 44524139Sjoergchar *cpustates_tag() 44624139Sjoerg 44724139Sjoerg{ 44824139Sjoerg register char *use; 44924139Sjoerg 45024139Sjoerg static char *short_tag = "CPU: "; 45124139Sjoerg static char *long_tag = "CPU states: "; 45224139Sjoerg 45324139Sjoerg /* if length + strlen(long_tag) >= screen_width, then we have to 45424139Sjoerg use the shorter tag (we subtract 2 to account for ": ") */ 45524139Sjoerg if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) 45624139Sjoerg { 45724139Sjoerg use = short_tag; 45824139Sjoerg } 45924139Sjoerg else 46024139Sjoerg { 46124139Sjoerg use = long_tag; 46224139Sjoerg } 46324139Sjoerg 46424139Sjoerg /* set cpustates_column accordingly then return result */ 46524139Sjoerg cpustates_column = strlen(use); 46624139Sjoerg return(use); 46724139Sjoerg} 468175420Speter#endif 46924139Sjoerg 470301836Sngievoid 47124139Sjoergi_cpustates(states) 47224139Sjoerg 473301836Sngieint *states; 47424139Sjoerg 47524139Sjoerg{ 47624139Sjoerg register int i = 0; 47724139Sjoerg register int value; 478175420Speter register char **names; 47924139Sjoerg register char *thisname; 480175420Speter int cpu; 48124139Sjoerg 482175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) { 483175420Speter names = cpustate_names; 484175420Speter 48524139Sjoerg /* print tag and bump lastline */ 486175420Speter if (num_cpus == 1) 487175420Speter printf("\nCPU: "); 488218171Sjhb else { 489218171Sjhb value = printf("\nCPU %d: ", cpu); 490218171Sjhb while (value++ <= cpustates_column) 491218171Sjhb printf(" "); 492218171Sjhb } 49324139Sjoerg lastline++; 49424139Sjoerg 49524139Sjoerg /* now walk thru the names and print the line */ 49624139Sjoerg while ((thisname = *names++) != NULL) 49724139Sjoerg { 49824139Sjoerg if (*thisname != '\0') 49924139Sjoerg { 50024139Sjoerg /* retrieve the value and remember it */ 50124139Sjoerg value = *states++; 50224139Sjoerg 50324139Sjoerg /* if percentage is >= 1000, print it as 100% */ 50424139Sjoerg printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), 505175420Speter (i++ % num_cpustates) == 0 ? "" : ", ", 50624139Sjoerg ((float)value)/10., 50724139Sjoerg thisname); 50824139Sjoerg } 50924139Sjoerg } 510175420Speter} 51124139Sjoerg 51224139Sjoerg /* copy over values into "last" array */ 513175420Speter memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus); 51424139Sjoerg} 51524139Sjoerg 516301836Sngievoid 51724139Sjoergu_cpustates(states) 51824139Sjoerg 519301836Sngieint *states; 52024139Sjoerg 52124139Sjoerg{ 52224139Sjoerg register int value; 523175420Speter register char **names; 52424139Sjoerg register char *thisname; 52524139Sjoerg register int *lp; 52624139Sjoerg register int *colp; 527175420Speter int cpu; 52824139Sjoerg 529175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) { 530175420Speter names = cpustate_names; 531175420Speter 532175420Speter Move_to(cpustates_column, y_cpustates + cpu); 533175420Speter lastline = y_cpustates + cpu; 534175420Speter lp = lcpustates + (cpu * num_cpustates); 53524139Sjoerg colp = cpustate_columns; 53624139Sjoerg 53724139Sjoerg /* we could be much more optimal about this */ 53824139Sjoerg while ((thisname = *names++) != NULL) 53924139Sjoerg { 54024139Sjoerg if (*thisname != '\0') 54124139Sjoerg { 54224139Sjoerg /* did the value change since last time? */ 54324139Sjoerg if (*lp != *states) 54424139Sjoerg { 54524139Sjoerg /* yes, move and change */ 546175420Speter Move_to(cpustates_column + *colp, y_cpustates + cpu); 547175420Speter lastline = y_cpustates + cpu; 54824139Sjoerg 54924139Sjoerg /* retrieve value and remember it */ 55024139Sjoerg value = *states; 55124139Sjoerg 55224139Sjoerg /* if percentage is >= 1000, print it as 100% */ 55324139Sjoerg printf((value >= 1000 ? "%4.0f" : "%4.1f"), 55424139Sjoerg ((double)value)/10.); 55524139Sjoerg 55624139Sjoerg /* remember it for next time */ 55789758Sdwmalone *lp = value; 55824139Sjoerg } 55924139Sjoerg } 56024139Sjoerg 56124139Sjoerg /* increment and move on */ 56224139Sjoerg lp++; 56324139Sjoerg states++; 56424139Sjoerg colp++; 56524139Sjoerg } 56624139Sjoerg} 567175420Speter} 56824139Sjoerg 569301836Sngievoid 57024139Sjoergz_cpustates() 57124139Sjoerg 57224139Sjoerg{ 57324139Sjoerg register int i = 0; 574175420Speter register char **names; 57524139Sjoerg register char *thisname; 57624139Sjoerg register int *lp; 577218171Sjhb int cpu, value; 57824139Sjoerg 579175420Speterfor (cpu = 0; cpu < num_cpus; cpu++) { 580175420Speter names = cpustate_names; 581175420Speter 58224139Sjoerg /* show tag and bump lastline */ 583175420Speter if (num_cpus == 1) 584175420Speter printf("\nCPU: "); 585218171Sjhb else { 586218171Sjhb value = printf("\nCPU %d: ", cpu); 587218171Sjhb while (value++ <= cpustates_column) 588218171Sjhb printf(" "); 589218171Sjhb } 59024139Sjoerg lastline++; 59124139Sjoerg 59224139Sjoerg while ((thisname = *names++) != NULL) 59324139Sjoerg { 59424139Sjoerg if (*thisname != '\0') 59524139Sjoerg { 596175420Speter printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname); 59724139Sjoerg } 59824139Sjoerg } 599175420Speter} 60024139Sjoerg 60124139Sjoerg /* fill the "last" array with all -1s, to insure correct updating */ 60224139Sjoerg lp = lcpustates; 603175420Speter i = num_cpustates * num_cpus; 60424139Sjoerg while (--i >= 0) 60524139Sjoerg { 60624139Sjoerg *lp++ = -1; 60724139Sjoerg } 60824139Sjoerg} 60924139Sjoerg 61024139Sjoerg/* 61124139Sjoerg * *_memory(stats) - print "Memory: " followed by the memory summary string 61224139Sjoerg * 61324139Sjoerg * Assumptions: cursor is on "lastline" 61424139Sjoerg * for i_memory ONLY: cursor is on the previous line 61524139Sjoerg */ 61624139Sjoerg 61724139Sjoergchar memory_buffer[MAX_COLS]; 61824139Sjoerg 619301836Sngievoid 62024139Sjoergi_memory(stats) 62124139Sjoerg 62224139Sjoergint *stats; 62324139Sjoerg 62424139Sjoerg{ 62524142Sjoerg fputs("\nMem: ", stdout); 62624139Sjoerg lastline++; 62724139Sjoerg 62824139Sjoerg /* format and print the memory summary */ 62924139Sjoerg summary_format(memory_buffer, stats, memory_names); 63024139Sjoerg fputs(memory_buffer, stdout); 63124139Sjoerg} 63224139Sjoerg 633301836Sngievoid 63424139Sjoergu_memory(stats) 63524139Sjoerg 63624139Sjoergint *stats; 63724139Sjoerg 63824139Sjoerg{ 63924139Sjoerg static char new[MAX_COLS]; 64024139Sjoerg 64124139Sjoerg /* format the new line */ 64224139Sjoerg summary_format(new, stats, memory_names); 64324139Sjoerg line_update(memory_buffer, new, x_mem, y_mem); 64424139Sjoerg} 64524139Sjoerg 64624139Sjoerg/* 647237656Sjhb * *_arc(stats) - print "ARC: " followed by the ARC summary string 648237656Sjhb * 649237656Sjhb * Assumptions: cursor is on "lastline" 650237656Sjhb * for i_arc ONLY: cursor is on the previous line 651237656Sjhb */ 652237656Sjhbchar arc_buffer[MAX_COLS]; 653237656Sjhb 654301836Sngievoid 655237656Sjhbi_arc(stats) 656237656Sjhb 657237656Sjhbint *stats; 658237656Sjhb 659237656Sjhb{ 660237656Sjhb if (arc_names == NULL) 661301836Sngie return; 662237656Sjhb 663237656Sjhb fputs("\nARC: ", stdout); 664237656Sjhb lastline++; 665237656Sjhb 666237656Sjhb /* format and print the memory summary */ 667237656Sjhb summary_format(arc_buffer, stats, arc_names); 668237656Sjhb fputs(arc_buffer, stdout); 669237656Sjhb} 670237656Sjhb 671301836Sngievoid 672237656Sjhbu_arc(stats) 673237656Sjhb 674237656Sjhbint *stats; 675237656Sjhb 676237656Sjhb{ 677237656Sjhb static char new[MAX_COLS]; 678237656Sjhb 679237656Sjhb if (arc_names == NULL) 680301836Sngie return; 681237656Sjhb 682237656Sjhb /* format the new line */ 683237656Sjhb summary_format(new, stats, arc_names); 684237656Sjhb line_update(arc_buffer, new, x_arc, y_arc); 685237656Sjhb} 686237656Sjhb 687237656Sjhb 688237656Sjhb/* 68924142Sjoerg * *_swap(stats) - print "Swap: " followed by the swap summary string 69024142Sjoerg * 69124142Sjoerg * Assumptions: cursor is on "lastline" 69224142Sjoerg * for i_swap ONLY: cursor is on the previous line 69324142Sjoerg */ 69424142Sjoerg 69524142Sjoergchar swap_buffer[MAX_COLS]; 69624142Sjoerg 697301836Sngievoid 69824142Sjoergi_swap(stats) 69924142Sjoerg 70024142Sjoergint *stats; 70124142Sjoerg 70224142Sjoerg{ 70324142Sjoerg fputs("\nSwap: ", stdout); 70424142Sjoerg lastline++; 70524142Sjoerg 70624142Sjoerg /* format and print the swap summary */ 70724142Sjoerg summary_format(swap_buffer, stats, swap_names); 70824142Sjoerg fputs(swap_buffer, stdout); 70924142Sjoerg} 71024142Sjoerg 711301836Sngievoid 71224142Sjoergu_swap(stats) 71324142Sjoerg 71424142Sjoergint *stats; 71524142Sjoerg 71624142Sjoerg{ 71724142Sjoerg static char new[MAX_COLS]; 71824142Sjoerg 71924142Sjoerg /* format the new line */ 72024142Sjoerg summary_format(new, stats, swap_names); 72124142Sjoerg line_update(swap_buffer, new, x_swap, y_swap); 72224142Sjoerg} 72324142Sjoerg 72424142Sjoerg/* 72524139Sjoerg * *_message() - print the next pending message line, or erase the one 72624139Sjoerg * that is there. 72724139Sjoerg * 72824139Sjoerg * Note that u_message is (currently) the same as i_message. 72924139Sjoerg * 73024139Sjoerg * Assumptions: lastline is consistent 73124139Sjoerg */ 73224139Sjoerg 73324139Sjoerg/* 73424139Sjoerg * i_message is funny because it gets its message asynchronously (with 73524139Sjoerg * respect to screen updates). 73624139Sjoerg */ 73724139Sjoerg 73824139Sjoergstatic char next_msg[MAX_COLS + 5]; 73924139Sjoergstatic int msglen = 0; 74024139Sjoerg/* Invariant: msglen is always the length of the message currently displayed 74124139Sjoerg on the screen (even when next_msg doesn't contain that message). */ 74224139Sjoerg 743301836Sngievoid 74424139Sjoergi_message() 74524139Sjoerg 74624139Sjoerg{ 74724139Sjoerg while (lastline < y_message) 74824139Sjoerg { 74924139Sjoerg fputc('\n', stdout); 75024139Sjoerg lastline++; 75124139Sjoerg } 75224139Sjoerg if (next_msg[0] != '\0') 75324139Sjoerg { 75424139Sjoerg standout(next_msg); 75524139Sjoerg msglen = strlen(next_msg); 75624139Sjoerg next_msg[0] = '\0'; 75724139Sjoerg } 75824139Sjoerg else if (msglen > 0) 75924139Sjoerg { 76024139Sjoerg (void) clear_eol(msglen); 76124139Sjoerg msglen = 0; 76224139Sjoerg } 76324139Sjoerg} 76424139Sjoerg 765301836Sngievoid 76624139Sjoergu_message() 76724139Sjoerg 76824139Sjoerg{ 76924139Sjoerg i_message(); 77024139Sjoerg} 77124139Sjoerg 77224139Sjoergstatic int header_length; 77324139Sjoerg 77424139Sjoerg/* 775146344Skeramida * Trim a header string to the current display width and return a newly 776146344Skeramida * allocated area with the trimmed header. 777146344Skeramida */ 778146344Skeramida 779146344Skeramidachar * 780146344Skeramidatrim_header(text) 781146344Skeramida 782146344Skeramidachar *text; 783146344Skeramida 784146344Skeramida{ 785146344Skeramida char *s; 786146344Skeramida int width; 787146344Skeramida 788146344Skeramida s = NULL; 789223342Sdelphij width = display_width; 790146344Skeramida header_length = strlen(text); 791146344Skeramida if (header_length >= width) { 792146344Skeramida s = malloc((width + 1) * sizeof(char)); 793146344Skeramida if (s == NULL) 794146344Skeramida return (NULL); 795146344Skeramida strncpy(s, text, width); 796146344Skeramida s[width] = '\0'; 797146344Skeramida } 798146344Skeramida return (s); 799146344Skeramida} 800146344Skeramida 801146344Skeramida/* 80224139Sjoerg * *_header(text) - print the header for the process area 80324139Sjoerg * 80424139Sjoerg * Assumptions: cursor is on the previous line and lastline is consistent 80524139Sjoerg */ 80624139Sjoerg 807301836Sngievoid 80824139Sjoergi_header(text) 80924139Sjoerg 81024139Sjoergchar *text; 81124139Sjoerg 81224139Sjoerg{ 813146344Skeramida char *s; 814146344Skeramida 815146344Skeramida s = trim_header(text); 816146344Skeramida if (s != NULL) 817146344Skeramida text = s; 818146344Skeramida 81924139Sjoerg if (header_status == ON) 82024139Sjoerg { 82124139Sjoerg putchar('\n'); 822223342Sdelphij fputs(text, stdout); 82324139Sjoerg lastline++; 82424139Sjoerg } 82524139Sjoerg else if (header_status == ERASE) 82624139Sjoerg { 82724139Sjoerg header_status = OFF; 82824139Sjoerg } 829146344Skeramida free(s); 83024139Sjoerg} 83124139Sjoerg 83224139Sjoerg/*ARGSUSED*/ 833301836Sngievoid 83424139Sjoergu_header(text) 83524139Sjoerg 836301836Sngiechar *text __unused; /* ignored */ 83724139Sjoerg 83824139Sjoerg{ 839146344Skeramida 84024139Sjoerg if (header_status == ERASE) 84124139Sjoerg { 84224139Sjoerg putchar('\n'); 84324139Sjoerg lastline++; 84424139Sjoerg clear_eol(header_length); 84524139Sjoerg header_status = OFF; 84624139Sjoerg } 84724139Sjoerg} 84824139Sjoerg 84924139Sjoerg/* 85024139Sjoerg * *_process(line, thisline) - print one process line 85124139Sjoerg * 85224139Sjoerg * Assumptions: lastline is consistent 85324139Sjoerg */ 85424139Sjoerg 855301836Sngievoid 85624139Sjoergi_process(line, thisline) 85724139Sjoerg 85824139Sjoergint line; 85924139Sjoergchar *thisline; 86024139Sjoerg 86124139Sjoerg{ 86224139Sjoerg register char *p; 86324139Sjoerg register char *base; 86424139Sjoerg 86524139Sjoerg /* make sure we are on the correct line */ 86624139Sjoerg while (lastline < y_procs + line) 86724139Sjoerg { 86824139Sjoerg putchar('\n'); 86924139Sjoerg lastline++; 87024139Sjoerg } 87124139Sjoerg 87224139Sjoerg /* truncate the line to conform to our current screen width */ 87324139Sjoerg thisline[display_width] = '\0'; 87424139Sjoerg 87524139Sjoerg /* write the line out */ 87624139Sjoerg fputs(thisline, stdout); 87724139Sjoerg 87824139Sjoerg /* copy it in to our buffer */ 87924139Sjoerg base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; 88024139Sjoerg p = strecpy(base, thisline); 88124139Sjoerg 88224139Sjoerg /* zero fill the rest of it */ 88324139Sjoerg memzero(p, display_width - (p - base)); 88424139Sjoerg} 88524139Sjoerg 886301836Sngievoid 88724139Sjoergu_process(line, newline) 88824139Sjoerg 88924139Sjoergint line; 89024139Sjoergchar *newline; 89124139Sjoerg 89224139Sjoerg{ 89324139Sjoerg register char *optr; 89424139Sjoerg register int screen_line = line + Header_lines; 89524139Sjoerg register char *bufferline; 89624139Sjoerg 89724139Sjoerg /* remember a pointer to the current line in the screen buffer */ 89824139Sjoerg bufferline = &screenbuf[lineindex(line)]; 89924139Sjoerg 90024139Sjoerg /* truncate the line to conform to our current screen width */ 90124139Sjoerg newline[display_width] = '\0'; 90224139Sjoerg 90324139Sjoerg /* is line higher than we went on the last display? */ 90424139Sjoerg if (line >= last_hi) 90524139Sjoerg { 90624139Sjoerg /* yes, just ignore screenbuf and write it out directly */ 90724139Sjoerg /* get positioned on the correct line */ 90824139Sjoerg if (screen_line - lastline == 1) 90924139Sjoerg { 91024139Sjoerg putchar('\n'); 91124139Sjoerg lastline++; 91224139Sjoerg } 91324139Sjoerg else 91424139Sjoerg { 91524139Sjoerg Move_to(0, screen_line); 91624139Sjoerg lastline = screen_line; 91724139Sjoerg } 91824139Sjoerg 91924139Sjoerg /* now write the line */ 92024139Sjoerg fputs(newline, stdout); 92124139Sjoerg 92224139Sjoerg /* copy it in to the buffer */ 92324139Sjoerg optr = strecpy(bufferline, newline); 92424139Sjoerg 92524139Sjoerg /* zero fill the rest of it */ 92624139Sjoerg memzero(optr, display_width - (optr - bufferline)); 92724139Sjoerg } 92824139Sjoerg else 92924139Sjoerg { 93024139Sjoerg line_update(bufferline, newline, 0, line + Header_lines); 93124139Sjoerg } 93224139Sjoerg} 93324139Sjoerg 934301836Sngievoid 93524139Sjoergu_endscreen(hi) 93624139Sjoerg 937301836Sngieint hi; 93824139Sjoerg 93924139Sjoerg{ 94024139Sjoerg register int screen_line = hi + Header_lines; 94124139Sjoerg register int i; 94224139Sjoerg 94324139Sjoerg if (smart_terminal) 94424139Sjoerg { 94524139Sjoerg if (hi < last_hi) 94624139Sjoerg { 94724139Sjoerg /* need to blank the remainder of the screen */ 94824139Sjoerg /* but only if there is any screen left below this line */ 94924139Sjoerg if (lastline + 1 < screen_length) 95024139Sjoerg { 95124139Sjoerg /* efficiently move to the end of currently displayed info */ 95224139Sjoerg if (screen_line - lastline < 5) 95324139Sjoerg { 95424139Sjoerg while (lastline < screen_line) 95524139Sjoerg { 95624139Sjoerg putchar('\n'); 95724139Sjoerg lastline++; 95824139Sjoerg } 95924139Sjoerg } 96024139Sjoerg else 96124139Sjoerg { 96224139Sjoerg Move_to(0, screen_line); 96324139Sjoerg lastline = screen_line; 96424139Sjoerg } 96524139Sjoerg 96624139Sjoerg if (clear_to_end) 96724139Sjoerg { 96824139Sjoerg /* we can do this the easy way */ 96924139Sjoerg putcap(clear_to_end); 97024139Sjoerg } 97124139Sjoerg else 97224139Sjoerg { 97324139Sjoerg /* use clear_eol on each line */ 97424139Sjoerg i = hi; 97524139Sjoerg while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) 97624139Sjoerg { 97724139Sjoerg putchar('\n'); 97824139Sjoerg } 97924139Sjoerg } 98024139Sjoerg } 98124139Sjoerg } 98224139Sjoerg last_hi = hi; 98324139Sjoerg 98424139Sjoerg /* move the cursor to a pleasant place */ 98524139Sjoerg Move_to(x_idlecursor, y_idlecursor); 98624139Sjoerg lastline = y_idlecursor; 98724139Sjoerg } 98824139Sjoerg else 98924139Sjoerg { 99024139Sjoerg /* separate this display from the next with some vertical room */ 99124139Sjoerg fputs("\n\n", stdout); 99224139Sjoerg } 99324139Sjoerg} 99424139Sjoerg 995301836Sngievoid 99624139Sjoergdisplay_header(t) 99724139Sjoerg 99824139Sjoergint t; 99924139Sjoerg 100024139Sjoerg{ 100124139Sjoerg if (t) 100224139Sjoerg { 100324139Sjoerg header_status = ON; 100424139Sjoerg } 100524139Sjoerg else if (header_status == ON) 100624139Sjoerg { 100724139Sjoerg header_status = ERASE; 100824139Sjoerg } 100924139Sjoerg} 101024139Sjoerg 101124139Sjoerg/*VARARGS2*/ 1012301836Sngievoid 101324139Sjoergnew_message(type, msgfmt, a1, a2, a3) 101424139Sjoerg 101524139Sjoergint type; 101624139Sjoergchar *msgfmt; 101724139Sjoergcaddr_t a1, a2, a3; 101824139Sjoerg 101924139Sjoerg{ 102024139Sjoerg register int i; 102124139Sjoerg 102224139Sjoerg /* first, format the message */ 102366641Simp (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3); 102424139Sjoerg 102524139Sjoerg if (msglen > 0) 102624139Sjoerg { 102724139Sjoerg /* message there already -- can we clear it? */ 102824139Sjoerg if (!overstrike) 102924139Sjoerg { 103024139Sjoerg /* yes -- write it and clear to end */ 103124139Sjoerg i = strlen(next_msg); 103224139Sjoerg if ((type & MT_delayed) == 0) 103324139Sjoerg { 103424139Sjoerg type & MT_standout ? standout(next_msg) : 103524139Sjoerg fputs(next_msg, stdout); 103624139Sjoerg (void) clear_eol(msglen - i); 103724139Sjoerg msglen = i; 103824139Sjoerg next_msg[0] = '\0'; 103924139Sjoerg } 104024139Sjoerg } 104124139Sjoerg } 104224139Sjoerg else 104324139Sjoerg { 104424139Sjoerg if ((type & MT_delayed) == 0) 104524139Sjoerg { 104624139Sjoerg type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout); 104724139Sjoerg msglen = strlen(next_msg); 104824139Sjoerg next_msg[0] = '\0'; 104924139Sjoerg } 105024139Sjoerg } 105124139Sjoerg} 105224139Sjoerg 1053301836Sngievoid 105424139Sjoergclear_message() 105524139Sjoerg 105624139Sjoerg{ 105724139Sjoerg if (clear_eol(msglen) == 1) 105824139Sjoerg { 105924139Sjoerg putchar('\r'); 106024139Sjoerg } 106124139Sjoerg} 106224139Sjoerg 1063301836Sngieint 106424139Sjoergreadline(buffer, size, numeric) 106524139Sjoerg 106624139Sjoergchar *buffer; 106724139Sjoergint size; 106824139Sjoergint numeric; 106924139Sjoerg 107024139Sjoerg{ 107124139Sjoerg register char *ptr = buffer; 107224139Sjoerg register char ch; 107324139Sjoerg register char cnt = 0; 107424139Sjoerg register char maxcnt = 0; 107524139Sjoerg 107624139Sjoerg /* allow room for null terminator */ 107724139Sjoerg size -= 1; 107824139Sjoerg 107924139Sjoerg /* read loop */ 108024139Sjoerg while ((fflush(stdout), read(0, ptr, 1) > 0)) 108124139Sjoerg { 108224139Sjoerg /* newline means we are done */ 108324142Sjoerg if ((ch = *ptr) == '\n' || ch == '\r') 108424139Sjoerg { 108524139Sjoerg break; 108624139Sjoerg } 108724139Sjoerg 108824139Sjoerg /* handle special editing characters */ 108924139Sjoerg if (ch == ch_kill) 109024139Sjoerg { 109124139Sjoerg /* kill line -- account for overstriking */ 109224139Sjoerg if (overstrike) 109324139Sjoerg { 109424139Sjoerg msglen += maxcnt; 109524139Sjoerg } 109624139Sjoerg 109724139Sjoerg /* return null string */ 109824139Sjoerg *buffer = '\0'; 109924139Sjoerg putchar('\r'); 110024139Sjoerg return(-1); 110124139Sjoerg } 110224139Sjoerg else if (ch == ch_erase) 110324139Sjoerg { 110424139Sjoerg /* erase previous character */ 110524139Sjoerg if (cnt <= 0) 110624139Sjoerg { 110724139Sjoerg /* none to erase! */ 110824139Sjoerg putchar('\7'); 110924139Sjoerg } 111024139Sjoerg else 111124139Sjoerg { 111224139Sjoerg fputs("\b \b", stdout); 111324139Sjoerg ptr--; 111424139Sjoerg cnt--; 111524139Sjoerg } 111624139Sjoerg } 111724139Sjoerg /* check for character validity and buffer overflow */ 111824139Sjoerg else if (cnt == size || (numeric && !isdigit(ch)) || 111924139Sjoerg !isprint(ch)) 112024139Sjoerg { 112124139Sjoerg /* not legal */ 112224139Sjoerg putchar('\7'); 112324139Sjoerg } 112424139Sjoerg else 112524139Sjoerg { 112624139Sjoerg /* echo it and store it in the buffer */ 112724139Sjoerg putchar(ch); 112824139Sjoerg ptr++; 112924139Sjoerg cnt++; 113024139Sjoerg if (cnt > maxcnt) 113124139Sjoerg { 113224139Sjoerg maxcnt = cnt; 113324139Sjoerg } 113424139Sjoerg } 113524139Sjoerg } 113624139Sjoerg 113724139Sjoerg /* all done -- null terminate the string */ 113824139Sjoerg *ptr = '\0'; 113924139Sjoerg 114024139Sjoerg /* account for the extra characters in the message area */ 114124139Sjoerg /* (if terminal overstrikes, remember the furthest they went) */ 114224139Sjoerg msglen += overstrike ? maxcnt : cnt; 114324139Sjoerg 114424139Sjoerg /* return either inputted number or string length */ 114524139Sjoerg putchar('\r'); 114624139Sjoerg return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); 114724139Sjoerg} 114824139Sjoerg 114924139Sjoerg/* internal support routines */ 115024139Sjoerg 115124139Sjoergstatic int string_count(pp) 115224139Sjoerg 115324139Sjoergregister char **pp; 115424139Sjoerg 115524139Sjoerg{ 115624139Sjoerg register int cnt; 115724139Sjoerg 115824139Sjoerg cnt = 0; 115924139Sjoerg while (*pp++ != NULL) 116024139Sjoerg { 116124139Sjoerg cnt++; 116224139Sjoerg } 116324139Sjoerg return(cnt); 116424139Sjoerg} 116524139Sjoerg 116624139Sjoergstatic void summary_format(str, numbers, names) 116724139Sjoerg 116824139Sjoergchar *str; 116924139Sjoergint *numbers; 117024139Sjoergregister char **names; 117124139Sjoerg 117224139Sjoerg{ 117324139Sjoerg register char *p; 117424139Sjoerg register int num; 117524139Sjoerg register char *thisname; 117624139Sjoerg register int useM = No; 117724139Sjoerg 117824139Sjoerg /* format each number followed by its string */ 117924139Sjoerg p = str; 118024139Sjoerg while ((thisname = *names++) != NULL) 118124139Sjoerg { 118224139Sjoerg /* get the number to format */ 118324139Sjoerg num = *numbers++; 118424139Sjoerg 118524139Sjoerg /* display only non-zero numbers */ 118624139Sjoerg if (num > 0) 118724139Sjoerg { 118824139Sjoerg /* is this number in kilobytes? */ 118924139Sjoerg if (thisname[0] == 'K') 119024139Sjoerg { 119124139Sjoerg /* yes: format it as a memory value */ 119224139Sjoerg p = strecpy(p, format_k(num)); 119324139Sjoerg 119424139Sjoerg /* skip over the K, since it was included by format_k */ 119524139Sjoerg p = strecpy(p, thisname+1); 119624139Sjoerg } 119724139Sjoerg else 119824139Sjoerg { 119924139Sjoerg p = strecpy(p, itoa(num)); 120024139Sjoerg p = strecpy(p, thisname); 120124139Sjoerg } 120224139Sjoerg } 120324139Sjoerg 120424139Sjoerg /* ignore negative numbers, but display corresponding string */ 120524139Sjoerg else if (num < 0) 120624139Sjoerg { 120724139Sjoerg p = strecpy(p, thisname); 120824139Sjoerg } 120924139Sjoerg } 121024139Sjoerg 121124139Sjoerg /* if the last two characters in the string are ", ", delete them */ 121224139Sjoerg p -= 2; 121324139Sjoerg if (p >= str && p[0] == ',' && p[1] == ' ') 121424139Sjoerg { 121524139Sjoerg *p = '\0'; 121624139Sjoerg } 121724139Sjoerg} 121824139Sjoerg 121924139Sjoergstatic void line_update(old, new, start, line) 122024139Sjoerg 122124139Sjoergregister char *old; 122224139Sjoergregister char *new; 122324139Sjoergint start; 122424139Sjoergint line; 122524139Sjoerg 122624139Sjoerg{ 122724139Sjoerg register int ch; 122824139Sjoerg register int diff; 122924139Sjoerg register int newcol = start + 1; 123024139Sjoerg register int lastcol = start; 123124139Sjoerg char cursor_on_line = No; 123224139Sjoerg char *current; 123324139Sjoerg 123424139Sjoerg /* compare the two strings and only rewrite what has changed */ 123524139Sjoerg current = old; 123624139Sjoerg#ifdef DEBUG 123724139Sjoerg fprintf(debug, "line_update, starting at %d\n", start); 123824139Sjoerg fputs(old, debug); 123924139Sjoerg fputc('\n', debug); 124024139Sjoerg fputs(new, debug); 124124139Sjoerg fputs("\n-\n", debug); 124224139Sjoerg#endif 124324139Sjoerg 124424139Sjoerg /* start things off on the right foot */ 124524139Sjoerg /* this is to make sure the invariants get set up right */ 124624139Sjoerg if ((ch = *new++) != *old) 124724139Sjoerg { 124824139Sjoerg if (line - lastline == 1 && start == 0) 124924139Sjoerg { 125024139Sjoerg putchar('\n'); 125124139Sjoerg } 125224139Sjoerg else 125324139Sjoerg { 125424139Sjoerg Move_to(start, line); 125524139Sjoerg } 125624139Sjoerg cursor_on_line = Yes; 125724139Sjoerg putchar(ch); 125824139Sjoerg *old = ch; 125924139Sjoerg lastcol = 1; 126024139Sjoerg } 126124139Sjoerg old++; 126224139Sjoerg 126324139Sjoerg /* 126424139Sjoerg * main loop -- check each character. If the old and new aren't the 126524139Sjoerg * same, then update the display. When the distance from the 126624139Sjoerg * current cursor position to the new change is small enough, 126724139Sjoerg * the characters that belong there are written to move the 126824139Sjoerg * cursor over. 126924139Sjoerg * 127024139Sjoerg * Invariants: 127124139Sjoerg * lastcol is the column where the cursor currently is sitting 127224139Sjoerg * (always one beyond the end of the last mismatch). 127324139Sjoerg */ 127424139Sjoerg do /* yes, a do...while */ 127524139Sjoerg { 127624139Sjoerg if ((ch = *new++) != *old) 127724139Sjoerg { 127824139Sjoerg /* new character is different from old */ 127924139Sjoerg /* make sure the cursor is on top of this character */ 128024139Sjoerg diff = newcol - lastcol; 128124139Sjoerg if (diff > 0) 128224139Sjoerg { 128324139Sjoerg /* some motion is required--figure out which is shorter */ 128424139Sjoerg if (diff < 6 && cursor_on_line) 128524139Sjoerg { 128624139Sjoerg /* overwrite old stuff--get it out of the old buffer */ 128724139Sjoerg printf("%.*s", diff, ¤t[lastcol-start]); 128824139Sjoerg } 128924139Sjoerg else 129024139Sjoerg { 129124139Sjoerg /* use cursor addressing */ 129224139Sjoerg Move_to(newcol, line); 129324139Sjoerg cursor_on_line = Yes; 129424139Sjoerg } 129524139Sjoerg /* remember where the cursor is */ 129624139Sjoerg lastcol = newcol + 1; 129724139Sjoerg } 129824139Sjoerg else 129924139Sjoerg { 130024139Sjoerg /* already there, update position */ 130124139Sjoerg lastcol++; 130224139Sjoerg } 130324139Sjoerg 130424139Sjoerg /* write what we need to */ 130524139Sjoerg if (ch == '\0') 130624139Sjoerg { 130724139Sjoerg /* at the end--terminate with a clear-to-end-of-line */ 130824139Sjoerg (void) clear_eol(strlen(old)); 130924139Sjoerg } 131024139Sjoerg else 131124139Sjoerg { 131224139Sjoerg /* write the new character */ 131324139Sjoerg putchar(ch); 131424139Sjoerg } 131524139Sjoerg /* put the new character in the screen buffer */ 131624139Sjoerg *old = ch; 131724139Sjoerg } 131824139Sjoerg 131924139Sjoerg /* update working column and screen buffer pointer */ 132024139Sjoerg newcol++; 132124139Sjoerg old++; 132224139Sjoerg 132324139Sjoerg } while (ch != '\0'); 132424139Sjoerg 132524139Sjoerg /* zero out the rest of the line buffer -- MUST BE DONE! */ 132624139Sjoerg diff = display_width - newcol; 132724139Sjoerg if (diff > 0) 132824139Sjoerg { 132924139Sjoerg memzero(old, diff); 133024139Sjoerg } 133124139Sjoerg 133224139Sjoerg /* remember where the current line is */ 133324139Sjoerg if (cursor_on_line) 133424139Sjoerg { 133524139Sjoerg lastline = line; 133624139Sjoerg } 133724139Sjoerg} 133824139Sjoerg 133924139Sjoerg/* 134024139Sjoerg * printable(str) - make the string pointed to by "str" into one that is 134124139Sjoerg * printable (i.e.: all ascii), by converting all non-printable 134224139Sjoerg * characters into '?'. Replacements are done in place and a pointer 134324139Sjoerg * to the original buffer is returned. 134424139Sjoerg */ 134524139Sjoerg 134624139Sjoergchar *printable(str) 134724139Sjoerg 134824139Sjoergchar *str; 134924139Sjoerg 135024139Sjoerg{ 135124139Sjoerg register char *ptr; 135224139Sjoerg register char ch; 135324139Sjoerg 135424139Sjoerg ptr = str; 135524139Sjoerg while ((ch = *ptr) != '\0') 135624139Sjoerg { 135724139Sjoerg if (!isprint(ch)) 135824139Sjoerg { 135924139Sjoerg *ptr = '?'; 136024139Sjoerg } 136124139Sjoerg ptr++; 136224139Sjoerg } 136324139Sjoerg return(str); 136424139Sjoerg} 136542447Sobrien 1366301836Sngievoid 136742447Sobrieni_uptime(bt, tod) 136842447Sobrien 136942447Sobrienstruct timeval* bt; 137042447Sobrientime_t *tod; 137142447Sobrien 137242447Sobrien{ 137342447Sobrien time_t uptime; 137442447Sobrien int days, hrs, mins, secs; 137542447Sobrien 137642447Sobrien if (bt->tv_sec != -1) { 137742447Sobrien uptime = *tod - bt->tv_sec; 137842447Sobrien days = uptime / 86400; 137942447Sobrien uptime %= 86400; 138042447Sobrien hrs = uptime / 3600; 138142447Sobrien uptime %= 3600; 138242447Sobrien mins = uptime / 60; 138342447Sobrien secs = uptime % 60; 138442447Sobrien 138542447Sobrien /* 138642447Sobrien * Display the uptime. 138742447Sobrien */ 138842447Sobrien 138942447Sobrien if (smart_terminal) 139042447Sobrien { 139142447Sobrien Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); 139242447Sobrien } 139342447Sobrien else 139442447Sobrien { 139542447Sobrien fputs(" ", stdout); 139642447Sobrien } 139742447Sobrien printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); 139842447Sobrien } 139942447Sobrien} 1400