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 various handy utilities used by top. 1624139Sjoerg */ 1724139Sjoerg 1824139Sjoerg#include "top.h" 1924139Sjoerg#include "os.h" 2024139Sjoerg 2124139Sjoergint atoiwi(str) 2224139Sjoerg 2324139Sjoergchar *str; 2424139Sjoerg 2524139Sjoerg{ 2624139Sjoerg register int len; 2724139Sjoerg 2824139Sjoerg len = strlen(str); 2924139Sjoerg if (len != 0) 3024139Sjoerg { 3124139Sjoerg if (strncmp(str, "infinity", len) == 0 || 32300395Sngie strncmp(str, "all", len) == 0 || 33300395Sngie strncmp(str, "maximum", len) == 0) 34300395Sngie { 35332948Slidl return(Infinity); 3624139Sjoerg } 37332948Slidl else if (str[0] == '-') 3824139Sjoerg { 39300395Sngie return(Invalid); 4024139Sjoerg } 4124139Sjoerg else 4224139Sjoerg { 4324139Sjoerg return(atoi(str)); 4424139Sjoerg } 4524139Sjoerg } 4624139Sjoerg return(0); 4724139Sjoerg} 4824139Sjoerg 4924139Sjoerg/* 5024139Sjoerg * itoa - convert integer (decimal) to ascii string for positive numbers 5124139Sjoerg * only (we don't bother with negative numbers since we know we 5224139Sjoerg * don't use them). 5324139Sjoerg */ 5424139Sjoerg 5524139Sjoerg /* 5624139Sjoerg * How do we know that 16 will suffice? 5724139Sjoerg * Because the biggest number that we will 5824139Sjoerg * ever convert will be 2^32-1, which is 10 5924139Sjoerg * digits. 6024139Sjoerg */ 6124139Sjoerg_Static_assert(sizeof(int) <= 4, "buffer too small for this sized int"); 6224139Sjoerg 6324139Sjoergchar *itoa(val) 6424139Sjoerg 6524139Sjoergregister int val; 6624139Sjoerg 6724139Sjoerg{ 6824139Sjoerg register char *ptr; 6924139Sjoerg static char buffer[16]; /* result is built here */ 7024139Sjoerg /* 16 is sufficient since the largest number 7124139Sjoerg we will ever convert will be 2^32-1, 7224139Sjoerg which is 10 digits. */ 73237656Sjhb 74318449Sallanjude ptr = buffer + sizeof(buffer); 7524142Sjoerg *--ptr = '\0'; 7624139Sjoerg if (val == 0) 7724139Sjoerg { 7824139Sjoerg *--ptr = '0'; 7924139Sjoerg } 8024142Sjoerg else while (val != 0) 8124139Sjoerg { 8224139Sjoerg *--ptr = (val % 10) + '0'; 8324139Sjoerg val /= 10; 8424139Sjoerg } 8524142Sjoerg return(ptr); 8624139Sjoerg} 87175420Speter 8824139Sjoerg/* 8924139Sjoerg * itoa7(val) - like itoa, except the number is right justified in a 7 90175420Speter * character field. This code is a duplication of itoa instead of 9124139Sjoerg * a front end to a more general routine for efficiency. 9224139Sjoerg */ 9324139Sjoerg 9424139Sjoergchar *itoa7(val) 9524139Sjoerg 9624139Sjoergregister int val; 9724139Sjoerg 98175420Speter{ 99175420Speter register char *ptr; 100175420Speter static char buffer[16]; /* result is built here */ 101175420Speter /* 16 is sufficient since the largest number 102175420Speter we will ever convert will be 2^32-1, 103175420Speter which is 10 digits. */ 104175420Speter 105175420Speter ptr = buffer + sizeof(buffer); 106175420Speter *--ptr = '\0'; 107175420Speter if (val == 0) 108175420Speter { 109237656Sjhb *--ptr = '0'; 110237656Sjhb } 111318449Sallanjude else while (val != 0) 112318449Sallanjude { 113175420Speter *--ptr = (val % 10) + '0'; 114175420Speter val /= 10; 115175420Speter } 116175420Speter while (ptr > buffer + sizeof(buffer) - 7) 117175420Speter { 118175420Speter *--ptr = ' '; 119175420Speter } 120175420Speter return(ptr); 121175420Speter} 122175420Speter 123175420Speter/* 124175420Speter * digits(val) - return number of decimal digits in val. Only works for 12524139Sjoerg * positive numbers. If val <= 0 then digits(val) == 0. 12624139Sjoerg */ 12724139Sjoerg 12824139Sjoergint digits(val) 12924139Sjoerg 13024139Sjoergint val; 13124139Sjoerg 13224139Sjoerg{ 13324139Sjoerg register int cnt = 0; 13424139Sjoerg 13524139Sjoerg while (val > 0) 13624139Sjoerg { 13724139Sjoerg cnt++; 13824139Sjoerg val /= 10; 13924139Sjoerg } 140101692Sdwmalone return(cnt); 141101692Sdwmalone} 14224139Sjoerg 14324139Sjoerg/* 14424139Sjoerg * strecpy(to, from) - copy string "from" into "to" and return a pointer 14524139Sjoerg * to the END of the string "to". 14624139Sjoerg */ 14724139Sjoerg 14824139Sjoergchar *strecpy(to, from) 14924139Sjoerg 15024139Sjoergregister char *to; 15124139Sjoergregister char *from; 15224139Sjoerg 15324139Sjoerg{ 15424139Sjoerg while ((*to++ = *from++) != '\0'); 15524139Sjoerg return(--to); 15624139Sjoerg} 15724139Sjoerg 15824139Sjoerg/* 15924139Sjoerg * string_index(string, array) - find string in array and return index 16024139Sjoerg */ 16124139Sjoerg 16224139Sjoergint string_index(string, array) 16324139Sjoerg 164223936Sjhbchar *string; 16524139Sjoergchar **array; 16624139Sjoerg 16724139Sjoerg{ 16824139Sjoerg register int i = 0; 169224205Sjhb 17024139Sjoerg while (*array != NULL) 17124139Sjoerg { 172223936Sjhb if (strcmp(string, *array) == 0) 17324139Sjoerg { 17424139Sjoerg return(i); 175224205Sjhb } 176224205Sjhb array++; 177224205Sjhb i++; 178224205Sjhb } 179175420Speter return(-1); 180175420Speter} 181175420Speter 182175420Speter/* 183175420Speter * argparse(line, cntp) - parse arguments in string "line", separating them 18424139Sjoerg * out into an argv-like array, and setting *cntp to the number of 185224205Sjhb * arguments encountered. This is a simple parser that doesn't understand 186224205Sjhb * squat about quotes. 187224205Sjhb */ 188224205Sjhb 189224205Sjhbchar **argparse(line, cntp) 190224205Sjhb 191224205Sjhbchar *line; 192224205Sjhbint *cntp; 193223936Sjhb 194223936Sjhb{ 195223936Sjhb register char *from; 196223936Sjhb register char *to; 197223936Sjhb register int cnt; 198223936Sjhb register int ch; 199223936Sjhb int length; 200223936Sjhb int lastch; 201223936Sjhb register char **argv; 202223936Sjhb char **argarray; 203223936Sjhb char *args; 204223936Sjhb 205223936Sjhb /* unfortunately, the only real way to do this is to go thru the 206223936Sjhb input string twice. */ 207223936Sjhb 20824139Sjoerg /* step thru the string counting the white space sections */ 20924139Sjoerg from = line; 21024139Sjoerg lastch = cnt = length = 0; 21124139Sjoerg while ((ch = *from++) != '\0') 21224139Sjoerg { 21324139Sjoerg length++; 21424139Sjoerg if (ch == ' ' && lastch != ' ') 21524139Sjoerg { 21624139Sjoerg cnt++; 21724142Sjoerg } 21824142Sjoerg lastch = ch; 21924142Sjoerg } 22024142Sjoerg 22124139Sjoerg /* add three to the count: one for the initial "dummy" argument, 222224205Sjhb one for the last argument and one for NULL */ 22324139Sjoerg cnt += 3; 22424139Sjoerg 22524139Sjoerg /* allocate a char * array to hold the pointers */ 22624139Sjoerg argarray = (char **)malloc(cnt * sizeof(char *)); 22724139Sjoerg 22824139Sjoerg /* allocate another array to hold the strings themselves */ 229237656Sjhb args = (char *)malloc(length+2); 230318449Sallanjude 231237656Sjhb /* initialization for main loop */ 23224139Sjoerg from = line; 23324139Sjoerg to = args; 23424139Sjoerg argv = argarray; 23524139Sjoerg lastch = '\0'; 23624139Sjoerg 23724139Sjoerg /* create a dummy argument to keep getopt happy */ 23889758Sdwmalone *argv++ = to; 23924139Sjoerg *to++ = '\0'; 24024139Sjoerg cnt = 2; 24124139Sjoerg 24224139Sjoerg /* now build argv while copying characters */ 24324139Sjoerg *argv++ = to; 24424139Sjoerg while ((ch = *from++) != '\0') 24524139Sjoerg { 24624139Sjoerg if (ch != ' ') 24724139Sjoerg { 24824139Sjoerg if (lastch == ' ') 24924139Sjoerg { 250300395Sngie *to++ = '\0'; 25124139Sjoerg *argv++ = to; 25224139Sjoerg cnt++; 25324139Sjoerg } 25424139Sjoerg *to++ = ch; 25524139Sjoerg } 25624139Sjoerg lastch = ch; 25724139Sjoerg } 25824139Sjoerg *to++ = '\0'; 25924139Sjoerg 260332948Slidl /* set cntp and return the allocated array */ 26124139Sjoerg *cntp = cnt; 26224139Sjoerg return(argarray); 26324139Sjoerg} 26424139Sjoerg 26524139Sjoerg/* 26624139Sjoerg * percentages(cnt, out, new, old, diffs) - calculate percentage change 26724139Sjoerg * between array "old" and "new", putting the percentages i "out". 26824139Sjoerg * "cnt" is size of each array and "diffs" is used for scratch space. 26924139Sjoerg * The array "old" is updated on each call. 27024139Sjoerg * The routine assumes modulo arithmetic. This function is especially 27124139Sjoerg * useful on BSD mchines for calculating cpu state percentages. 27224139Sjoerg */ 27324139Sjoerg 27424139Sjoerglong percentages(cnt, out, new, old, diffs) 27524139Sjoerg 27624139Sjoergint cnt; 27724139Sjoergint *out; 27824139Sjoergregister long *new; 279300395Sngieregister long *old; 28024139Sjoerglong *diffs; 28124139Sjoerg 28224139Sjoerg{ 28324139Sjoerg register int i; 28424139Sjoerg register long change; 28524139Sjoerg register long total_change; 28624139Sjoerg register long *dp; 28724139Sjoerg long half_total; 28824139Sjoerg 28924139Sjoerg /* initialization */ 29024139Sjoerg total_change = 0; 29124139Sjoerg dp = diffs; 29224139Sjoerg 29324139Sjoerg /* calculate changes for each state and the overall change */ 29424139Sjoerg for (i = 0; i < cnt; i++) 29524139Sjoerg { 29624139Sjoerg if ((change = *new - *old) < 0) 29724139Sjoerg { 29824139Sjoerg /* this only happens when the counter wraps */ 29924139Sjoerg change = (int) 30024139Sjoerg ((unsigned long)*new-(unsigned long)*old); 30124139Sjoerg } 30224139Sjoerg total_change += (*dp++ = change); 30324139Sjoerg *old++ = *new++; 30424139Sjoerg } 30524139Sjoerg 30624139Sjoerg /* avoid divide by zero potential */ 30724139Sjoerg if (total_change == 0) 30824139Sjoerg { 30924139Sjoerg total_change = 1; 31024139Sjoerg } 31124139Sjoerg 31224139Sjoerg /* calculate percentages based on overall change, rounding up */ 31324139Sjoerg half_total = total_change / 2l; 31424139Sjoerg 31524139Sjoerg /* Do not divide by 0. Causes Floating point exception */ 31624139Sjoerg if(total_change) { 31724139Sjoerg for (i = 0; i < cnt; i++) 31824139Sjoerg { 319300395Sngie *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); 32024139Sjoerg } 32124139Sjoerg } 32224139Sjoerg 32324139Sjoerg /* return the total in case the caller wants to use it */ 32424139Sjoerg return(total_change); 32524139Sjoerg} 32624139Sjoerg 32724139Sjoerg/* 32824139Sjoerg * errmsg(errnum) - return an error message string appropriate to the 32924139Sjoerg * error number "errnum". This is a substitute for the System V 33024139Sjoerg * function "strerror". There appears to be no reliable way to 33124139Sjoerg * determine if "strerror" exists at compile time, so I make do 33224139Sjoerg * by providing something of similar functionality. For those 33324139Sjoerg * systems that have strerror and NOT errlist, define 33424139Sjoerg * -DHAVE_STRERROR in the module file and this function will 33524139Sjoerg * use strerror. 33624139Sjoerg */ 33724139Sjoerg 33824139Sjoerg/* externs referenced by errmsg */ 33924139Sjoerg 34024139Sjoerg#ifndef HAVE_STRERROR 34124139Sjoerg#ifndef SYS_ERRLIST_DECLARED 34224139Sjoerg#define SYS_ERRLIST_DECLARED 34324139Sjoergextern char *sys_errlist[]; 34424139Sjoerg#endif 34524139Sjoerg 34624139Sjoergextern int sys_nerr; 34724139Sjoerg#endif 34824139Sjoerg 34924139Sjoergchar *errmsg(errnum) 35024139Sjoerg 35124139Sjoergint errnum; 35224139Sjoerg 35324139Sjoerg{ 35424139Sjoerg#ifdef HAVE_STRERROR 35524139Sjoerg char *msg = strerror(errnum); 35689758Sdwmalone if (msg != NULL) 35724139Sjoerg { 35824139Sjoerg return msg; 35924139Sjoerg } 36024139Sjoerg#else 36124139Sjoerg if (errnum > 0 && errnum < sys_nerr) 36224139Sjoerg { 36324139Sjoerg return((char *)sys_errlist[errnum]); 36424139Sjoerg } 365300395Sngie#endif 36624139Sjoerg return("No error"); 36724139Sjoerg} 36824139Sjoerg 36924139Sjoerg/* format_time(seconds) - format number of seconds into a suitable 37024139Sjoerg * display that will fit within 6 characters. Note that this 37124139Sjoerg * routine builds its string in a static area. If it needs 37224139Sjoerg * to be called more than once without overwriting previous data, 37324139Sjoerg * then we will need to adopt a technique similar to the 37424139Sjoerg * one used for format_k. 37524139Sjoerg */ 37624139Sjoerg 37724139Sjoerg/* Explanation: 37824139Sjoerg We want to keep the output within 6 characters. For low values we use 37924139Sjoerg the format mm:ss. For values that exceed 999:59, we switch to a format 38024139Sjoerg that displays hours and fractions: hhh.tH. For values that exceed 38124139Sjoerg 999.9, we use hhhh.t and drop the "H" designator. For values that 38224139Sjoerg exceed 9999.9, we use "???". 38324139Sjoerg */ 38424139Sjoerg 38524139Sjoergchar *format_time(seconds) 38624139Sjoerg 38724139Sjoerglong seconds; 38824139Sjoerg 38924139Sjoerg{ 39024139Sjoerg register int value; 39124139Sjoerg register int digit; 39224139Sjoerg register char *ptr; 393300395Sngie static char result[10]; 39424139Sjoerg 39524139Sjoerg /* sanity protection */ 39624139Sjoerg if (seconds < 0 || seconds > (99999l * 360l)) 39724139Sjoerg { 39824139Sjoerg strcpy(result, " ???"); 39924139Sjoerg } 40089758Sdwmalone else if (seconds >= (1000l * 60l)) 40124139Sjoerg { 40224139Sjoerg /* alternate (slow) method displaying hours and tenths */ 40324139Sjoerg sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l)); 40424139Sjoerg 40524139Sjoerg /* It is possible that the sprintf took more than 6 characters. 40624139Sjoerg If so, then the "H" appears as result[6]. If not, then there 40724139Sjoerg is a \0 in result[6]. Either way, it is safe to step on. 40824139Sjoerg */ 40924139Sjoerg result[6] = '\0'; 41024139Sjoerg } 41124139Sjoerg else 41224139Sjoerg { 41324139Sjoerg /* standard method produces MMM:SS */ 41424139Sjoerg /* we avoid printf as must as possible to make this quick */ 41524139Sjoerg sprintf(result, "%3ld:%02ld", 41624139Sjoerg (long)(seconds / 60), (long)(seconds % 60)); 41724139Sjoerg } 41824139Sjoerg return(result); 41924139Sjoerg} 42024139Sjoerg 42124139Sjoerg/* 42224139Sjoerg * format_k(amt) - format a kilobyte memory value, returning a string 42324139Sjoerg * suitable for display. Returns a pointer to a static 42424139Sjoerg * area that changes each call. "amt" is converted to a 42524139Sjoerg * string with a trailing "K". If "amt" is 10000 or greater, 42624139Sjoerg * then it is formatted as megabytes (rounded) with a 42724139Sjoerg * trailing "M". 42824139Sjoerg */ 42924139Sjoerg 43024139Sjoerg/* 43124139Sjoerg * Compromise time. We need to return a string, but we don't want the 43224139Sjoerg * caller to have to worry about freeing a dynamically allocated string. 43324139Sjoerg * Unfortunately, we can't just return a pointer to a static area as one 43424139Sjoerg * of the common uses of this function is in a large call to sprintf where 43524139Sjoerg * it might get invoked several times. Our compromise is to maintain an 43624139Sjoerg * array of strings and cycle thru them with each invocation. We make the 43724139Sjoerg * array large enough to handle the above mentioned case. The constant 43824139Sjoerg * NUM_STRINGS defines the number of strings in this array: we can tolerate 43924139Sjoerg * up to NUM_STRINGS calls before we start overwriting old information. 44024139Sjoerg * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer 44124139Sjoerg * to convert the modulo operation into something quicker. What a hack! 442175420Speter */ 44324139Sjoerg 44424139Sjoerg#define NUM_STRINGS 8 44524139Sjoerg 44624139Sjoergchar *format_k(amt) 44724139Sjoerg 44824139Sjoergint amt; 44924139Sjoerg 45024139Sjoerg{ 45124139Sjoerg static char retarray[NUM_STRINGS][16]; 45224139Sjoerg static int index = 0; 45324139Sjoerg register char *p; 45424139Sjoerg register char *ret; 45524139Sjoerg register char tag = 'K'; 45624139Sjoerg 45724139Sjoerg p = ret = retarray[index]; 45824139Sjoerg index = (index + 1) % NUM_STRINGS; 45924139Sjoerg 46024139Sjoerg if (amt >= 10000) 46124139Sjoerg { 46224139Sjoerg amt = (amt + 512) / 1024; 46324139Sjoerg tag = 'M'; 46424139Sjoerg if (amt >= 10000) 46524139Sjoerg { 46624139Sjoerg amt = (amt + 512) / 1024; 46724139Sjoerg tag = 'G'; 46824139Sjoerg } 46924139Sjoerg } 47024139Sjoerg 47124139Sjoerg p = strecpy(p, itoa(amt)); 47224139Sjoerg *p++ = tag; 47324139Sjoerg *p = '\0'; 474175420Speter 47524139Sjoerg return(ret); 476300395Sngie} 47724139Sjoerg 47824139Sjoergchar *format_k2(amt) 479300395Sngie 48024139Sjoergunsigned long long amt; 48124139Sjoerg 48224139Sjoerg{ 48324139Sjoerg static char retarray[NUM_STRINGS][16]; 484175420Speter static int index = 0; 48524139Sjoerg register char *p; 486175420Speter register char *ret; 48724139Sjoerg register char tag = 'K'; 488175420Speter 489175420Speter p = ret = retarray[index]; 490175420Speter index = (index + 1) % NUM_STRINGS; 49124139Sjoerg 492175420Speter if (amt >= 100000) 493175420Speter { 494218171Sjhb amt = (amt + 512) / 1024; 495218171Sjhb tag = 'M'; 496218171Sjhb if (amt >= 100000) 497218171Sjhb { 498218171Sjhb amt = (amt + 512) / 1024; 49924139Sjoerg tag = 'G'; 50024139Sjoerg } 50124139Sjoerg } 50224139Sjoerg 50324139Sjoerg p = strecpy(p, itoa((int)amt)); 50424139Sjoerg *p++ = tag; 50524139Sjoerg *p = '\0'; 50624139Sjoerg 50724139Sjoerg return(ret); 50824139Sjoerg} 50924139Sjoerg