display.c revision 101692
150477Speter/* 235388Smjacob * Top users/processes display for Unix 335388Smjacob * Version 3 435388Smjacob * 573319Smjacob * This program may be freely redistributed, 635388Smjacob * but this entire comment MUST remain intact. 735388Smjacob * 835388Smjacob * Copyright (c) 1984, 1989, William LeFebvre, Rice University 935388Smjacob * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 1035388Smjacob * 1135388Smjacob * $FreeBSD: head/contrib/top/display.c 101692 2002-08-11 18:37:25Z dwmalone $ 1235388Smjacob */ 1366189Smjacob 1466189Smjacob/* 1535388Smjacob * This file contains the routines that display information on the screen. 1635388Smjacob * Each section of the screen has two routines: one for initially writing 1735388Smjacob * all constant and dynamic text, and one for only updating the text that 1835388Smjacob * changes. The prefix "i_" is used on all the "initial" routines and the 1935388Smjacob * prefix "u_" is used for all the "updating" routines. 2035388Smjacob * 2135388Smjacob * ASSUMPTIONS: 2235388Smjacob * None of the "i_" routines use any of the termcap capabilities. 2335388Smjacob * In this way, those routines can be safely used on terminals that 2435388Smjacob * have minimal (or nonexistant) terminal capabilities. 2535388Smjacob * 2635388Smjacob * The routines are called in this order: *_loadave, i_timeofday, 2735388Smjacob * *_procstates, *_cpustates, *_memory, *_message, *_header, 2835388Smjacob * *_process, u_endscreen. 2977365Smjacob */ 3077365Smjacob 3164176Smjacob#include "os.h" 3277365Smjacob#include <ctype.h> 33100679Smjacob#include <time.h> 3477365Smjacob#include <sys/time.h> 3577365Smjacob 3635388Smjacob#include "screen.h" /* interface to screen package */ 3775200Smjacob#include "layout.h" /* defines for screen position layout */ 38100679Smjacob#include "display.h" 3999756Smjacob#include "top.h" 4099756Smjacob#include "top.local.h" 4199756Smjacob#include "boolean.h" 4277365Smjacob#include "machine.h" /* we should eliminate this!!! */ 4362498Smjacob#include "utils.h" 4449915Smjacob 4549915Smjacob#ifdef DEBUG 4662173SmjacobFILE *debug; 4777365Smjacob#endif 4849915Smjacob 4939235Sgibbs/* imported from screen.c */ 5060220Smjacobextern int overstrike; 5177365Smjacob 5277365Smjacobstatic int lmpid = 0; 5377365Smjacobstatic int last_hi = 0; /* used in u_process and u_endscreen */ 5477365Smjacobstatic int lastline = 0; 5577365Smjacobstatic int display_width = MAX_COLS; 5677365Smjacob 5777365Smjacob#define lineindex(l) ((l)*display_width) 5877365Smjacob 5977365Smjacobchar *printable(); 6077365Smjacob 6177365Smjacob/* things initialized by display_init and used thruout */ 6277365Smjacob 6377365Smjacob/* buffer of proc information lines for display updating */ 6477365Smjacobchar *screenbuf = NULL; 6577365Smjacob 6677365Smjacobstatic char **procstate_names; 6777365Smjacobstatic char **cpustate_names; 6855371Smjacobstatic char **memory_names; 6949915Smjacobstatic char **swap_names; 7039235Sgibbs 7142131Smjacobstatic int num_procstates; 7239235Sgibbsstatic int num_cpustates; 7346972Smjacobstatic int num_memory; 7439235Sgibbsstatic int num_swap; 7539235Sgibbs 7646972Smjacobstatic int *lprocstates; 7746972Smjacobstatic int *lcpustates; 7839235Sgibbsstatic int *lmemory; 7939235Sgibbsstatic int *lswap; 8046972Smjacob 8139235Sgibbsstatic int *cpustate_columns; 8246972Smjacobstatic int cpustate_total_length; 8346972Smjacob 8446972Smjacobstatic enum { OFF, ON, ERASE } header_status = ON; 8546972Smjacob 8646972Smjacobstatic int string_count(); 8746972Smjacobstatic void summary_format(); 8846972Smjacobstatic void line_update(); 8952349Smjacob 9039235Sgibbsint display_resize() 9139235Sgibbs 9239235Sgibbs{ 9339235Sgibbs register int lines; 9439235Sgibbs 9546972Smjacob /* first, deallocate any previous buffer that may have been there */ 9639235Sgibbs if (screenbuf != NULL) 9779336Smjacob { 9846972Smjacob free(screenbuf); 9973245Smjacob } 10046972Smjacob 10139235Sgibbs /* calculate the current dimensions */ 10279336Smjacob /* if operating in "dumb" mode, we only need one line */ 10339235Sgibbs lines = smart_terminal ? screen_length - Header_lines : 1; 10439235Sgibbs 10579336Smjacob if (lines < 0) 10662498Smjacob lines = 0; 10762498Smjacob /* we don't want more than MAX_COLS columns, since the machine-dependent 10862498Smjacob modules make static allocations based on MAX_COLS and we don't want 10979336Smjacob to run off the end of their buffers */ 11062498Smjacob display_width = screen_width; 11179336Smjacob if (display_width >= MAX_COLS) 11279336Smjacob { 11369597Smjacob display_width = MAX_COLS - 1; 11469597Smjacob } 11562498Smjacob 11662498Smjacob /* now, allocate space for the screen buffer */ 11762498Smjacob screenbuf = (char *)malloc(lines * display_width); 11846972Smjacob if (screenbuf == (char *)NULL) 11946972Smjacob { 12079336Smjacob /* oops! */ 12139235Sgibbs return(-1); 12239235Sgibbs } 12339235Sgibbs 12446972Smjacob /* return number of lines available */ 12539235Sgibbs /* for dumb terminals, pretend like we can show any amount */ 12646972Smjacob return(smart_terminal ? lines : Largest); 12746972Smjacob} 12877365Smjacob 12979336Smjacobint display_init(statics) 13039235Sgibbs 13139235Sgibbsstruct statics *statics; 13239235Sgibbs 13346972Smjacob{ 13439235Sgibbs register int lines; 13539235Sgibbs register char **pp; 13643420Smjacob register int *ip; 13746972Smjacob register int i; 13839235Sgibbs 13979336Smjacob /* call resize to do the dirty work */ 14046972Smjacob lines = display_resize(); 14146972Smjacob 14277365Smjacob /* only do the rest if we need to */ 14377365Smjacob if (lines > -1) 14477365Smjacob { 14577365Smjacob /* save pointers and allocate space for names */ 14677365Smjacob procstate_names = statics->procstate_names; 14779336Smjacob num_procstates = string_count(procstate_names); 14879336Smjacob lprocstates = (int *)malloc(num_procstates * sizeof(int)); 14977365Smjacob 15077365Smjacob cpustate_names = statics->cpustate_names; 15177365Smjacob 15277365Smjacob swap_names = statics->swap_names; 15377365Smjacob num_swap = string_count(swap_names); 15477365Smjacob lswap = (int *)malloc(num_swap * sizeof(int)); 15577365Smjacob num_cpustates = string_count(cpustate_names); 15679336Smjacob lcpustates = (int *)malloc(num_cpustates * sizeof(int)); 15779336Smjacob cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); 15877365Smjacob 15977365Smjacob memory_names = statics->memory_names; 16079338Smjacob num_memory = string_count(memory_names); 16177365Smjacob lmemory = (int *)malloc(num_memory * sizeof(int)); 16239235Sgibbs 16377365Smjacob /* calculate starting columns where needed */ 16446972Smjacob cpustate_total_length = 0; 16546972Smjacob pp = cpustate_names; 16646972Smjacob ip = cpustate_columns; 16754671Smjacob while (*pp != NULL) 16879336Smjacob { 16946972Smjacob *ip++ = cpustate_total_length; 17073245Smjacob if ((i = strlen(*pp++)) > 0) 17146972Smjacob { 17246972Smjacob cpustate_total_length += i + 8; 17346972Smjacob } 17446972Smjacob } 17577365Smjacob } 17646972Smjacob 17746972Smjacob /* return number of lines available */ 17846972Smjacob return(lines); 17946972Smjacob} 18046972Smjacob 18146972Smjacobi_loadave(mpid, avenrun) 18277365Smjacob 18379336Smjacobint mpid; 18446972Smjacobdouble *avenrun; 18546972Smjacob 18646972Smjacob{ 18746972Smjacob register int i; 18846972Smjacob 18946972Smjacob /* i_loadave also clears the screen, since it is first */ 19046972Smjacob clear(); 19146972Smjacob 19246972Smjacob /* mpid == -1 implies this system doesn't have an _mpid */ 19377365Smjacob if (mpid != -1) 19479336Smjacob { 19546972Smjacob printf("last pid: %5d; ", mpid); 19646972Smjacob } 19746972Smjacob 19846972Smjacob printf("load averages"); 19946972Smjacob 20046972Smjacob for (i = 0; i < 3; i++) 20146972Smjacob { 20246972Smjacob printf("%c %5.2f", 20346972Smjacob i == 0 ? ':' : ',', 20479336Smjacob avenrun[i]); 20546972Smjacob } 20646972Smjacob lmpid = mpid; 20746972Smjacob} 20877365Smjacob 20983028Smjacobu_loadave(mpid, avenrun) 21083028Smjacob 21183028Smjacobint mpid; 21283028Smjacobdouble *avenrun; 21383028Smjacob 21483028Smjacob{ 21577365Smjacob register int i; 21677365Smjacob 21777365Smjacob if (mpid != -1) 21877365Smjacob { 21977365Smjacob /* change screen only when value has really changed */ 22077365Smjacob if (mpid != lmpid) 22172347Smjacob { 22272347Smjacob Move_to(x_lastpid, y_lastpid); 22372347Smjacob printf("%5d", mpid); 22472347Smjacob lmpid = mpid; 22555371Smjacob } 22655371Smjacob 22755371Smjacob /* i remembers x coordinate to move to */ 22855371Smjacob i = x_loadave; 22955371Smjacob } 23055371Smjacob else 23155371Smjacob { 23255371Smjacob i = x_loadave_nompid; 23349915Smjacob } 23477365Smjacob 23539235Sgibbs /* move into position for load averages */ 23639235Sgibbs Move_to(i, y_loadave); 237102884Smjacob 23899598Smjacob /* display new load averages */ 23999598Smjacob /* we should optimize this and only display changes */ 24099598Smjacob for (i = 0; i < 3; i++) 24199598Smjacob { 24299598Smjacob printf("%s%5.2f", 24399598Smjacob i == 0 ? "" : ", ", 24499598Smjacob avenrun[i]); 24599598Smjacob } 24699598Smjacob} 24799598Smjacob 24899598Smjacobi_timeofday(tod) 24999598Smjacob 25099598Smjacobtime_t *tod; 25199598Smjacob 25277365Smjacob{ 25383366Sjulian /* 25477365Smjacob * Display the current time. 25577365Smjacob * "ctime" always returns a string that looks like this: 25677365Smjacob * 25777365Smjacob * Sun Sep 16 01:03:52 1973 25877365Smjacob * 012345678901234567890123 25977365Smjacob * 1 2 26077365Smjacob * 26177365Smjacob * We want indices 11 thru 18 (length 8). 26277365Smjacob */ 26377365Smjacob 26477365Smjacob if (smart_terminal) 26577365Smjacob { 26677365Smjacob Move_to(screen_width - 8, 0); 26777365Smjacob } 26877365Smjacob else 26990813Smjacob { 27090813Smjacob fputs(" ", stdout); 27190813Smjacob } 27290813Smjacob#ifdef DEBUG 27390813Smjacob { 27490813Smjacob char *foo; 27590813Smjacob foo = ctime(tod); 27690813Smjacob fputs(foo, stdout); 27790813Smjacob } 27890813Smjacob#endif 27990813Smjacob printf("%-8.8s\n", &(ctime(tod)[11])); 28090813Smjacob lastline = 1; 28190813Smjacob} 28290813Smjacob 28390813Smjacobstatic int ltotal = 0; 28490813Smjacobstatic char procstates_buffer[MAX_COLS]; 28590813Smjacob 28690813Smjacob/* 28790813Smjacob * *_procstates(total, brkdn, names) - print the process summary line 28890813Smjacob * 28990813Smjacob * Assumptions: cursor is at the beginning of the line on entry 29090813Smjacob * lastline is valid 29190813Smjacob */ 29290813Smjacob 29390813Smjacobi_procstates(total, brkdn) 29490813Smjacob 29590813Smjacobint total; 29690813Smjacobint *brkdn; 29799598Smjacob 29890813Smjacob{ 29990813Smjacob register int i; 30090813Smjacob 30190813Smjacob /* write current number of processes and remember the value */ 30290813Smjacob printf("%d processes:", total); 30390813Smjacob ltotal = total; 30477365Smjacob 30577365Smjacob /* put out enough spaces to get to column 15 */ 30677365Smjacob i = digits(total); 30777365Smjacob while (i++ < 4) 30877365Smjacob { 30977365Smjacob putchar(' '); 31077365Smjacob } 31177365Smjacob 31277365Smjacob /* format and print the process state summary */ 31377365Smjacob summary_format(procstates_buffer, brkdn, procstate_names); 31477365Smjacob fputs(procstates_buffer, stdout); 31577365Smjacob 31677365Smjacob /* save the numbers for next time */ 31777365Smjacob memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 31891036Smjacob} 31977365Smjacob 32077365Smjacobu_procstates(total, brkdn) 32177365Smjacob 32277365Smjacobint total; 32377365Smjacobint *brkdn; 32477365Smjacob 32577365Smjacob{ 32677365Smjacob static char new[MAX_COLS]; 32777365Smjacob register int i; 32877365Smjacob 32977365Smjacob /* update number of processes only if it has changed */ 33077365Smjacob if (ltotal != total) 33177365Smjacob { 33277365Smjacob /* move and overwrite */ 33377365Smjacob#if (x_procstate == 0) 33477365Smjacob Move_to(x_procstate, y_procstate); 33577365Smjacob#else 33677365Smjacob /* cursor is already there...no motion needed */ 33777365Smjacob /* assert(lastline == 1); */ 33877365Smjacob#endif 33977365Smjacob printf("%d", total); 34077365Smjacob 34177365Smjacob /* if number of digits differs, rewrite the label */ 34277365Smjacob if (digits(total) != digits(ltotal)) 34377365Smjacob { 34477365Smjacob fputs(" processes:", stdout); 34577365Smjacob /* put out enough spaces to get to column 15 */ 34677365Smjacob i = digits(total); 34777365Smjacob while (i++ < 4) 34877365Smjacob { 34977365Smjacob putchar(' '); 35077365Smjacob } 35177365Smjacob /* cursor may end up right where we want it!!! */ 35277365Smjacob } 35377365Smjacob 35477365Smjacob /* save new total */ 35577365Smjacob ltotal = total; 35677365Smjacob } 35777365Smjacob 35877365Smjacob /* see if any of the state numbers has changed */ 35977365Smjacob if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) 36077365Smjacob { 36177365Smjacob /* format and update the line */ 36277365Smjacob summary_format(new, brkdn, procstate_names); 36388855Smjacob line_update(procstates_buffer, new, x_brkdn, y_brkdn); 36488855Smjacob memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 36588855Smjacob } 36688855Smjacob} 36788855Smjacob 36888855Smjacob/* 36988855Smjacob * *_cpustates(states, names) - print the cpu state percentages 37088855Smjacob * 37188855Smjacob * Assumptions: cursor is on the PREVIOUS line 37288855Smjacob */ 37388855Smjacob 37488855Smjacobstatic int cpustates_column; 37588855Smjacob 37688855Smjacob/* cpustates_tag() calculates the correct tag to use to label the line */ 37788855Smjacob 37888855Smjacobchar *cpustates_tag() 37988855Smjacob 38088855Smjacob{ 38188855Smjacob register char *use; 38288855Smjacob 38388855Smjacob static char *short_tag = "CPU: "; 38488855Smjacob static char *long_tag = "CPU states: "; 38588855Smjacob 38688855Smjacob /* if length + strlen(long_tag) >= screen_width, then we have to 38788855Smjacob use the shorter tag (we subtract 2 to account for ": ") */ 38888855Smjacob if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) 38988855Smjacob { 39088855Smjacob use = short_tag; 39188855Smjacob } 39288855Smjacob else 39388855Smjacob { 39488855Smjacob use = long_tag; 39588855Smjacob } 39688855Smjacob 39798289Smjacob /* set cpustates_column accordingly then return result */ 39898289Smjacob cpustates_column = strlen(use); 39998289Smjacob return(use); 40098289Smjacob} 40198289Smjacob 40298289Smjacobi_cpustates(states) 40398289Smjacob 40498289Smjacobregister int *states; 40598289Smjacob 40698289Smjacob{ 40798289Smjacob register int i = 0; 40898289Smjacob register int value; 40998289Smjacob register char **names = cpustate_names; 41098289Smjacob register char *thisname; 41198289Smjacob 41299598Smjacob /* print tag and bump lastline */ 41399598Smjacob printf("\n%s", cpustates_tag()); 41499598Smjacob lastline++; 41599598Smjacob 41699598Smjacob /* now walk thru the names and print the line */ 41799598Smjacob while ((thisname = *names++) != NULL) 41899598Smjacob { 41999598Smjacob if (*thisname != '\0') 42099598Smjacob { 42199598Smjacob /* retrieve the value and remember it */ 42299598Smjacob value = *states++; 42399598Smjacob 42499598Smjacob /* if percentage is >= 1000, print it as 100% */ 42599598Smjacob printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), 42699598Smjacob i++ == 0 ? "" : ", ", 42799598Smjacob ((float)value)/10., 42899598Smjacob thisname); 42999598Smjacob } 43099598Smjacob } 43199598Smjacob 43299598Smjacob /* copy over values into "last" array */ 43399598Smjacob memcpy(lcpustates, states, num_cpustates * sizeof(int)); 43499598Smjacob} 43599598Smjacob 43699598Smjacobu_cpustates(states) 43799598Smjacob 43899598Smjacobregister int *states; 43999598Smjacob 44099598Smjacob{ 44199598Smjacob register int value; 44299598Smjacob register char **names = cpustate_names; 44399598Smjacob register char *thisname; 44499598Smjacob register int *lp; 44599598Smjacob register int *colp; 44699598Smjacob 44799598Smjacob Move_to(cpustates_column, y_cpustates); 44899598Smjacob lastline = y_cpustates; 44999598Smjacob lp = lcpustates; 45099598Smjacob colp = cpustate_columns; 45199598Smjacob 45299598Smjacob /* we could be much more optimal about this */ 45399598Smjacob while ((thisname = *names++) != NULL) 45499598Smjacob { 45599598Smjacob if (*thisname != '\0') 45699598Smjacob { 45799598Smjacob /* did the value change since last time? */ 45899598Smjacob if (*lp != *states) 45999598Smjacob { 46099598Smjacob /* yes, move and change */ 46199598Smjacob Move_to(cpustates_column + *colp, y_cpustates); 46299598Smjacob lastline = y_cpustates; 46399598Smjacob 46499598Smjacob /* retrieve value and remember it */ 46599598Smjacob value = *states; 46699598Smjacob 46799598Smjacob /* if percentage is >= 1000, print it as 100% */ 46899598Smjacob printf((value >= 1000 ? "%4.0f" : "%4.1f"), 46999598Smjacob ((double)value)/10.); 47099598Smjacob 47199598Smjacob /* remember it for next time */ 47299598Smjacob *lp = value; 47399598Smjacob } 47499598Smjacob } 47599598Smjacob 47699598Smjacob /* increment and move on */ 47799598Smjacob lp++; 47899598Smjacob states++; 47999598Smjacob colp++; 48099598Smjacob } 48199598Smjacob} 48299598Smjacob 48399598Smjacobz_cpustates() 48499598Smjacob 48599598Smjacob{ 48699598Smjacob register int i = 0; 48799598Smjacob register char **names = cpustate_names; 48899598Smjacob register char *thisname; 48999598Smjacob register int *lp; 49099598Smjacob 49199598Smjacob /* show tag and bump lastline */ 49299598Smjacob printf("\n%s", cpustates_tag()); 49399598Smjacob lastline++; 49499598Smjacob 49599598Smjacob while ((thisname = *names++) != NULL) 49699598Smjacob { 49799598Smjacob if (*thisname != '\0') 49899598Smjacob { 49999598Smjacob printf("%s %% %s", i++ == 0 ? "" : ", ", thisname); 50077365Smjacob } 50177365Smjacob } 50277365Smjacob 50377365Smjacob /* fill the "last" array with all -1s, to insure correct updating */ 50477365Smjacob lp = lcpustates; 50577365Smjacob i = num_cpustates; 50662498Smjacob while (--i >= 0) 50762498Smjacob { 50862498Smjacob *lp++ = -1; 50962498Smjacob } 51072347Smjacob} 51172347Smjacob 51272347Smjacob/* 51372347Smjacob * *_memory(stats) - print "Memory: " followed by the memory summary string 51462498Smjacob * 51562498Smjacob * Assumptions: cursor is on "lastline" 51662498Smjacob * for i_memory ONLY: cursor is on the previous line 51755371Smjacob */ 51855371Smjacob 51955371Smjacobchar memory_buffer[MAX_COLS]; 52055371Smjacob 52155371Smjacobi_memory(stats) 52255371Smjacob 52355371Smjacobint *stats; 524102884Smjacob 525102884Smjacob{ 526102884Smjacob fputs("\nMem: ", stdout); 527102884Smjacob lastline++; 528102884Smjacob 529102884Smjacob /* format and print the memory summary */ 530102884Smjacob summary_format(memory_buffer, stats, memory_names); 531102884Smjacob fputs(memory_buffer, stdout); 532102884Smjacob} 53355371Smjacob 53475200Smjacobu_memory(stats) 53555371Smjacob 53655371Smjacobint *stats; 53755371Smjacob 53875200Smjacob{ 53975200Smjacob static char new[MAX_COLS]; 54075200Smjacob 54155371Smjacob /* format the new line */ 54255371Smjacob summary_format(new, stats, memory_names); 54355371Smjacob line_update(memory_buffer, new, x_mem, y_mem); 54455371Smjacob} 54598289Smjacob 54698289Smjacob/* 54755371Smjacob * *_swap(stats) - print "Swap: " followed by the swap summary string 548102884Smjacob * 54975200Smjacob * Assumptions: cursor is on "lastline" 55055371Smjacob * for i_swap ONLY: cursor is on the previous line 55155371Smjacob */ 55275200Smjacob 55375200Smjacobchar swap_buffer[MAX_COLS]; 55455371Smjacob 55555371Smjacobi_swap(stats) 55655371Smjacob 55775200Smjacobint *stats; 55855371Smjacob 55955371Smjacob{ 56055371Smjacob fputs("\nSwap: ", stdout); 56155371Smjacob lastline++; 56255371Smjacob 56355371Smjacob /* format and print the swap summary */ 564102884Smjacob summary_format(swap_buffer, stats, swap_names); 56575200Smjacob fputs(swap_buffer, stdout); 56655371Smjacob} 56775200Smjacob 56875200Smjacobu_swap(stats) 56975200Smjacob 57075200Smjacobint *stats; 57175200Smjacob 57275200Smjacob{ 57375200Smjacob static char new[MAX_COLS]; 57475200Smjacob 57575200Smjacob /* format the new line */ 57675200Smjacob summary_format(new, stats, swap_names); 57755371Smjacob line_update(swap_buffer, new, x_swap, y_swap); 57855371Smjacob} 57955371Smjacob 58055371Smjacob/* 58155371Smjacob * *_message() - print the next pending message line, or erase the one 58255371Smjacob * that is there. 583102884Smjacob * 58475200Smjacob * Note that u_message is (currently) the same as i_message. 58555371Smjacob * 58683028Smjacob * Assumptions: lastline is consistent 58755371Smjacob */ 58855371Smjacob 58983028Smjacob/* 59082689Smjacob * i_message is funny because it gets its message asynchronously (with 59182689Smjacob * respect to screen updates). 59282689Smjacob */ 59382689Smjacob 59455371Smjacobstatic char next_msg[MAX_COLS + 5]; 59575200Smjacobstatic int msglen = 0; 59683028Smjacob/* Invariant: msglen is always the length of the message currently displayed 59783028Smjacob on the screen (even when next_msg doesn't contain that message). */ 59883028Smjacob 59955371Smjacobi_message() 60055371Smjacob 60155371Smjacob{ 60275200Smjacob while (lastline < y_message) 60355371Smjacob { 60455371Smjacob fputc('\n', stdout); 60555371Smjacob lastline++; 60655371Smjacob } 60755371Smjacob if (next_msg[0] != '\0') 60855371Smjacob { 60955371Smjacob standout(next_msg); 610102884Smjacob msglen = strlen(next_msg); 61155371Smjacob next_msg[0] = '\0'; 61255371Smjacob } 61355371Smjacob else if (msglen > 0) 61455371Smjacob { 61555371Smjacob (void) clear_eol(msglen); 61655371Smjacob msglen = 0; 617102884Smjacob } 61883028Smjacob} 61955371Smjacob 62083028Smjacobu_message() 62183028Smjacob 622102884Smjacob{ 62383028Smjacob i_message(); 62455371Smjacob} 62555371Smjacob 626102884Smjacobstatic int header_length; 627102884Smjacob 628102884Smjacob/* 629102884Smjacob * *_header(text) - print the header for the process area 630102884Smjacob * 63183028Smjacob * Assumptions: cursor is on the previous line and lastline is consistent 63255371Smjacob */ 63355371Smjacob 63455371Smjacobi_header(text) 63555371Smjacob 636102884Smjacobchar *text; 63783028Smjacob 63855371Smjacob{ 639102884Smjacob header_length = strlen(text); 64083028Smjacob if (header_status == ON) 64155371Smjacob { 64255371Smjacob putchar('\n'); 643102884Smjacob fputs(text, stdout); 644102884Smjacob lastline++; 645102884Smjacob } 646102884Smjacob else if (header_status == ERASE) 647102884Smjacob { 64855371Smjacob header_status = OFF; 64955371Smjacob } 65055371Smjacob} 651102884Smjacob 65283028Smjacob/*ARGSUSED*/ 65355371Smjacobu_header(text) 65483028Smjacob 655102884Smjacobchar *text; /* ignored */ 65683028Smjacob 657102884Smjacob{ 658102884Smjacob if (header_status == ERASE) 659102884Smjacob { 66055371Smjacob putchar('\n'); 66155371Smjacob lastline++; 662102884Smjacob clear_eol(header_length); 66383028Smjacob header_status = OFF; 66455371Smjacob } 66583028Smjacob} 66683028Smjacob 667102884Smjacob/* 66883028Smjacob * *_process(line, thisline) - print one process line 669102884Smjacob * 670102884Smjacob * Assumptions: lastline is consistent 671102884Smjacob */ 67255371Smjacob 67383028Smjacobi_process(line, thisline) 67455371Smjacob 67555371Smjacobint line; 676102884Smjacobchar *thisline; 67784242Smjacob 67884242Smjacob{ 67984242Smjacob register char *p; 68084242Smjacob register char *base; 68184242Smjacob 68284242Smjacob /* make sure we are on the correct line */ 68384242Smjacob while (lastline < y_procs + line) 68484242Smjacob { 68584242Smjacob putchar('\n'); 68684242Smjacob lastline++; 68784242Smjacob } 68855371Smjacob 68975200Smjacob /* truncate the line to conform to our current screen width */ 69075200Smjacob thisline[display_width] = '\0'; 69155371Smjacob 69255371Smjacob /* write the line out */ 69355371Smjacob fputs(thisline, stdout); 69475200Smjacob 69555371Smjacob /* copy it in to our buffer */ 69655371Smjacob base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; 69755371Smjacob p = strecpy(base, thisline); 69855371Smjacob 69955371Smjacob /* zero fill the rest of it */ 70055371Smjacob memzero(p, display_width - (p - base)); 70175200Smjacob} 70255371Smjacob 70355371Smjacobu_process(line, newline) 70469557Sdwmalone 70555371Smjacobint line; 70655371Smjacobchar *newline; 70755371Smjacob 70855371Smjacob{ 70955371Smjacob register char *optr; 71055371Smjacob register int screen_line = line + Header_lines; 71155371Smjacob register char *bufferline; 71255371Smjacob 71355371Smjacob /* remember a pointer to the current line in the screen buffer */ 71455371Smjacob bufferline = &screenbuf[lineindex(line)]; 71575200Smjacob 71655371Smjacob /* truncate the line to conform to our current screen width */ 71755371Smjacob newline[display_width] = '\0'; 71855371Smjacob 71955371Smjacob /* is line higher than we went on the last display? */ 72055371Smjacob if (line >= last_hi) 72175200Smjacob { 72275200Smjacob /* yes, just ignore screenbuf and write it out directly */ 72375200Smjacob /* get positioned on the correct line */ 72475200Smjacob if (screen_line - lastline == 1) 72555371Smjacob { 72655371Smjacob putchar('\n'); 72755371Smjacob lastline++; 72855371Smjacob } 72955371Smjacob else 73055371Smjacob { 73155371Smjacob Move_to(0, screen_line); 73255371Smjacob lastline = screen_line; 73355371Smjacob } 734102884Smjacob 73555371Smjacob /* now write the line */ 73655371Smjacob fputs(newline, stdout); 73775200Smjacob 73855371Smjacob /* copy it in to the buffer */ 73955371Smjacob optr = strecpy(bufferline, newline); 74075200Smjacob 74155371Smjacob /* zero fill the rest of it */ 74255371Smjacob memzero(optr, display_width - (optr - bufferline)); 74355371Smjacob } 74475200Smjacob else 74555371Smjacob { 74655371Smjacob line_update(bufferline, newline, 0, line + Header_lines); 74775200Smjacob } 74875200Smjacob} 74955371Smjacob 75055371Smjacobu_endscreen(hi) 75155371Smjacob 75255371Smjacobregister int hi; 75375200Smjacob 75455371Smjacob{ 75555371Smjacob register int screen_line = hi + Header_lines; 75655371Smjacob register int i; 75755371Smjacob 75855371Smjacob if (smart_terminal) 75955371Smjacob { 76055371Smjacob if (hi < last_hi) 76155371Smjacob { 76255371Smjacob /* need to blank the remainder of the screen */ 76355371Smjacob /* but only if there is any screen left below this line */ 76455371Smjacob if (lastline + 1 < screen_length) 76555371Smjacob { 76655371Smjacob /* efficiently move to the end of currently displayed info */ 76777365Smjacob if (screen_line - lastline < 5) 76877365Smjacob { 76977365Smjacob while (lastline < screen_line) 77039235Sgibbs { 77155371Smjacob putchar('\n'); 77255371Smjacob lastline++; 77375200Smjacob } 77455371Smjacob } 77555371Smjacob else 77655371Smjacob { 77783028Smjacob Move_to(0, screen_line); 77855371Smjacob lastline = screen_line; 77955371Smjacob } 78055371Smjacob 78155371Smjacob if (clear_to_end) 78275200Smjacob { 78355371Smjacob /* we can do this the easy way */ 78455371Smjacob putcap(clear_to_end); 78555371Smjacob } 78655371Smjacob else 78765140Smjacob { 78865140Smjacob /* use clear_eol on each line */ 78965140Smjacob i = hi; 79072347Smjacob while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) 79172347Smjacob { 79265140Smjacob putchar('\n'); 79365140Smjacob } 79465140Smjacob } 79583028Smjacob } 79665140Smjacob } 79775200Smjacob last_hi = hi; 79875200Smjacob 79965140Smjacob /* move the cursor to a pleasant place */ 80075200Smjacob Move_to(x_idlecursor, y_idlecursor); 80165140Smjacob lastline = y_idlecursor; 80265140Smjacob } 80365140Smjacob else 80465140Smjacob { 80565140Smjacob /* separate this display from the next with some vertical room */ 80672347Smjacob fputs("\n\n", stdout); 80765140Smjacob } 80865140Smjacob} 80965140Smjacob 81083028Smjacobdisplay_header(t) 81183028Smjacob 81283028Smjacobint t; 81383028Smjacob 81483028Smjacob{ 81583028Smjacob if (t) 81683028Smjacob { 81772347Smjacob header_status = ON; 81872347Smjacob } 81983028Smjacob else if (header_status == ON) 82083028Smjacob { 82183028Smjacob header_status = ERASE; 82283028Smjacob } 82383028Smjacob} 82483028Smjacob 82583028Smjacob/*VARARGS2*/ 82665140Smjacobnew_message(type, msgfmt, a1, a2, a3) 82765140Smjacob 82865140Smjacobint type; 82983028Smjacobchar *msgfmt; 83083028Smjacobcaddr_t a1, a2, a3; 83183028Smjacob 83283028Smjacob{ 83383028Smjacob register int i; 83455371Smjacob 83555371Smjacob /* first, format the message */ 83682689Smjacob (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3); 83782689Smjacob 83882689Smjacob if (msglen > 0) 83955371Smjacob { 84055371Smjacob /* message there already -- can we clear it? */ 84155371Smjacob if (!overstrike) 84283028Smjacob { 84383028Smjacob /* yes -- write it and clear to end */ 84483028Smjacob i = strlen(next_msg); 84583028Smjacob if ((type & MT_delayed) == 0) 84655371Smjacob { 84782689Smjacob type & MT_standout ? standout(next_msg) : 84882689Smjacob fputs(next_msg, stdout); 84975200Smjacob (void) clear_eol(msglen - i); 85055371Smjacob msglen = i; 85183028Smjacob next_msg[0] = '\0'; 85283028Smjacob } 85355371Smjacob } 85455371Smjacob } 85555371Smjacob else 85655371Smjacob { 85755371Smjacob if ((type & MT_delayed) == 0) 85855371Smjacob { 85955371Smjacob type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout); 86055371Smjacob msglen = strlen(next_msg); 86155371Smjacob next_msg[0] = '\0'; 86255371Smjacob } 86355371Smjacob } 86455371Smjacob} 86555371Smjacob 86683028Smjacobclear_message() 86755371Smjacob 86883028Smjacob{ 86983028Smjacob if (clear_eol(msglen) == 1) 87082689Smjacob { 87155371Smjacob putchar('\r'); 87255371Smjacob } 87382689Smjacob} 87455371Smjacob 87555371Smjacobreadline(buffer, size, numeric) 87655371Smjacob 87782689Smjacobchar *buffer; 87883028Smjacobint size; 87982689Smjacobint numeric; 88082689Smjacob 88182689Smjacob{ 88282689Smjacob register char *ptr = buffer; 88382689Smjacob register char ch; 88482689Smjacob register char cnt = 0; 88582689Smjacob register char maxcnt = 0; 88682689Smjacob 88783028Smjacob /* allow room for null terminator */ 88882689Smjacob size -= 1; 88982689Smjacob 89082689Smjacob /* read loop */ 89182689Smjacob while ((fflush(stdout), read(0, ptr, 1) > 0)) 89282689Smjacob { 89383028Smjacob /* newline means we are done */ 89483028Smjacob if ((ch = *ptr) == '\n' || ch == '\r') 89582689Smjacob { 89655371Smjacob break; 89782689Smjacob } 89855371Smjacob 89983028Smjacob /* handle special editing characters */ 90082689Smjacob if (ch == ch_kill) 90182689Smjacob { 90283028Smjacob /* kill line -- account for overstriking */ 90383028Smjacob if (overstrike) 90482689Smjacob { 90582689Smjacob msglen += maxcnt; 90682689Smjacob } 90782689Smjacob 90882689Smjacob /* return null string */ 90982689Smjacob *buffer = '\0'; 91082689Smjacob putchar('\r'); 91182689Smjacob return(-1); 91282689Smjacob } 91383028Smjacob else if (ch == ch_erase) 91482689Smjacob { 91582689Smjacob /* erase previous character */ 91682689Smjacob if (cnt <= 0) 91782689Smjacob { 91882689Smjacob /* none to erase! */ 91983028Smjacob putchar('\7'); 92055371Smjacob } 92155371Smjacob else 92255371Smjacob { 92355371Smjacob fputs("\b \b", stdout); 92455371Smjacob ptr--; 92575200Smjacob cnt--; 92655371Smjacob } 92755371Smjacob } 92855371Smjacob /* check for character validity and buffer overflow */ 92955371Smjacob else if (cnt == size || (numeric && !isdigit(ch)) || 93075200Smjacob !isprint(ch)) 93155371Smjacob { 93255371Smjacob /* not legal */ 93355371Smjacob putchar('\7'); 93455371Smjacob } 93555371Smjacob else 93655371Smjacob { 93783028Smjacob /* echo it and store it in the buffer */ 93855371Smjacob putchar(ch); 93955371Smjacob ptr++; 94055371Smjacob cnt++; 94155371Smjacob if (cnt > maxcnt) 94255371Smjacob { 94355371Smjacob maxcnt = cnt; 94455371Smjacob } 94555371Smjacob } 94655371Smjacob } 94777365Smjacob 94877365Smjacob /* all done -- null terminate the string */ 94977365Smjacob *ptr = '\0'; 95077365Smjacob 95177365Smjacob /* account for the extra characters in the message area */ 95277365Smjacob /* (if terminal overstrikes, remember the furthest they went) */ 95377365Smjacob msglen += overstrike ? maxcnt : cnt; 95477365Smjacob 95577365Smjacob /* return either inputted number or string length */ 95677365Smjacob putchar('\r'); 95777365Smjacob return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); 95877365Smjacob} 95977365Smjacob 96077365Smjacob/* internal support routines */ 96155371Smjacob 96277365Smjacobstatic int string_count(pp) 96355371Smjacob 96473245Smjacobregister char **pp; 96555371Smjacob 96655371Smjacob{ 96783028Smjacob register int cnt; 96855371Smjacob 96973245Smjacob cnt = 0; 97077365Smjacob while (*pp++ != NULL) 97155371Smjacob { 97255371Smjacob cnt++; 97383028Smjacob } 97455371Smjacob return(cnt); 97555371Smjacob} 97673245Smjacob 97777365Smjacobstatic void summary_format(str, numbers, names) 97855371Smjacob 97955371Smjacobchar *str; 98055371Smjacobint *numbers; 98177365Smjacobregister char **names; 98255371Smjacob 98355371Smjacob{ 98477365Smjacob register char *p; 98555371Smjacob register int num; 98677365Smjacob register char *thisname; 98755371Smjacob register int useM = No; 98877365Smjacob 98977365Smjacob /* format each number followed by its string */ 99077365Smjacob p = str; 99177365Smjacob while ((thisname = *names++) != NULL) 99277365Smjacob { 99377365Smjacob /* get the number to format */ 99477365Smjacob num = *numbers++; 99577365Smjacob 99677365Smjacob /* display only non-zero numbers */ 99777365Smjacob if (num > 0) 99877365Smjacob { 99955371Smjacob /* is this number in kilobytes? */ 100073245Smjacob if (thisname[0] == 'K') 100155371Smjacob { 100255371Smjacob /* yes: format it as a memory value */ 100383028Smjacob p = strecpy(p, format_k(num)); 100455371Smjacob 100573245Smjacob /* skip over the K, since it was included by format_k */ 100673245Smjacob p = strecpy(p, thisname+1); 100755371Smjacob } 100855371Smjacob else 100983028Smjacob { 101055371Smjacob p = strecpy(p, itoa(num)); 101155371Smjacob p = strecpy(p, thisname); 101273245Smjacob } 101373245Smjacob } 101455371Smjacob 101555371Smjacob /* ignore negative numbers, but display corresponding string */ 101677365Smjacob else if (num < 0) 101777365Smjacob { 101877365Smjacob p = strecpy(p, thisname); 101977365Smjacob } 102055371Smjacob } 102155371Smjacob 102277365Smjacob /* if the last two characters in the string are ", ", delete them */ 102377365Smjacob p -= 2; 102477365Smjacob if (p >= str && p[0] == ',' && p[1] == ' ') 102555371Smjacob { 102673245Smjacob *p = '\0'; 102755371Smjacob } 102855371Smjacob} 102983028Smjacob 103055371Smjacobstatic void line_update(old, new, start, line) 103173245Smjacob 103277365Smjacobregister char *old; 103355371Smjacobregister char *new; 103455371Smjacobint start; 103583028Smjacobint line; 103655371Smjacob 103755371Smjacob{ 103873245Smjacob register int ch; 103977365Smjacob register int diff; 104055371Smjacob register int newcol = start + 1; 104155371Smjacob register int lastcol = start; 104282689Smjacob char cursor_on_line = No; 104382689Smjacob char *current; 104482689Smjacob 104582689Smjacob /* compare the two strings and only rewrite what has changed */ 104682689Smjacob current = old; 104782689Smjacob#ifdef DEBUG 104882689Smjacob fprintf(debug, "line_update, starting at %d\n", start); 104982689Smjacob fputs(old, debug); 105083028Smjacob fputc('\n', debug); 105182689Smjacob fputs(new, debug); 105282689Smjacob fputs("\n-\n", debug); 105382689Smjacob#endif 105482689Smjacob 105555371Smjacob /* start things off on the right foot */ 105682689Smjacob /* this is to make sure the invariants get set up right */ 105755371Smjacob if ((ch = *new++) != *old) 105883028Smjacob { 105955371Smjacob if (line - lastline == 1 && start == 0) 106055371Smjacob { 106155371Smjacob putchar('\n'); 106273245Smjacob } 106373245Smjacob else 106455371Smjacob { 106555371Smjacob Move_to(start, line); 106655371Smjacob } 106755371Smjacob cursor_on_line = Yes; 106855371Smjacob putchar(ch); 106955371Smjacob *old = ch; 107075200Smjacob lastcol = 1; 107175200Smjacob } 107255371Smjacob old++; 107355371Smjacob 107455371Smjacob /* 107555371Smjacob * main loop -- check each character. If the old and new aren't the 107655371Smjacob * same, then update the display. When the distance from the 107755371Smjacob * current cursor position to the new change is small enough, 107855371Smjacob * the characters that belong there are written to move the 107955371Smjacob * cursor over. 108055371Smjacob * 108155371Smjacob * Invariants: 108255371Smjacob * lastcol is the column where the cursor currently is sitting 108355371Smjacob * (always one beyond the end of the last mismatch). 108455371Smjacob */ 108555371Smjacob do /* yes, a do...while */ 108655371Smjacob { 108755371Smjacob if ((ch = *new++) != *old) 108855371Smjacob { 108955371Smjacob /* new character is different from old */ 109055371Smjacob /* make sure the cursor is on top of this character */ 109155371Smjacob diff = newcol - lastcol; 109255371Smjacob if (diff > 0) 109355371Smjacob { 109455371Smjacob /* some motion is required--figure out which is shorter */ 109555371Smjacob if (diff < 6 && cursor_on_line) 109655371Smjacob { 109755371Smjacob /* overwrite old stuff--get it out of the old buffer */ 109875200Smjacob printf("%.*s", diff, ¤t[lastcol-start]); 109955371Smjacob } 110055371Smjacob else 110155371Smjacob { 110255371Smjacob /* use cursor addressing */ 110355371Smjacob Move_to(newcol, line); 110455371Smjacob cursor_on_line = Yes; 110555371Smjacob } 110655371Smjacob /* remember where the cursor is */ 110755371Smjacob lastcol = newcol + 1; 110855371Smjacob } 110955371Smjacob else 111055371Smjacob { 111155371Smjacob /* already there, update position */ 111255371Smjacob lastcol++; 111355371Smjacob } 111455371Smjacob 111555371Smjacob /* write what we need to */ 111655371Smjacob if (ch == '\0') 111755371Smjacob { 111855371Smjacob /* at the end--terminate with a clear-to-end-of-line */ 111955371Smjacob (void) clear_eol(strlen(old)); 112055371Smjacob } 112155371Smjacob else 112255371Smjacob { 112355371Smjacob /* write the new character */ 112455371Smjacob putchar(ch); 112555371Smjacob } 112655371Smjacob /* put the new character in the screen buffer */ 112755371Smjacob *old = ch; 112855371Smjacob } 112955371Smjacob 113055371Smjacob /* update working column and screen buffer pointer */ 113155371Smjacob newcol++; 113255371Smjacob old++; 113355371Smjacob 113455371Smjacob } while (ch != '\0'); 113555371Smjacob 113655371Smjacob /* zero out the rest of the line buffer -- MUST BE DONE! */ 113755371Smjacob diff = display_width - newcol; 113855371Smjacob if (diff > 0) 113955371Smjacob { 114055371Smjacob memzero(old, diff); 114156007Smjacob } 114273319Smjacob 114387635Smjacob /* remember where the current line is */ 114487635Smjacob if (cursor_on_line) 114555371Smjacob { 114663385Smjacob lastline = line; 114787635Smjacob } 114855387Smjacob} 114955387Smjacob 115055371Smjacob/* 115155371Smjacob * printable(str) - make the string pointed to by "str" into one that is 115287635Smjacob * printable (i.e.: all ascii), by converting all non-printable 115355371Smjacob * characters into '?'. Replacements are done in place and a pointer 115455371Smjacob * to the original buffer is returned. 115555371Smjacob */ 115655371Smjacob 115755371Smjacobchar *printable(str) 115855371Smjacob 115984242Smjacobchar *str; 116087635Smjacob 116156007Smjacob{ 116255371Smjacob register char *ptr; 116355371Smjacob register char ch; 116456007Smjacob 116583028Smjacob ptr = str; 116661775Smjacob while ((ch = *ptr) != '\0') 116761775Smjacob { 116863385Smjacob if (!isprint(ch)) 116984242Smjacob { 117084242Smjacob *ptr = '?'; 117198289Smjacob } 117298289Smjacob ptr++; 117384242Smjacob } 117498289Smjacob return(str); 117584242Smjacob} 117684242Smjacob 117756007Smjacobi_uptime(bt, tod) 117856007Smjacob 117956007Smjacobstruct timeval* bt; 118063385Smjacobtime_t *tod; 118163385Smjacob 118263385Smjacob{ 118384242Smjacob time_t uptime; 118484242Smjacob int days, hrs, mins, secs; 118598289Smjacob 118698289Smjacob if (bt->tv_sec != -1) { 118798289Smjacob uptime = *tod - bt->tv_sec; 118898289Smjacob uptime += 30; 118998289Smjacob days = uptime / 86400; 119098289Smjacob uptime %= 86400; 119198289Smjacob hrs = uptime / 3600; 119263385Smjacob uptime %= 3600; 119356007Smjacob mins = uptime / 60; 119456007Smjacob secs = uptime % 60; 119556007Smjacob 119656007Smjacob /* 119756007Smjacob * Display the uptime. 119855371Smjacob */ 119956007Smjacob 120056007Smjacob if (smart_terminal) 120156007Smjacob { 120256007Smjacob Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); 120356007Smjacob } 120456007Smjacob else 120555387Smjacob { 120698289Smjacob fputs(" ", stdout); 120756007Smjacob } 120856007Smjacob printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); 120956007Smjacob } 121084242Smjacob} 121184242Smjacob