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 1089758Sdwmalone * 1189758Sdwmalone * $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 || 3224139Sjoerg strncmp(str, "all", len) == 0 || 3324139Sjoerg strncmp(str, "maximum", len) == 0) 3424139Sjoerg { 3524139Sjoerg return(Infinity); 3624139Sjoerg } 3724139Sjoerg else if (str[0] == '-') 3824139Sjoerg { 3924139Sjoerg 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 6224139Sjoergchar *itoa(val) 6324139Sjoerg 6424139Sjoergregister int val; 6524139Sjoerg 6624139Sjoerg{ 6724139Sjoerg register char *ptr; 6824139Sjoerg static char buffer[16]; /* result is built here */ 6924139Sjoerg /* 16 is sufficient since the largest number 7024139Sjoerg we will ever convert will be 2^32-1, 7124139Sjoerg which is 10 digits. */ 7224139Sjoerg 7324139Sjoerg ptr = buffer + sizeof(buffer); 7424139Sjoerg *--ptr = '\0'; 7524139Sjoerg if (val == 0) 7624139Sjoerg { 7724139Sjoerg *--ptr = '0'; 7824139Sjoerg } 7924139Sjoerg else while (val != 0) 8024139Sjoerg { 8124139Sjoerg *--ptr = (val % 10) + '0'; 8224139Sjoerg val /= 10; 8324139Sjoerg } 8424139Sjoerg return(ptr); 8524139Sjoerg} 8624139Sjoerg 8724139Sjoerg/* 8824139Sjoerg * itoa7(val) - like itoa, except the number is right justified in a 7 8924139Sjoerg * character field. This code is a duplication of itoa instead of 9024139Sjoerg * a front end to a more general routine for efficiency. 9124139Sjoerg */ 9224139Sjoerg 9324139Sjoergchar *itoa7(val) 9424139Sjoerg 9524139Sjoergregister int val; 9624139Sjoerg 9724139Sjoerg{ 9824139Sjoerg register char *ptr; 9924139Sjoerg static char buffer[16]; /* result is built here */ 10024139Sjoerg /* 16 is sufficient since the largest number 10124139Sjoerg we will ever convert will be 2^32-1, 10224139Sjoerg which is 10 digits. */ 10324139Sjoerg 10424139Sjoerg ptr = buffer + sizeof(buffer); 10524139Sjoerg *--ptr = '\0'; 10624139Sjoerg if (val == 0) 10724139Sjoerg { 10824139Sjoerg *--ptr = '0'; 10924139Sjoerg } 11024139Sjoerg else while (val != 0) 11124139Sjoerg { 11224139Sjoerg *--ptr = (val % 10) + '0'; 11324139Sjoerg val /= 10; 11424139Sjoerg } 11524139Sjoerg while (ptr > buffer + sizeof(buffer) - 7) 11624139Sjoerg { 11724139Sjoerg *--ptr = ' '; 11824139Sjoerg } 11924139Sjoerg return(ptr); 12024139Sjoerg} 12124139Sjoerg 12224139Sjoerg/* 12324139Sjoerg * digits(val) - return number of decimal digits in val. Only works for 12424139Sjoerg * positive numbers. If val <= 0 then digits(val) == 0. 12524139Sjoerg */ 12624139Sjoerg 12724139Sjoergint digits(val) 12824139Sjoerg 12924139Sjoergint val; 13024139Sjoerg 13124139Sjoerg{ 13224139Sjoerg register int cnt = 0; 13324139Sjoerg 13424139Sjoerg while (val > 0) 13524139Sjoerg { 13624139Sjoerg cnt++; 13724139Sjoerg val /= 10; 13824139Sjoerg } 13924139Sjoerg return(cnt); 14024139Sjoerg} 14124139Sjoerg 14224139Sjoerg/* 14324139Sjoerg * strecpy(to, from) - copy string "from" into "to" and return a pointer 14424139Sjoerg * to the END of the string "to". 14524139Sjoerg */ 14624139Sjoerg 14724139Sjoergchar *strecpy(to, from) 14824139Sjoerg 14924139Sjoergregister char *to; 15024139Sjoergregister char *from; 15124139Sjoerg 15224139Sjoerg{ 15324139Sjoerg while ((*to++ = *from++) != '\0'); 15424139Sjoerg return(--to); 15524139Sjoerg} 15624139Sjoerg 15724139Sjoerg/* 15824139Sjoerg * string_index(string, array) - find string in array and return index 15924139Sjoerg */ 16024139Sjoerg 16124139Sjoergint string_index(string, array) 16224139Sjoerg 16324139Sjoergchar *string; 16424139Sjoergchar **array; 16524139Sjoerg 16624139Sjoerg{ 16724139Sjoerg register int i = 0; 16824139Sjoerg 16924139Sjoerg while (*array != NULL) 17024139Sjoerg { 17124139Sjoerg if (strcmp(string, *array) == 0) 17224139Sjoerg { 17324139Sjoerg return(i); 17424139Sjoerg } 17524139Sjoerg array++; 17624139Sjoerg i++; 17724139Sjoerg } 17824139Sjoerg return(-1); 17924139Sjoerg} 18024139Sjoerg 18124139Sjoerg/* 18224139Sjoerg * argparse(line, cntp) - parse arguments in string "line", separating them 18324139Sjoerg * out into an argv-like array, and setting *cntp to the number of 18424139Sjoerg * arguments encountered. This is a simple parser that doesn't understand 18524139Sjoerg * squat about quotes. 18624139Sjoerg */ 18724139Sjoerg 18824139Sjoergchar **argparse(line, cntp) 18924139Sjoerg 19024139Sjoergchar *line; 19124139Sjoergint *cntp; 19224139Sjoerg 19324139Sjoerg{ 19424139Sjoerg register char *from; 19524139Sjoerg register char *to; 19624139Sjoerg register int cnt; 19724139Sjoerg register int ch; 19824139Sjoerg int length; 19924139Sjoerg int lastch; 20024139Sjoerg register char **argv; 20124139Sjoerg char **argarray; 20224139Sjoerg char *args; 20324139Sjoerg 20424139Sjoerg /* unfortunately, the only real way to do this is to go thru the 20524139Sjoerg input string twice. */ 20624139Sjoerg 20724139Sjoerg /* step thru the string counting the white space sections */ 20824139Sjoerg from = line; 20924139Sjoerg lastch = cnt = length = 0; 21024139Sjoerg while ((ch = *from++) != '\0') 21124139Sjoerg { 21224139Sjoerg length++; 21324139Sjoerg if (ch == ' ' && lastch != ' ') 21424139Sjoerg { 21524139Sjoerg cnt++; 21624139Sjoerg } 21724139Sjoerg lastch = ch; 21824139Sjoerg } 21924139Sjoerg 22024139Sjoerg /* add three to the count: one for the initial "dummy" argument, 22124139Sjoerg one for the last argument and one for NULL */ 22224139Sjoerg cnt += 3; 22324139Sjoerg 22424139Sjoerg /* allocate a char * array to hold the pointers */ 22524139Sjoerg argarray = (char **)malloc(cnt * sizeof(char *)); 22624139Sjoerg 22724139Sjoerg /* allocate another array to hold the strings themselves */ 22824139Sjoerg args = (char *)malloc(length+2); 22924139Sjoerg 23024139Sjoerg /* initialization for main loop */ 23124139Sjoerg from = line; 23224139Sjoerg to = args; 23324139Sjoerg argv = argarray; 23424139Sjoerg lastch = '\0'; 23524139Sjoerg 23624139Sjoerg /* create a dummy argument to keep getopt happy */ 23724139Sjoerg *argv++ = to; 23824139Sjoerg *to++ = '\0'; 23924139Sjoerg cnt = 2; 24024139Sjoerg 24124139Sjoerg /* now build argv while copying characters */ 24224139Sjoerg *argv++ = to; 24324139Sjoerg while ((ch = *from++) != '\0') 24424139Sjoerg { 24524139Sjoerg if (ch != ' ') 24624139Sjoerg { 24724139Sjoerg if (lastch == ' ') 24824139Sjoerg { 24924139Sjoerg *to++ = '\0'; 25024139Sjoerg *argv++ = to; 25124139Sjoerg cnt++; 25224139Sjoerg } 25324139Sjoerg *to++ = ch; 25424139Sjoerg } 25524139Sjoerg lastch = ch; 25624139Sjoerg } 25724139Sjoerg *to++ = '\0'; 25824139Sjoerg 25924139Sjoerg /* set cntp and return the allocated array */ 26024139Sjoerg *cntp = cnt; 26124139Sjoerg return(argarray); 26224139Sjoerg} 26324139Sjoerg 26424139Sjoerg/* 26524139Sjoerg * percentages(cnt, out, new, old, diffs) - calculate percentage change 26624139Sjoerg * between array "old" and "new", putting the percentages i "out". 26724139Sjoerg * "cnt" is size of each array and "diffs" is used for scratch space. 26824139Sjoerg * The array "old" is updated on each call. 26924139Sjoerg * The routine assumes modulo arithmetic. This function is especially 27024139Sjoerg * useful on BSD mchines for calculating cpu state percentages. 27124139Sjoerg */ 27224139Sjoerg 27324139Sjoerglong percentages(cnt, out, new, old, diffs) 27424139Sjoerg 27524139Sjoergint cnt; 27624139Sjoergint *out; 27724139Sjoergregister long *new; 27824139Sjoergregister long *old; 27924139Sjoerglong *diffs; 28024139Sjoerg 28124139Sjoerg{ 28224139Sjoerg register int i; 28324139Sjoerg register long change; 28424139Sjoerg register long total_change; 28524139Sjoerg register long *dp; 28624139Sjoerg long half_total; 28724139Sjoerg 28824139Sjoerg /* initialization */ 28924139Sjoerg total_change = 0; 29024139Sjoerg dp = diffs; 29124139Sjoerg 29224139Sjoerg /* calculate changes for each state and the overall change */ 29324139Sjoerg for (i = 0; i < cnt; i++) 29424139Sjoerg { 29524139Sjoerg if ((change = *new - *old) < 0) 29624139Sjoerg { 29724139Sjoerg /* this only happens when the counter wraps */ 29824139Sjoerg change = (int) 29924139Sjoerg ((unsigned long)*new-(unsigned long)*old); 30024139Sjoerg } 30124139Sjoerg total_change += (*dp++ = change); 30224139Sjoerg *old++ = *new++; 30324139Sjoerg } 30424139Sjoerg 30524139Sjoerg /* avoid divide by zero potential */ 30624139Sjoerg if (total_change == 0) 30724139Sjoerg { 30824139Sjoerg total_change = 1; 30924139Sjoerg } 31024139Sjoerg 31124139Sjoerg /* calculate percentages based on overall change, rounding up */ 31224139Sjoerg half_total = total_change / 2l; 31324142Sjoerg 31424142Sjoerg /* Do not divide by 0. Causes Floating point exception */ 31524142Sjoerg if(total_change) { 31624142Sjoerg for (i = 0; i < cnt; i++) 31724142Sjoerg { 31824142Sjoerg *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); 31924142Sjoerg } 32024139Sjoerg } 32124139Sjoerg 32224139Sjoerg /* return the total in case the caller wants to use it */ 32324139Sjoerg return(total_change); 32424139Sjoerg} 32524139Sjoerg 32624139Sjoerg/* 32724139Sjoerg * errmsg(errnum) - return an error message string appropriate to the 32824139Sjoerg * error number "errnum". This is a substitute for the System V 32989758Sdwmalone * function "strerror". There appears to be no reliable way to 33089758Sdwmalone * determine if "strerror" exists at compile time, so I make do 33189758Sdwmalone * by providing something of similar functionality. For those 33289758Sdwmalone * systems that have strerror and NOT errlist, define 33389758Sdwmalone * -DHAVE_STRERROR in the module file and this function will 33489758Sdwmalone * use strerror. 33524139Sjoerg */ 33624139Sjoerg 33724139Sjoerg/* externs referenced by errmsg */ 33824139Sjoerg 33989758Sdwmalone#ifndef HAVE_STRERROR 34089758Sdwmalone#ifndef SYS_ERRLIST_DECLARED 34189758Sdwmalone#define SYS_ERRLIST_DECLARED 34289758Sdwmaloneextern char *sys_errlist[]; 34389758Sdwmalone#endif 34489758Sdwmalone 34589758Sdwmaloneextern int sys_nerr; 34689758Sdwmalone#endif 34789758Sdwmalone 34824139Sjoergchar *errmsg(errnum) 34924139Sjoerg 35024139Sjoergint errnum; 35124139Sjoerg 35224139Sjoerg{ 35389758Sdwmalone#ifdef HAVE_STRERROR 35489758Sdwmalone char *msg = strerror(errnum); 35589758Sdwmalone if (msg != NULL) 35689758Sdwmalone { 35789758Sdwmalone return msg; 35889758Sdwmalone } 35989758Sdwmalone#else 36024139Sjoerg if (errnum > 0 && errnum < sys_nerr) 36124139Sjoerg { 36224142Sjoerg return((char *)sys_errlist[errnum]); 36324139Sjoerg } 36489758Sdwmalone#endif 36524139Sjoerg return("No error"); 36624139Sjoerg} 36724139Sjoerg 36824139Sjoerg/* format_time(seconds) - format number of seconds into a suitable 36924139Sjoerg * display that will fit within 6 characters. Note that this 37024139Sjoerg * routine builds its string in a static area. If it needs 37124139Sjoerg * to be called more than once without overwriting previous data, 37224139Sjoerg * then we will need to adopt a technique similar to the 37324139Sjoerg * one used for format_k. 37424139Sjoerg */ 37524139Sjoerg 37624139Sjoerg/* Explanation: 37724139Sjoerg We want to keep the output within 6 characters. For low values we use 37824139Sjoerg the format mm:ss. For values that exceed 999:59, we switch to a format 37924139Sjoerg that displays hours and fractions: hhh.tH. For values that exceed 38024139Sjoerg 999.9, we use hhhh.t and drop the "H" designator. For values that 38124139Sjoerg exceed 9999.9, we use "???". 38224139Sjoerg */ 38324139Sjoerg 38424139Sjoergchar *format_time(seconds) 38524139Sjoerg 38624139Sjoerglong seconds; 38724139Sjoerg 38824139Sjoerg{ 38924139Sjoerg register int value; 39024139Sjoerg register int digit; 39124139Sjoerg register char *ptr; 39224139Sjoerg static char result[10]; 39324139Sjoerg 39424139Sjoerg /* sanity protection */ 39524139Sjoerg if (seconds < 0 || seconds > (99999l * 360l)) 39624139Sjoerg { 39724139Sjoerg strcpy(result, " ???"); 39824139Sjoerg } 39924139Sjoerg else if (seconds >= (1000l * 60l)) 40024139Sjoerg { 40124139Sjoerg /* alternate (slow) method displaying hours and tenths */ 40224139Sjoerg sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l)); 40324139Sjoerg 40424139Sjoerg /* It is possible that the sprintf took more than 6 characters. 40524139Sjoerg If so, then the "H" appears as result[6]. If not, then there 40624139Sjoerg is a \0 in result[6]. Either way, it is safe to step on. 40724139Sjoerg */ 40824139Sjoerg result[6] = '\0'; 40924139Sjoerg } 41024139Sjoerg else 41124139Sjoerg { 41224139Sjoerg /* standard method produces MMM:SS */ 41324139Sjoerg /* we avoid printf as must as possible to make this quick */ 41437453Sbde sprintf(result, "%3ld:%02ld", 41537453Sbde (long)(seconds / 60), (long)(seconds % 60)); 41624139Sjoerg } 41724139Sjoerg return(result); 41824139Sjoerg} 41924139Sjoerg 42024139Sjoerg/* 42124139Sjoerg * format_k(amt) - format a kilobyte memory value, returning a string 42224139Sjoerg * suitable for display. Returns a pointer to a static 42324139Sjoerg * area that changes each call. "amt" is converted to a 42424139Sjoerg * string with a trailing "K". If "amt" is 10000 or greater, 42524139Sjoerg * then it is formatted as megabytes (rounded) with a 42624139Sjoerg * trailing "M". 42724139Sjoerg */ 42824139Sjoerg 42924139Sjoerg/* 43024139Sjoerg * Compromise time. We need to return a string, but we don't want the 43124139Sjoerg * caller to have to worry about freeing a dynamically allocated string. 43224139Sjoerg * Unfortunately, we can't just return a pointer to a static area as one 43324139Sjoerg * of the common uses of this function is in a large call to sprintf where 43424139Sjoerg * it might get invoked several times. Our compromise is to maintain an 43524139Sjoerg * array of strings and cycle thru them with each invocation. We make the 43624139Sjoerg * array large enough to handle the above mentioned case. The constant 43724139Sjoerg * NUM_STRINGS defines the number of strings in this array: we can tolerate 43824139Sjoerg * up to NUM_STRINGS calls before we start overwriting old information. 43924139Sjoerg * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer 44024139Sjoerg * to convert the modulo operation into something quicker. What a hack! 44124139Sjoerg */ 44224139Sjoerg 44324139Sjoerg#define NUM_STRINGS 8 44424139Sjoerg 44524139Sjoergchar *format_k(amt) 44624139Sjoerg 44724139Sjoergint amt; 44824139Sjoerg 44924139Sjoerg{ 45024139Sjoerg static char retarray[NUM_STRINGS][16]; 45124139Sjoerg static int index = 0; 45224139Sjoerg register char *p; 45324139Sjoerg register char *ret; 45424139Sjoerg register char tag = 'K'; 45524139Sjoerg 45624139Sjoerg p = ret = retarray[index]; 45724139Sjoerg index = (index + 1) % NUM_STRINGS; 45824139Sjoerg 45924139Sjoerg if (amt >= 10000) 46024139Sjoerg { 46124139Sjoerg amt = (amt + 512) / 1024; 46224139Sjoerg tag = 'M'; 46324139Sjoerg if (amt >= 10000) 46424139Sjoerg { 46524139Sjoerg amt = (amt + 512) / 1024; 46624139Sjoerg tag = 'G'; 46724139Sjoerg } 46824139Sjoerg } 46924139Sjoerg 47024139Sjoerg p = strecpy(p, itoa(amt)); 47124139Sjoerg *p++ = tag; 47224139Sjoerg *p = '\0'; 47324139Sjoerg 47424139Sjoerg return(ret); 47524139Sjoerg} 47624142Sjoerg 47724142Sjoergchar *format_k2(amt) 47824142Sjoerg 479205119Sbrucecunsigned long long amt; 48024142Sjoerg 48124142Sjoerg{ 48224142Sjoerg static char retarray[NUM_STRINGS][16]; 48324142Sjoerg static int index = 0; 48424142Sjoerg register char *p; 48524142Sjoerg register char *ret; 48624142Sjoerg register char tag = 'K'; 48724142Sjoerg 48824142Sjoerg p = ret = retarray[index]; 48924142Sjoerg index = (index + 1) % NUM_STRINGS; 49024142Sjoerg 49124142Sjoerg if (amt >= 100000) 49224142Sjoerg { 49324142Sjoerg amt = (amt + 512) / 1024; 49424142Sjoerg tag = 'M'; 49524142Sjoerg if (amt >= 100000) 49624142Sjoerg { 49724142Sjoerg amt = (amt + 512) / 1024; 49824142Sjoerg tag = 'G'; 49924142Sjoerg } 50024142Sjoerg } 50124142Sjoerg 502206842Snwhitehorn p = strecpy(p, itoa((int)amt)); 50324142Sjoerg *p++ = tag; 50424142Sjoerg *p = '\0'; 50524142Sjoerg 50624142Sjoerg return(ret); 50724142Sjoerg} 508