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