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