display.c revision 41943
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 1024139Sjoerg */ 1124139Sjoerg 1224139Sjoerg/* 1324139Sjoerg * This file contains the routines that display information on the screen. 1424139Sjoerg * Each section of the screen has two routines: one for initially writing 1524139Sjoerg * all constant and dynamic text, and one for only updating the text that 1624139Sjoerg * changes. The prefix "i_" is used on all the "initial" routines and the 1724139Sjoerg * prefix "u_" is used for all the "updating" routines. 1824139Sjoerg * 1924139Sjoerg * ASSUMPTIONS: 2024139Sjoerg * None of the "i_" routines use any of the termcap capabilities. 2124139Sjoerg * In this way, those routines can be safely used on terminals that 2224139Sjoerg * have minimal (or nonexistant) terminal capabilities. 2324139Sjoerg * 2424139Sjoerg * The routines are called in this order: *_loadave, i_timeofday, 2524139Sjoerg * *_procstates, *_cpustates, *_memory, *_message, *_header, 2624139Sjoerg * *_process, u_endscreen. 2724139Sjoerg */ 2824139Sjoerg 2924139Sjoerg#include "os.h" 3024139Sjoerg#include <ctype.h> 3124139Sjoerg#include <time.h> 3241943Sobrien#include <sys/time.h> 3341943Sobrien#include <sys/types.h> 3441943Sobrien#include <sys/sysctl.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; 6924142Sjoergstatic char **swap_names; 7024139Sjoerg 7124139Sjoergstatic int num_procstates; 7224139Sjoergstatic int num_cpustates; 7324139Sjoergstatic int num_memory; 7424142Sjoergstatic int num_swap; 7524139Sjoerg 7624139Sjoergstatic int *lprocstates; 7724139Sjoergstatic int *lcpustates; 7824139Sjoergstatic int *lmemory; 7924142Sjoergstatic int *lswap; 8024139Sjoerg 8124139Sjoergstatic int *cpustate_columns; 8224139Sjoergstatic int cpustate_total_length; 8324139Sjoerg 8424139Sjoergstatic enum { OFF, ON, ERASE } header_status = ON; 8524139Sjoerg 8624139Sjoergstatic int string_count(); 8724139Sjoergstatic void summary_format(); 8824139Sjoergstatic void line_update(); 8924139Sjoerg 9024139Sjoergint display_resize() 9124139Sjoerg 9224139Sjoerg{ 9324139Sjoerg register int lines; 9424139Sjoerg 9524139Sjoerg /* first, deallocate any previous buffer that may have been there */ 9624139Sjoerg if (screenbuf != NULL) 9724139Sjoerg { 9824139Sjoerg free(screenbuf); 9924139Sjoerg } 10024139Sjoerg 10124139Sjoerg /* calculate the current dimensions */ 10224139Sjoerg /* if operating in "dumb" mode, we only need one line */ 10324139Sjoerg lines = smart_terminal ? screen_length - Header_lines : 1; 10424139Sjoerg 10524139Sjoerg /* we don't want more than MAX_COLS columns, since the machine-dependent 10624139Sjoerg modules make static allocations based on MAX_COLS and we don't want 10724139Sjoerg to run off the end of their buffers */ 10824139Sjoerg display_width = screen_width; 10924139Sjoerg if (display_width >= MAX_COLS) 11024139Sjoerg { 11124139Sjoerg display_width = MAX_COLS - 1; 11224139Sjoerg } 11324139Sjoerg 11424139Sjoerg /* now, allocate space for the screen buffer */ 11524139Sjoerg screenbuf = (char *)malloc(lines * display_width); 11624139Sjoerg if (screenbuf == (char *)NULL) 11724139Sjoerg { 11824139Sjoerg /* oops! */ 11924139Sjoerg return(-1); 12024139Sjoerg } 12124139Sjoerg 12224139Sjoerg /* return number of lines available */ 12324139Sjoerg /* for dumb terminals, pretend like we can show any amount */ 12424139Sjoerg return(smart_terminal ? lines : Largest); 12524139Sjoerg} 12624139Sjoerg 12724139Sjoergint display_init(statics) 12824139Sjoerg 12924139Sjoergstruct statics *statics; 13024139Sjoerg 13124139Sjoerg{ 13224139Sjoerg register int lines; 13324139Sjoerg register char **pp; 13424139Sjoerg register int *ip; 13524139Sjoerg register int i; 13624139Sjoerg 13724139Sjoerg /* call resize to do the dirty work */ 13824139Sjoerg lines = display_resize(); 13924139Sjoerg 14024139Sjoerg /* only do the rest if we need to */ 14124139Sjoerg if (lines > -1) 14224139Sjoerg { 14324139Sjoerg /* save pointers and allocate space for names */ 14424139Sjoerg procstate_names = statics->procstate_names; 14524139Sjoerg num_procstates = string_count(procstate_names); 14624139Sjoerg lprocstates = (int *)malloc(num_procstates * sizeof(int)); 14724139Sjoerg 14824139Sjoerg cpustate_names = statics->cpustate_names; 14924142Sjoerg 15024142Sjoerg swap_names = statics->swap_names; 15124142Sjoerg num_swap = string_count(swap_names); 15224142Sjoerg lswap = (int *)malloc(num_swap * sizeof(int)); 15324139Sjoerg num_cpustates = string_count(cpustate_names); 15424139Sjoerg lcpustates = (int *)malloc(num_cpustates * sizeof(int)); 15524139Sjoerg cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); 15624139Sjoerg 15724139Sjoerg memory_names = statics->memory_names; 15824139Sjoerg num_memory = string_count(memory_names); 15924139Sjoerg lmemory = (int *)malloc(num_memory * sizeof(int)); 16024139Sjoerg 16124139Sjoerg /* calculate starting columns where needed */ 16224139Sjoerg cpustate_total_length = 0; 16324139Sjoerg pp = cpustate_names; 16424139Sjoerg ip = cpustate_columns; 16524139Sjoerg while (*pp != NULL) 16624139Sjoerg { 16724139Sjoerg if ((i = strlen(*pp++)) > 0) 16824139Sjoerg { 16924139Sjoerg *ip++ = cpustate_total_length; 17024139Sjoerg cpustate_total_length += i + 8; 17124139Sjoerg } 17224139Sjoerg } 17324139Sjoerg } 17424139Sjoerg 17524139Sjoerg /* return number of lines available */ 17624139Sjoerg return(lines); 17724139Sjoerg} 17824139Sjoerg 17924139Sjoergi_loadave(mpid, avenrun) 18024139Sjoerg 18124139Sjoergint mpid; 18224139Sjoergdouble *avenrun; 18324139Sjoerg 18424139Sjoerg{ 18524139Sjoerg register int i; 18624139Sjoerg 18724139Sjoerg /* i_loadave also clears the screen, since it is first */ 18824139Sjoerg clear(); 18924139Sjoerg 19024139Sjoerg /* mpid == -1 implies this system doesn't have an _mpid */ 19124139Sjoerg if (mpid != -1) 19224139Sjoerg { 19324139Sjoerg printf("last pid: %5d; ", mpid); 19424139Sjoerg } 19524139Sjoerg 19624139Sjoerg printf("load averages"); 19724139Sjoerg 19824139Sjoerg for (i = 0; i < 3; i++) 19924139Sjoerg { 20024139Sjoerg printf("%c %5.2f", 20124139Sjoerg i == 0 ? ':' : ',', 20224139Sjoerg avenrun[i]); 20324139Sjoerg } 20424139Sjoerg lmpid = mpid; 20524139Sjoerg} 20624139Sjoerg 20724139Sjoergu_loadave(mpid, avenrun) 20824139Sjoerg 20924139Sjoergint mpid; 21024139Sjoergdouble *avenrun; 21124139Sjoerg 21224139Sjoerg{ 21324139Sjoerg register int i; 21424139Sjoerg 21524139Sjoerg if (mpid != -1) 21624139Sjoerg { 21724139Sjoerg /* change screen only when value has really changed */ 21824139Sjoerg if (mpid != lmpid) 21924139Sjoerg { 22024139Sjoerg Move_to(x_lastpid, y_lastpid); 22124139Sjoerg printf("%5d", mpid); 22224139Sjoerg lmpid = mpid; 22324139Sjoerg } 22424139Sjoerg 22524139Sjoerg /* i remembers x coordinate to move to */ 22624139Sjoerg i = x_loadave; 22724139Sjoerg } 22824139Sjoerg else 22924139Sjoerg { 23024139Sjoerg i = x_loadave_nompid; 23124139Sjoerg } 23224139Sjoerg 23324139Sjoerg /* move into position for load averages */ 23424139Sjoerg Move_to(i, y_loadave); 23524139Sjoerg 23624139Sjoerg /* display new load averages */ 23724139Sjoerg /* we should optimize this and only display changes */ 23824139Sjoerg for (i = 0; i < 3; i++) 23924139Sjoerg { 24024139Sjoerg printf("%s%5.2f", 24124139Sjoerg i == 0 ? "" : ", ", 24224139Sjoerg avenrun[i]); 24324139Sjoerg } 24424139Sjoerg} 24524139Sjoerg 24641943Sobrienstruct timeval boottime; 24741943Sobrientime_t now; 24841943Sobrientime_t uptime; 24941943Sobrien 25024139Sjoergi_timeofday(tod) 25124139Sjoerg 25224139Sjoergtime_t *tod; 25324139Sjoerg 25424139Sjoerg{ 25541943Sobrien int days, hrs, i, mins, secs; 25641943Sobrien int mib[2]; 25741943Sobrien size_t size; 25841943Sobrien 25941943Sobrien (void)time(&now); 26041943Sobrien 26141943Sobrien /* 26241943Sobrien * Print how long system has been up. 26341943Sobrien * (Found by looking getting "boottime" from the kernel) 26441943Sobrien */ 26541943Sobrien mib[0] = CTL_KERN; 26641943Sobrien mib[1] = KERN_BOOTTIME; 26741943Sobrien size = sizeof(boottime); 26841943Sobrien if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && 26941943Sobrien boottime.tv_sec != 0) { 27041943Sobrien uptime = now - boottime.tv_sec; 27141943Sobrien uptime += 30; 27241943Sobrien days = uptime / 86400; 27341943Sobrien uptime %= 86400; 27441943Sobrien hrs = uptime / 3600; 27541943Sobrien uptime %= 3600; 27641943Sobrien mins = uptime / 60; 27741943Sobrien secs = uptime % 60; 27841943Sobrien 27941943Sobrien if (smart_terminal) 28041943Sobrien { 28141943Sobrien Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); 28241943Sobrien } 28341943Sobrien else 28441943Sobrien { 28541943Sobrien fputs(" ", stdout); 28641943Sobrien } 28741943Sobrien 28841943Sobrien printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); 28941943Sobrien } 29041943Sobrien 29124139Sjoerg /* 29224139Sjoerg * Display the current time. 29324139Sjoerg * "ctime" always returns a string that looks like this: 29424139Sjoerg * 29524139Sjoerg * Sun Sep 16 01:03:52 1973 29624139Sjoerg * 012345678901234567890123 29724139Sjoerg * 1 2 29824139Sjoerg * 29924139Sjoerg * We want indices 11 thru 18 (length 8). 30024139Sjoerg */ 30124139Sjoerg 30224139Sjoerg if (smart_terminal) 30324139Sjoerg { 30424139Sjoerg Move_to(screen_width - 8, 0); 30524139Sjoerg } 30624139Sjoerg else 30724139Sjoerg { 30824139Sjoerg fputs(" ", stdout); 30924139Sjoerg } 31024139Sjoerg#ifdef DEBUG 31124139Sjoerg { 31224139Sjoerg char *foo; 31324139Sjoerg foo = ctime(tod); 31424139Sjoerg fputs(foo, stdout); 31524139Sjoerg } 31624139Sjoerg#endif 31724139Sjoerg printf("%-8.8s\n", &(ctime(tod)[11])); 31824139Sjoerg lastline = 1; 31924139Sjoerg} 32024139Sjoerg 32124139Sjoergstatic int ltotal = 0; 32224139Sjoergstatic char procstates_buffer[128]; 32324139Sjoerg 32424139Sjoerg/* 32524139Sjoerg * *_procstates(total, brkdn, names) - print the process summary line 32624139Sjoerg * 32724139Sjoerg * Assumptions: cursor is at the beginning of the line on entry 32824139Sjoerg * lastline is valid 32924139Sjoerg */ 33024139Sjoerg 33124139Sjoergi_procstates(total, brkdn) 33224139Sjoerg 33324139Sjoergint total; 33424139Sjoergint *brkdn; 33524139Sjoerg 33624139Sjoerg{ 33724139Sjoerg register int i; 33824139Sjoerg 33924139Sjoerg /* write current number of processes and remember the value */ 34024139Sjoerg printf("%d processes:", total); 34124139Sjoerg ltotal = total; 34224139Sjoerg 34324139Sjoerg /* put out enough spaces to get to column 15 */ 34424139Sjoerg i = digits(total); 34524139Sjoerg while (i++ < 4) 34624139Sjoerg { 34724139Sjoerg putchar(' '); 34824139Sjoerg } 34924139Sjoerg 35024139Sjoerg /* format and print the process state summary */ 35124139Sjoerg summary_format(procstates_buffer, brkdn, procstate_names); 35224139Sjoerg fputs(procstates_buffer, stdout); 35324139Sjoerg 35424139Sjoerg /* save the numbers for next time */ 35524139Sjoerg memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 35624139Sjoerg} 35724139Sjoerg 35824139Sjoergu_procstates(total, brkdn) 35924139Sjoerg 36024139Sjoergint total; 36124139Sjoergint *brkdn; 36224139Sjoerg 36324139Sjoerg{ 36424139Sjoerg static char new[128]; 36524139Sjoerg register int i; 36624139Sjoerg 36724139Sjoerg /* update number of processes only if it has changed */ 36824139Sjoerg if (ltotal != total) 36924139Sjoerg { 37024139Sjoerg /* move and overwrite */ 37124139Sjoerg#if (x_procstate == 0) 37224139Sjoerg Move_to(x_procstate, y_procstate); 37324139Sjoerg#else 37424139Sjoerg /* cursor is already there...no motion needed */ 37524139Sjoerg /* assert(lastline == 1); */ 37624139Sjoerg#endif 37724139Sjoerg printf("%d", total); 37824139Sjoerg 37924139Sjoerg /* if number of digits differs, rewrite the label */ 38024139Sjoerg if (digits(total) != digits(ltotal)) 38124139Sjoerg { 38224139Sjoerg fputs(" processes:", stdout); 38324139Sjoerg /* put out enough spaces to get to column 15 */ 38424139Sjoerg i = digits(total); 38524139Sjoerg while (i++ < 4) 38624139Sjoerg { 38724139Sjoerg putchar(' '); 38824139Sjoerg } 38924139Sjoerg /* cursor may end up right where we want it!!! */ 39024139Sjoerg } 39124139Sjoerg 39224139Sjoerg /* save new total */ 39324139Sjoerg ltotal = total; 39424139Sjoerg } 39524139Sjoerg 39624139Sjoerg /* see if any of the state numbers has changed */ 39724139Sjoerg if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) 39824139Sjoerg { 39924139Sjoerg /* format and update the line */ 40024139Sjoerg summary_format(new, brkdn, procstate_names); 40124139Sjoerg line_update(procstates_buffer, new, x_brkdn, y_brkdn); 40224139Sjoerg memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); 40324139Sjoerg } 40424139Sjoerg} 40524139Sjoerg 40624139Sjoerg/* 40724139Sjoerg * *_cpustates(states, names) - print the cpu state percentages 40824139Sjoerg * 40924139Sjoerg * Assumptions: cursor is on the PREVIOUS line 41024139Sjoerg */ 41124139Sjoerg 41224139Sjoergstatic int cpustates_column; 41324139Sjoerg 41424139Sjoerg/* cpustates_tag() calculates the correct tag to use to label the line */ 41524139Sjoerg 41624139Sjoergchar *cpustates_tag() 41724139Sjoerg 41824139Sjoerg{ 41924139Sjoerg register char *use; 42024139Sjoerg 42124139Sjoerg static char *short_tag = "CPU: "; 42224139Sjoerg static char *long_tag = "CPU states: "; 42324139Sjoerg 42424139Sjoerg /* if length + strlen(long_tag) >= screen_width, then we have to 42524139Sjoerg use the shorter tag (we subtract 2 to account for ": ") */ 42624139Sjoerg if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) 42724139Sjoerg { 42824139Sjoerg use = short_tag; 42924139Sjoerg } 43024139Sjoerg else 43124139Sjoerg { 43224139Sjoerg use = long_tag; 43324139Sjoerg } 43424139Sjoerg 43524139Sjoerg /* set cpustates_column accordingly then return result */ 43624139Sjoerg cpustates_column = strlen(use); 43724139Sjoerg return(use); 43824139Sjoerg} 43924139Sjoerg 44024139Sjoergi_cpustates(states) 44124139Sjoerg 44224139Sjoergregister int *states; 44324139Sjoerg 44424139Sjoerg{ 44524139Sjoerg register int i = 0; 44624139Sjoerg register int value; 44724139Sjoerg register char **names = cpustate_names; 44824139Sjoerg register char *thisname; 44924139Sjoerg 45024139Sjoerg /* print tag and bump lastline */ 45124139Sjoerg printf("\n%s", cpustates_tag()); 45224139Sjoerg lastline++; 45324139Sjoerg 45424139Sjoerg /* now walk thru the names and print the line */ 45524139Sjoerg while ((thisname = *names++) != NULL) 45624139Sjoerg { 45724139Sjoerg if (*thisname != '\0') 45824139Sjoerg { 45924139Sjoerg /* retrieve the value and remember it */ 46024139Sjoerg value = *states++; 46124139Sjoerg 46224139Sjoerg /* if percentage is >= 1000, print it as 100% */ 46324139Sjoerg printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), 46424139Sjoerg i++ == 0 ? "" : ", ", 46524139Sjoerg ((float)value)/10., 46624139Sjoerg thisname); 46724139Sjoerg } 46824139Sjoerg } 46924139Sjoerg 47024139Sjoerg /* copy over values into "last" array */ 47124139Sjoerg memcpy(lcpustates, states, num_cpustates * sizeof(int)); 47224139Sjoerg} 47324139Sjoerg 47424139Sjoergu_cpustates(states) 47524139Sjoerg 47624139Sjoergregister int *states; 47724139Sjoerg 47824139Sjoerg{ 47924139Sjoerg register int value; 48024139Sjoerg register char **names = cpustate_names; 48124139Sjoerg register char *thisname; 48224139Sjoerg register int *lp; 48324139Sjoerg register int *colp; 48424139Sjoerg 48524139Sjoerg Move_to(cpustates_column, y_cpustates); 48624139Sjoerg lastline = y_cpustates; 48724139Sjoerg lp = lcpustates; 48824139Sjoerg colp = cpustate_columns; 48924139Sjoerg 49024139Sjoerg /* we could be much more optimal about this */ 49124139Sjoerg while ((thisname = *names++) != NULL) 49224139Sjoerg { 49324139Sjoerg if (*thisname != '\0') 49424139Sjoerg { 49524139Sjoerg /* did the value change since last time? */ 49624139Sjoerg if (*lp != *states) 49724139Sjoerg { 49824139Sjoerg /* yes, move and change */ 49924139Sjoerg Move_to(cpustates_column + *colp, y_cpustates); 50024139Sjoerg lastline = y_cpustates; 50124139Sjoerg 50224139Sjoerg /* retrieve value and remember it */ 50324139Sjoerg value = *states; 50424139Sjoerg 50524139Sjoerg /* if percentage is >= 1000, print it as 100% */ 50624139Sjoerg printf((value >= 1000 ? "%4.0f" : "%4.1f"), 50724139Sjoerg ((double)value)/10.); 50824139Sjoerg 50924139Sjoerg /* remember it for next time */ 51024139Sjoerg *lp = *states; 51124139Sjoerg } 51224139Sjoerg } 51324139Sjoerg 51424139Sjoerg /* increment and move on */ 51524139Sjoerg lp++; 51624139Sjoerg states++; 51724139Sjoerg colp++; 51824139Sjoerg } 51924139Sjoerg} 52024139Sjoerg 52124139Sjoergz_cpustates() 52224139Sjoerg 52324139Sjoerg{ 52424139Sjoerg register int i = 0; 52524139Sjoerg register char **names = cpustate_names; 52624139Sjoerg register char *thisname; 52724139Sjoerg register int *lp; 52824139Sjoerg 52924139Sjoerg /* show tag and bump lastline */ 53024139Sjoerg printf("\n%s", cpustates_tag()); 53124139Sjoerg lastline++; 53224139Sjoerg 53324139Sjoerg while ((thisname = *names++) != NULL) 53424139Sjoerg { 53524139Sjoerg if (*thisname != '\0') 53624139Sjoerg { 53724139Sjoerg printf("%s %% %s", i++ == 0 ? "" : ", ", thisname); 53824139Sjoerg } 53924139Sjoerg } 54024139Sjoerg 54124139Sjoerg /* fill the "last" array with all -1s, to insure correct updating */ 54224139Sjoerg lp = lcpustates; 54324139Sjoerg i = num_cpustates; 54424139Sjoerg while (--i >= 0) 54524139Sjoerg { 54624139Sjoerg *lp++ = -1; 54724139Sjoerg } 54824139Sjoerg} 54924139Sjoerg 55024139Sjoerg/* 55124139Sjoerg * *_memory(stats) - print "Memory: " followed by the memory summary string 55224139Sjoerg * 55324139Sjoerg * Assumptions: cursor is on "lastline" 55424139Sjoerg * for i_memory ONLY: cursor is on the previous line 55524139Sjoerg */ 55624139Sjoerg 55724139Sjoergchar memory_buffer[MAX_COLS]; 55824139Sjoerg 55924139Sjoergi_memory(stats) 56024139Sjoerg 56124139Sjoergint *stats; 56224139Sjoerg 56324139Sjoerg{ 56424142Sjoerg fputs("\nMem: ", stdout); 56524139Sjoerg lastline++; 56624139Sjoerg 56724139Sjoerg /* format and print the memory summary */ 56824139Sjoerg summary_format(memory_buffer, stats, memory_names); 56924139Sjoerg fputs(memory_buffer, stdout); 57024139Sjoerg} 57124139Sjoerg 57224139Sjoergu_memory(stats) 57324139Sjoerg 57424139Sjoergint *stats; 57524139Sjoerg 57624139Sjoerg{ 57724139Sjoerg static char new[MAX_COLS]; 57824139Sjoerg 57924139Sjoerg /* format the new line */ 58024139Sjoerg summary_format(new, stats, memory_names); 58124139Sjoerg line_update(memory_buffer, new, x_mem, y_mem); 58224139Sjoerg} 58324139Sjoerg 58424139Sjoerg/* 58524142Sjoerg * *_swap(stats) - print "Swap: " followed by the swap summary string 58624142Sjoerg * 58724142Sjoerg * Assumptions: cursor is on "lastline" 58824142Sjoerg * for i_swap ONLY: cursor is on the previous line 58924142Sjoerg */ 59024142Sjoerg 59124142Sjoergchar swap_buffer[MAX_COLS]; 59224142Sjoerg 59324142Sjoergi_swap(stats) 59424142Sjoerg 59524142Sjoergint *stats; 59624142Sjoerg 59724142Sjoerg{ 59824142Sjoerg fputs("\nSwap: ", stdout); 59924142Sjoerg lastline++; 60024142Sjoerg 60124142Sjoerg /* format and print the swap summary */ 60224142Sjoerg summary_format(swap_buffer, stats, swap_names); 60324142Sjoerg fputs(swap_buffer, stdout); 60424142Sjoerg} 60524142Sjoerg 60624142Sjoergu_swap(stats) 60724142Sjoerg 60824142Sjoergint *stats; 60924142Sjoerg 61024142Sjoerg{ 61124142Sjoerg static char new[MAX_COLS]; 61224142Sjoerg 61324142Sjoerg /* format the new line */ 61424142Sjoerg summary_format(new, stats, swap_names); 61524142Sjoerg line_update(swap_buffer, new, x_swap, y_swap); 61624142Sjoerg} 61724142Sjoerg 61824142Sjoerg/* 61924139Sjoerg * *_message() - print the next pending message line, or erase the one 62024139Sjoerg * that is there. 62124139Sjoerg * 62224139Sjoerg * Note that u_message is (currently) the same as i_message. 62324139Sjoerg * 62424139Sjoerg * Assumptions: lastline is consistent 62524139Sjoerg */ 62624139Sjoerg 62724139Sjoerg/* 62824139Sjoerg * i_message is funny because it gets its message asynchronously (with 62924139Sjoerg * respect to screen updates). 63024139Sjoerg */ 63124139Sjoerg 63224139Sjoergstatic char next_msg[MAX_COLS + 5]; 63324139Sjoergstatic int msglen = 0; 63424139Sjoerg/* Invariant: msglen is always the length of the message currently displayed 63524139Sjoerg on the screen (even when next_msg doesn't contain that message). */ 63624139Sjoerg 63724139Sjoergi_message() 63824139Sjoerg 63924139Sjoerg{ 64024139Sjoerg while (lastline < y_message) 64124139Sjoerg { 64224139Sjoerg fputc('\n', stdout); 64324139Sjoerg lastline++; 64424139Sjoerg } 64524139Sjoerg if (next_msg[0] != '\0') 64624139Sjoerg { 64724139Sjoerg standout(next_msg); 64824139Sjoerg msglen = strlen(next_msg); 64924139Sjoerg next_msg[0] = '\0'; 65024139Sjoerg } 65124139Sjoerg else if (msglen > 0) 65224139Sjoerg { 65324139Sjoerg (void) clear_eol(msglen); 65424139Sjoerg msglen = 0; 65524139Sjoerg } 65624139Sjoerg} 65724139Sjoerg 65824139Sjoergu_message() 65924139Sjoerg 66024139Sjoerg{ 66124139Sjoerg i_message(); 66224139Sjoerg} 66324139Sjoerg 66424139Sjoergstatic int header_length; 66524139Sjoerg 66624139Sjoerg/* 66724139Sjoerg * *_header(text) - print the header for the process area 66824139Sjoerg * 66924139Sjoerg * Assumptions: cursor is on the previous line and lastline is consistent 67024139Sjoerg */ 67124139Sjoerg 67224139Sjoergi_header(text) 67324139Sjoerg 67424139Sjoergchar *text; 67524139Sjoerg 67624139Sjoerg{ 67724139Sjoerg header_length = strlen(text); 67824139Sjoerg if (header_status == ON) 67924139Sjoerg { 68024139Sjoerg putchar('\n'); 68124139Sjoerg fputs(text, stdout); 68224139Sjoerg lastline++; 68324139Sjoerg } 68424139Sjoerg else if (header_status == ERASE) 68524139Sjoerg { 68624139Sjoerg header_status = OFF; 68724139Sjoerg } 68824139Sjoerg} 68924139Sjoerg 69024139Sjoerg/*ARGSUSED*/ 69124139Sjoergu_header(text) 69224139Sjoerg 69324139Sjoergchar *text; /* ignored */ 69424139Sjoerg 69524139Sjoerg{ 69624139Sjoerg if (header_status == ERASE) 69724139Sjoerg { 69824139Sjoerg putchar('\n'); 69924139Sjoerg lastline++; 70024139Sjoerg clear_eol(header_length); 70124139Sjoerg header_status = OFF; 70224139Sjoerg } 70324139Sjoerg} 70424139Sjoerg 70524139Sjoerg/* 70624139Sjoerg * *_process(line, thisline) - print one process line 70724139Sjoerg * 70824139Sjoerg * Assumptions: lastline is consistent 70924139Sjoerg */ 71024139Sjoerg 71124139Sjoergi_process(line, thisline) 71224139Sjoerg 71324139Sjoergint line; 71424139Sjoergchar *thisline; 71524139Sjoerg 71624139Sjoerg{ 71724139Sjoerg register char *p; 71824139Sjoerg register char *base; 71924139Sjoerg 72024139Sjoerg /* make sure we are on the correct line */ 72124139Sjoerg while (lastline < y_procs + line) 72224139Sjoerg { 72324139Sjoerg putchar('\n'); 72424139Sjoerg lastline++; 72524139Sjoerg } 72624139Sjoerg 72724139Sjoerg /* truncate the line to conform to our current screen width */ 72824139Sjoerg thisline[display_width] = '\0'; 72924139Sjoerg 73024139Sjoerg /* write the line out */ 73124139Sjoerg fputs(thisline, stdout); 73224139Sjoerg 73324139Sjoerg /* copy it in to our buffer */ 73424139Sjoerg base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; 73524139Sjoerg p = strecpy(base, thisline); 73624139Sjoerg 73724139Sjoerg /* zero fill the rest of it */ 73824139Sjoerg memzero(p, display_width - (p - base)); 73924139Sjoerg} 74024139Sjoerg 74124139Sjoergu_process(line, newline) 74224139Sjoerg 74324139Sjoergint line; 74424139Sjoergchar *newline; 74524139Sjoerg 74624139Sjoerg{ 74724139Sjoerg register char *optr; 74824139Sjoerg register int screen_line = line + Header_lines; 74924139Sjoerg register char *bufferline; 75024139Sjoerg 75124139Sjoerg /* remember a pointer to the current line in the screen buffer */ 75224139Sjoerg bufferline = &screenbuf[lineindex(line)]; 75324139Sjoerg 75424139Sjoerg /* truncate the line to conform to our current screen width */ 75524139Sjoerg newline[display_width] = '\0'; 75624139Sjoerg 75724139Sjoerg /* is line higher than we went on the last display? */ 75824139Sjoerg if (line >= last_hi) 75924139Sjoerg { 76024139Sjoerg /* yes, just ignore screenbuf and write it out directly */ 76124139Sjoerg /* get positioned on the correct line */ 76224139Sjoerg if (screen_line - lastline == 1) 76324139Sjoerg { 76424139Sjoerg putchar('\n'); 76524139Sjoerg lastline++; 76624139Sjoerg } 76724139Sjoerg else 76824139Sjoerg { 76924139Sjoerg Move_to(0, screen_line); 77024139Sjoerg lastline = screen_line; 77124139Sjoerg } 77224139Sjoerg 77324139Sjoerg /* now write the line */ 77424139Sjoerg fputs(newline, stdout); 77524139Sjoerg 77624139Sjoerg /* copy it in to the buffer */ 77724139Sjoerg optr = strecpy(bufferline, newline); 77824139Sjoerg 77924139Sjoerg /* zero fill the rest of it */ 78024139Sjoerg memzero(optr, display_width - (optr - bufferline)); 78124139Sjoerg } 78224139Sjoerg else 78324139Sjoerg { 78424139Sjoerg line_update(bufferline, newline, 0, line + Header_lines); 78524139Sjoerg } 78624139Sjoerg} 78724139Sjoerg 78824139Sjoergu_endscreen(hi) 78924139Sjoerg 79024139Sjoergregister int hi; 79124139Sjoerg 79224139Sjoerg{ 79324139Sjoerg register int screen_line = hi + Header_lines; 79424139Sjoerg register int i; 79524139Sjoerg 79624139Sjoerg if (smart_terminal) 79724139Sjoerg { 79824139Sjoerg if (hi < last_hi) 79924139Sjoerg { 80024139Sjoerg /* need to blank the remainder of the screen */ 80124139Sjoerg /* but only if there is any screen left below this line */ 80224139Sjoerg if (lastline + 1 < screen_length) 80324139Sjoerg { 80424139Sjoerg /* efficiently move to the end of currently displayed info */ 80524139Sjoerg if (screen_line - lastline < 5) 80624139Sjoerg { 80724139Sjoerg while (lastline < screen_line) 80824139Sjoerg { 80924139Sjoerg putchar('\n'); 81024139Sjoerg lastline++; 81124139Sjoerg } 81224139Sjoerg } 81324139Sjoerg else 81424139Sjoerg { 81524139Sjoerg Move_to(0, screen_line); 81624139Sjoerg lastline = screen_line; 81724139Sjoerg } 81824139Sjoerg 81924139Sjoerg if (clear_to_end) 82024139Sjoerg { 82124139Sjoerg /* we can do this the easy way */ 82224139Sjoerg putcap(clear_to_end); 82324139Sjoerg } 82424139Sjoerg else 82524139Sjoerg { 82624139Sjoerg /* use clear_eol on each line */ 82724139Sjoerg i = hi; 82824139Sjoerg while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) 82924139Sjoerg { 83024139Sjoerg putchar('\n'); 83124139Sjoerg } 83224139Sjoerg } 83324139Sjoerg } 83424139Sjoerg } 83524139Sjoerg last_hi = hi; 83624139Sjoerg 83724139Sjoerg /* move the cursor to a pleasant place */ 83824139Sjoerg Move_to(x_idlecursor, y_idlecursor); 83924139Sjoerg lastline = y_idlecursor; 84024139Sjoerg } 84124139Sjoerg else 84224139Sjoerg { 84324139Sjoerg /* separate this display from the next with some vertical room */ 84424139Sjoerg fputs("\n\n", stdout); 84524139Sjoerg } 84624139Sjoerg} 84724139Sjoerg 84824139Sjoergdisplay_header(t) 84924139Sjoerg 85024139Sjoergint t; 85124139Sjoerg 85224139Sjoerg{ 85324139Sjoerg if (t) 85424139Sjoerg { 85524139Sjoerg header_status = ON; 85624139Sjoerg } 85724139Sjoerg else if (header_status == ON) 85824139Sjoerg { 85924139Sjoerg header_status = ERASE; 86024139Sjoerg } 86124139Sjoerg} 86224139Sjoerg 86324139Sjoerg/*VARARGS2*/ 86424139Sjoergnew_message(type, msgfmt, a1, a2, a3) 86524139Sjoerg 86624139Sjoergint type; 86724139Sjoergchar *msgfmt; 86824139Sjoergcaddr_t a1, a2, a3; 86924139Sjoerg 87024139Sjoerg{ 87124139Sjoerg register int i; 87224139Sjoerg 87324139Sjoerg /* first, format the message */ 87424139Sjoerg (void) sprintf(next_msg, msgfmt, a1, a2, a3); 87524139Sjoerg 87624139Sjoerg if (msglen > 0) 87724139Sjoerg { 87824139Sjoerg /* message there already -- can we clear it? */ 87924139Sjoerg if (!overstrike) 88024139Sjoerg { 88124139Sjoerg /* yes -- write it and clear to end */ 88224139Sjoerg i = strlen(next_msg); 88324139Sjoerg if ((type & MT_delayed) == 0) 88424139Sjoerg { 88524139Sjoerg type & MT_standout ? standout(next_msg) : 88624139Sjoerg fputs(next_msg, stdout); 88724139Sjoerg (void) clear_eol(msglen - i); 88824139Sjoerg msglen = i; 88924139Sjoerg next_msg[0] = '\0'; 89024139Sjoerg } 89124139Sjoerg } 89224139Sjoerg } 89324139Sjoerg else 89424139Sjoerg { 89524139Sjoerg if ((type & MT_delayed) == 0) 89624139Sjoerg { 89724139Sjoerg type & MT_standout ? standout(next_msg) : fputs(next_msg, stdout); 89824139Sjoerg msglen = strlen(next_msg); 89924139Sjoerg next_msg[0] = '\0'; 90024139Sjoerg } 90124139Sjoerg } 90224139Sjoerg} 90324139Sjoerg 90424139Sjoergclear_message() 90524139Sjoerg 90624139Sjoerg{ 90724139Sjoerg if (clear_eol(msglen) == 1) 90824139Sjoerg { 90924139Sjoerg putchar('\r'); 91024139Sjoerg } 91124139Sjoerg} 91224139Sjoerg 91324139Sjoergreadline(buffer, size, numeric) 91424139Sjoerg 91524139Sjoergchar *buffer; 91624139Sjoergint size; 91724139Sjoergint numeric; 91824139Sjoerg 91924139Sjoerg{ 92024139Sjoerg register char *ptr = buffer; 92124139Sjoerg register char ch; 92224139Sjoerg register char cnt = 0; 92324139Sjoerg register char maxcnt = 0; 92424139Sjoerg 92524139Sjoerg /* allow room for null terminator */ 92624139Sjoerg size -= 1; 92724139Sjoerg 92824139Sjoerg /* read loop */ 92924139Sjoerg while ((fflush(stdout), read(0, ptr, 1) > 0)) 93024139Sjoerg { 93124139Sjoerg /* newline means we are done */ 93224142Sjoerg if ((ch = *ptr) == '\n' || ch == '\r') 93324139Sjoerg { 93424139Sjoerg break; 93524139Sjoerg } 93624139Sjoerg 93724139Sjoerg /* handle special editing characters */ 93824139Sjoerg if (ch == ch_kill) 93924139Sjoerg { 94024139Sjoerg /* kill line -- account for overstriking */ 94124139Sjoerg if (overstrike) 94224139Sjoerg { 94324139Sjoerg msglen += maxcnt; 94424139Sjoerg } 94524139Sjoerg 94624139Sjoerg /* return null string */ 94724139Sjoerg *buffer = '\0'; 94824139Sjoerg putchar('\r'); 94924139Sjoerg return(-1); 95024139Sjoerg } 95124139Sjoerg else if (ch == ch_erase) 95224139Sjoerg { 95324139Sjoerg /* erase previous character */ 95424139Sjoerg if (cnt <= 0) 95524139Sjoerg { 95624139Sjoerg /* none to erase! */ 95724139Sjoerg putchar('\7'); 95824139Sjoerg } 95924139Sjoerg else 96024139Sjoerg { 96124139Sjoerg fputs("\b \b", stdout); 96224139Sjoerg ptr--; 96324139Sjoerg cnt--; 96424139Sjoerg } 96524139Sjoerg } 96624139Sjoerg /* check for character validity and buffer overflow */ 96724139Sjoerg else if (cnt == size || (numeric && !isdigit(ch)) || 96824139Sjoerg !isprint(ch)) 96924139Sjoerg { 97024139Sjoerg /* not legal */ 97124139Sjoerg putchar('\7'); 97224139Sjoerg } 97324139Sjoerg else 97424139Sjoerg { 97524139Sjoerg /* echo it and store it in the buffer */ 97624139Sjoerg putchar(ch); 97724139Sjoerg ptr++; 97824139Sjoerg cnt++; 97924139Sjoerg if (cnt > maxcnt) 98024139Sjoerg { 98124139Sjoerg maxcnt = cnt; 98224139Sjoerg } 98324139Sjoerg } 98424139Sjoerg } 98524139Sjoerg 98624139Sjoerg /* all done -- null terminate the string */ 98724139Sjoerg *ptr = '\0'; 98824139Sjoerg 98924139Sjoerg /* account for the extra characters in the message area */ 99024139Sjoerg /* (if terminal overstrikes, remember the furthest they went) */ 99124139Sjoerg msglen += overstrike ? maxcnt : cnt; 99224139Sjoerg 99324139Sjoerg /* return either inputted number or string length */ 99424139Sjoerg putchar('\r'); 99524139Sjoerg return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); 99624139Sjoerg} 99724139Sjoerg 99824139Sjoerg/* internal support routines */ 99924139Sjoerg 100024139Sjoergstatic int string_count(pp) 100124139Sjoerg 100224139Sjoergregister char **pp; 100324139Sjoerg 100424139Sjoerg{ 100524139Sjoerg register int cnt; 100624139Sjoerg 100724139Sjoerg cnt = 0; 100824139Sjoerg while (*pp++ != NULL) 100924139Sjoerg { 101024139Sjoerg cnt++; 101124139Sjoerg } 101224139Sjoerg return(cnt); 101324139Sjoerg} 101424139Sjoerg 101524139Sjoergstatic void summary_format(str, numbers, names) 101624139Sjoerg 101724139Sjoergchar *str; 101824139Sjoergint *numbers; 101924139Sjoergregister char **names; 102024139Sjoerg 102124139Sjoerg{ 102224139Sjoerg register char *p; 102324139Sjoerg register int num; 102424139Sjoerg register char *thisname; 102524139Sjoerg register int useM = No; 102624139Sjoerg 102724139Sjoerg /* format each number followed by its string */ 102824139Sjoerg p = str; 102924139Sjoerg while ((thisname = *names++) != NULL) 103024139Sjoerg { 103124139Sjoerg /* get the number to format */ 103224139Sjoerg num = *numbers++; 103324139Sjoerg 103424139Sjoerg /* display only non-zero numbers */ 103524139Sjoerg if (num > 0) 103624139Sjoerg { 103724139Sjoerg /* is this number in kilobytes? */ 103824139Sjoerg if (thisname[0] == 'K') 103924139Sjoerg { 104024139Sjoerg /* yes: format it as a memory value */ 104124139Sjoerg p = strecpy(p, format_k(num)); 104224139Sjoerg 104324139Sjoerg /* skip over the K, since it was included by format_k */ 104424139Sjoerg p = strecpy(p, thisname+1); 104524139Sjoerg } 104624139Sjoerg else 104724139Sjoerg { 104824139Sjoerg p = strecpy(p, itoa(num)); 104924139Sjoerg p = strecpy(p, thisname); 105024139Sjoerg } 105124139Sjoerg } 105224139Sjoerg 105324139Sjoerg /* ignore negative numbers, but display corresponding string */ 105424139Sjoerg else if (num < 0) 105524139Sjoerg { 105624139Sjoerg p = strecpy(p, thisname); 105724139Sjoerg } 105824139Sjoerg } 105924139Sjoerg 106024139Sjoerg /* if the last two characters in the string are ", ", delete them */ 106124139Sjoerg p -= 2; 106224139Sjoerg if (p >= str && p[0] == ',' && p[1] == ' ') 106324139Sjoerg { 106424139Sjoerg *p = '\0'; 106524139Sjoerg } 106624139Sjoerg} 106724139Sjoerg 106824139Sjoergstatic void line_update(old, new, start, line) 106924139Sjoerg 107024139Sjoergregister char *old; 107124139Sjoergregister char *new; 107224139Sjoergint start; 107324139Sjoergint line; 107424139Sjoerg 107524139Sjoerg{ 107624139Sjoerg register int ch; 107724139Sjoerg register int diff; 107824139Sjoerg register int newcol = start + 1; 107924139Sjoerg register int lastcol = start; 108024139Sjoerg char cursor_on_line = No; 108124139Sjoerg char *current; 108224139Sjoerg 108324139Sjoerg /* compare the two strings and only rewrite what has changed */ 108424139Sjoerg current = old; 108524139Sjoerg#ifdef DEBUG 108624139Sjoerg fprintf(debug, "line_update, starting at %d\n", start); 108724139Sjoerg fputs(old, debug); 108824139Sjoerg fputc('\n', debug); 108924139Sjoerg fputs(new, debug); 109024139Sjoerg fputs("\n-\n", debug); 109124139Sjoerg#endif 109224139Sjoerg 109324139Sjoerg /* start things off on the right foot */ 109424139Sjoerg /* this is to make sure the invariants get set up right */ 109524139Sjoerg if ((ch = *new++) != *old) 109624139Sjoerg { 109724139Sjoerg if (line - lastline == 1 && start == 0) 109824139Sjoerg { 109924139Sjoerg putchar('\n'); 110024139Sjoerg } 110124139Sjoerg else 110224139Sjoerg { 110324139Sjoerg Move_to(start, line); 110424139Sjoerg } 110524139Sjoerg cursor_on_line = Yes; 110624139Sjoerg putchar(ch); 110724139Sjoerg *old = ch; 110824139Sjoerg lastcol = 1; 110924139Sjoerg } 111024139Sjoerg old++; 111124139Sjoerg 111224139Sjoerg /* 111324139Sjoerg * main loop -- check each character. If the old and new aren't the 111424139Sjoerg * same, then update the display. When the distance from the 111524139Sjoerg * current cursor position to the new change is small enough, 111624139Sjoerg * the characters that belong there are written to move the 111724139Sjoerg * cursor over. 111824139Sjoerg * 111924139Sjoerg * Invariants: 112024139Sjoerg * lastcol is the column where the cursor currently is sitting 112124139Sjoerg * (always one beyond the end of the last mismatch). 112224139Sjoerg */ 112324139Sjoerg do /* yes, a do...while */ 112424139Sjoerg { 112524139Sjoerg if ((ch = *new++) != *old) 112624139Sjoerg { 112724139Sjoerg /* new character is different from old */ 112824139Sjoerg /* make sure the cursor is on top of this character */ 112924139Sjoerg diff = newcol - lastcol; 113024139Sjoerg if (diff > 0) 113124139Sjoerg { 113224139Sjoerg /* some motion is required--figure out which is shorter */ 113324139Sjoerg if (diff < 6 && cursor_on_line) 113424139Sjoerg { 113524139Sjoerg /* overwrite old stuff--get it out of the old buffer */ 113624139Sjoerg printf("%.*s", diff, ¤t[lastcol-start]); 113724139Sjoerg } 113824139Sjoerg else 113924139Sjoerg { 114024139Sjoerg /* use cursor addressing */ 114124139Sjoerg Move_to(newcol, line); 114224139Sjoerg cursor_on_line = Yes; 114324139Sjoerg } 114424139Sjoerg /* remember where the cursor is */ 114524139Sjoerg lastcol = newcol + 1; 114624139Sjoerg } 114724139Sjoerg else 114824139Sjoerg { 114924139Sjoerg /* already there, update position */ 115024139Sjoerg lastcol++; 115124139Sjoerg } 115224139Sjoerg 115324139Sjoerg /* write what we need to */ 115424139Sjoerg if (ch == '\0') 115524139Sjoerg { 115624139Sjoerg /* at the end--terminate with a clear-to-end-of-line */ 115724139Sjoerg (void) clear_eol(strlen(old)); 115824139Sjoerg } 115924139Sjoerg else 116024139Sjoerg { 116124139Sjoerg /* write the new character */ 116224139Sjoerg putchar(ch); 116324139Sjoerg } 116424139Sjoerg /* put the new character in the screen buffer */ 116524139Sjoerg *old = ch; 116624139Sjoerg } 116724139Sjoerg 116824139Sjoerg /* update working column and screen buffer pointer */ 116924139Sjoerg newcol++; 117024139Sjoerg old++; 117124139Sjoerg 117224139Sjoerg } while (ch != '\0'); 117324139Sjoerg 117424139Sjoerg /* zero out the rest of the line buffer -- MUST BE DONE! */ 117524139Sjoerg diff = display_width - newcol; 117624139Sjoerg if (diff > 0) 117724139Sjoerg { 117824139Sjoerg memzero(old, diff); 117924139Sjoerg } 118024139Sjoerg 118124139Sjoerg /* remember where the current line is */ 118224139Sjoerg if (cursor_on_line) 118324139Sjoerg { 118424139Sjoerg lastline = line; 118524139Sjoerg } 118624139Sjoerg} 118724139Sjoerg 118824139Sjoerg/* 118924139Sjoerg * printable(str) - make the string pointed to by "str" into one that is 119024139Sjoerg * printable (i.e.: all ascii), by converting all non-printable 119124139Sjoerg * characters into '?'. Replacements are done in place and a pointer 119224139Sjoerg * to the original buffer is returned. 119324139Sjoerg */ 119424139Sjoerg 119524139Sjoergchar *printable(str) 119624139Sjoerg 119724139Sjoergchar *str; 119824139Sjoerg 119924139Sjoerg{ 120024139Sjoerg register char *ptr; 120124139Sjoerg register char ch; 120224139Sjoerg 120324139Sjoerg ptr = str; 120424139Sjoerg while ((ch = *ptr) != '\0') 120524139Sjoerg { 120624139Sjoerg if (!isprint(ch)) 120724139Sjoerg { 120824139Sjoerg *ptr = '?'; 120924139Sjoerg } 121024139Sjoerg ptr++; 121124139Sjoerg } 121224139Sjoerg return(str); 121324139Sjoerg} 1214