xref: /netbsd-src/external/bsd/top/dist/utils.c (revision 9ded70a5ef6bdad60231e03e3b27fe20e81315e4)
110dd2532Schristos /*
210dd2532Schristos  * Copyright (c) 1984 through 2008, William LeFebvre
310dd2532Schristos  * All rights reserved.
410dd2532Schristos  *
510dd2532Schristos  * Redistribution and use in source and binary forms, with or without
610dd2532Schristos  * modification, are permitted provided that the following conditions are met:
710dd2532Schristos  *
810dd2532Schristos  *     * Redistributions of source code must retain the above copyright
910dd2532Schristos  * notice, this list of conditions and the following disclaimer.
1010dd2532Schristos  *
1110dd2532Schristos  *     * Redistributions in binary form must reproduce the above
1210dd2532Schristos  * copyright notice, this list of conditions and the following disclaimer
1310dd2532Schristos  * in the documentation and/or other materials provided with the
1410dd2532Schristos  * distribution.
1510dd2532Schristos  *
1610dd2532Schristos  *     * Neither the name of William LeFebvre nor the names of other
1710dd2532Schristos  * contributors may be used to endorse or promote products derived from
1810dd2532Schristos  * this software without specific prior written permission.
1910dd2532Schristos  *
2010dd2532Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2110dd2532Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2210dd2532Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2310dd2532Schristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2410dd2532Schristos  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2510dd2532Schristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2610dd2532Schristos  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2710dd2532Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2810dd2532Schristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2910dd2532Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3010dd2532Schristos  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3110dd2532Schristos  */
3210dd2532Schristos 
3310dd2532Schristos /*
3410dd2532Schristos  *  Top users/processes display for Unix
3510dd2532Schristos  *  Version 3
3610dd2532Schristos  */
3710dd2532Schristos 
3810dd2532Schristos /*
3910dd2532Schristos  *  This file contains various handy utilities used by top.
4010dd2532Schristos  */
4110dd2532Schristos 
4210dd2532Schristos #include "os.h"
4310dd2532Schristos #include <ctype.h>
440ca1e3e0Sdholland #include <math.h>
4510dd2532Schristos #ifdef HAVE_STDARG_H
4610dd2532Schristos #include <stdarg.h>
4710dd2532Schristos #else
4810dd2532Schristos #undef DEBUG
4910dd2532Schristos #endif
5010dd2532Schristos #include "top.h"
5110dd2532Schristos #include "utils.h"
5210dd2532Schristos 
5310dd2532Schristos static int
alldigits(char * s)5410dd2532Schristos alldigits(char *s)
5510dd2532Schristos 
5610dd2532Schristos {
5710dd2532Schristos     int ch;
5810dd2532Schristos 
5910dd2532Schristos     while ((ch = *s++) != '\0')
6010dd2532Schristos     {
6110dd2532Schristos 	if (!isdigit(ch))
6210dd2532Schristos 	{
6310dd2532Schristos 	    return 0;
6410dd2532Schristos 	}
6510dd2532Schristos     }
6610dd2532Schristos     return 1;
6710dd2532Schristos }
6810dd2532Schristos 
6910dd2532Schristos int
atoiwi(char * str)7010dd2532Schristos atoiwi(char *str)
7110dd2532Schristos 
7210dd2532Schristos {
7310dd2532Schristos     register int len;
7410dd2532Schristos 
7510dd2532Schristos     len = strlen(str);
7610dd2532Schristos     if (len != 0)
7710dd2532Schristos     {
7810dd2532Schristos 	if (strncmp(str, "infinity", len) == 0 ||
7910dd2532Schristos 	    strncmp(str, "all",      len) == 0 ||
8010dd2532Schristos 	    strncmp(str, "maximum",  len) == 0)
8110dd2532Schristos 	{
8210dd2532Schristos 	    return(Infinity);
8310dd2532Schristos 	}
8410dd2532Schristos 	else if (alldigits(str))
8510dd2532Schristos 	{
8610dd2532Schristos 	    return(atoi(str));
8710dd2532Schristos 	}
8810dd2532Schristos 	else
8910dd2532Schristos 	{
9010dd2532Schristos 	    return(Invalid);
9110dd2532Schristos 	}
9210dd2532Schristos     }
9310dd2532Schristos     return(0);
9410dd2532Schristos }
9510dd2532Schristos 
9610dd2532Schristos /*
9710dd2532Schristos  *  itoa - convert integer (decimal) to ascii string for positive numbers
9810dd2532Schristos  *  	   only (we don't bother with negative numbers since we know we
9910dd2532Schristos  *	   don't use them).
10010dd2532Schristos  */
10110dd2532Schristos 
10210dd2532Schristos 				/*
10310dd2532Schristos 				 * How do we know that 16 will suffice?
10410dd2532Schristos 				 * Because the biggest number that we will
10510dd2532Schristos 				 * ever convert will be 2^32-1, which is 10
10610dd2532Schristos 				 * digits.
10710dd2532Schristos 				 */
10810dd2532Schristos 
10910dd2532Schristos char *
itoa(int val)11010dd2532Schristos itoa(int val)
11110dd2532Schristos 
11210dd2532Schristos {
11310dd2532Schristos     register char *ptr;
11410dd2532Schristos     static char buffer[16];	/* result is built here */
11510dd2532Schristos     				/* 16 is sufficient since the largest number
11610dd2532Schristos 				   we will ever convert will be 2^32-1,
11710dd2532Schristos 				   which is 10 digits. */
11810dd2532Schristos 
11910dd2532Schristos     ptr = buffer + sizeof(buffer);
12010dd2532Schristos     *--ptr = '\0';
12110dd2532Schristos     if (val == 0)
12210dd2532Schristos     {
12310dd2532Schristos 	*--ptr = '0';
12410dd2532Schristos     }
12510dd2532Schristos     else while (val != 0)
12610dd2532Schristos     {
12710dd2532Schristos 	*--ptr = (val % 10) + '0';
12810dd2532Schristos 	val /= 10;
12910dd2532Schristos     }
13010dd2532Schristos     return(ptr);
13110dd2532Schristos }
13210dd2532Schristos 
13310dd2532Schristos /*
13410dd2532Schristos  *  itoa7(val) - like itoa, except the number is right justified in a 7
13510dd2532Schristos  *	character field.  This code is a duplication of itoa instead of
13610dd2532Schristos  *	a front end to a more general routine for efficiency.
13710dd2532Schristos  */
13810dd2532Schristos 
13910dd2532Schristos char *
itoa_w(int val,int w)14010dd2532Schristos itoa_w(int val, int w)
14110dd2532Schristos 
14210dd2532Schristos {
14310dd2532Schristos     char *ptr;
14410dd2532Schristos     char *eptr;
14510dd2532Schristos     static char buffer[16];	/* result is built here */
14610dd2532Schristos     				/* 16 is sufficient since the largest number
14710dd2532Schristos 				   we will ever convert will be 2^32-1,
14810dd2532Schristos 				   which is 10 digits. */
14910dd2532Schristos 
15010dd2532Schristos     if (w > 15)
15110dd2532Schristos     {
15210dd2532Schristos 	w = 15;
15310dd2532Schristos     }
15410dd2532Schristos     eptr = ptr = buffer + sizeof(buffer);
15510dd2532Schristos     *--ptr = '\0';
15610dd2532Schristos     if (val == 0)
15710dd2532Schristos     {
15810dd2532Schristos 	*--ptr = '0';
15910dd2532Schristos     }
16010dd2532Schristos     else while (val != 0)
16110dd2532Schristos     {
16210dd2532Schristos 	*--ptr = (val % 10) + '0';
16310dd2532Schristos 	val /= 10;
16410dd2532Schristos     }
16510dd2532Schristos     while (ptr >= eptr - w)
16610dd2532Schristos     {
16710dd2532Schristos 	*--ptr = ' ';
16810dd2532Schristos     }
16910dd2532Schristos     return(ptr);
17010dd2532Schristos }
17110dd2532Schristos 
17210dd2532Schristos char *
itoa7(int val)17310dd2532Schristos itoa7(int val)
17410dd2532Schristos 
17510dd2532Schristos {
17610dd2532Schristos     return itoa_w(val, 7);
17710dd2532Schristos }
17810dd2532Schristos 
17910dd2532Schristos /*
18010dd2532Schristos  *  digits(val) - return number of decimal digits in val.  Only works for
18110dd2532Schristos  *	positive numbers.  If val < 0 then digits(val) == 0, but
18210dd2532Schristos  *      digits(0) == 1.
18310dd2532Schristos  */
18410dd2532Schristos 
18510dd2532Schristos int
digits(int val)18610dd2532Schristos digits(int val)
18710dd2532Schristos 
18810dd2532Schristos {
18910dd2532Schristos     register int cnt = 0;
19010dd2532Schristos 
19110dd2532Schristos     if (val == 0)
19210dd2532Schristos     {
19310dd2532Schristos 	return 1;
19410dd2532Schristos     }
19510dd2532Schristos     while (val > 0)
19610dd2532Schristos     {
19710dd2532Schristos 	cnt++;
19810dd2532Schristos 	val /= 10;
19910dd2532Schristos     }
20010dd2532Schristos     return(cnt);
20110dd2532Schristos }
20210dd2532Schristos 
20310dd2532Schristos /*
20410dd2532Schristos  *  printable(char *str) - make the string pointed to by "str" into one that is
20510dd2532Schristos  *	printable (i.e.: all ascii), by converting all non-printable
20610dd2532Schristos  *	characters into '?'.  Replacements are done in place and a pointer
20710dd2532Schristos  *	to the original buffer is returned.
20810dd2532Schristos  */
20910dd2532Schristos 
21010dd2532Schristos char *
printable(char * str)21110dd2532Schristos printable(char *str)
21210dd2532Schristos 
21310dd2532Schristos {
21410dd2532Schristos     register char *ptr;
21510dd2532Schristos     register int ch;
21610dd2532Schristos 
21710dd2532Schristos     ptr = str;
21810dd2532Schristos     while ((ch = *ptr) != '\0')
21910dd2532Schristos     {
22010dd2532Schristos 	if (!isprint(ch))
22110dd2532Schristos 	{
22210dd2532Schristos 	    *ptr = '?';
22310dd2532Schristos 	}
22410dd2532Schristos 	ptr++;
22510dd2532Schristos     }
22610dd2532Schristos     return(str);
22710dd2532Schristos }
22810dd2532Schristos 
22910dd2532Schristos /*
23010dd2532Schristos  *  strcpyend(to, from) - copy string "from" into "to" and return a pointer
23110dd2532Schristos  *	to the END of the string "to".
23210dd2532Schristos  */
23310dd2532Schristos 
23410dd2532Schristos char *
strcpyend(char * to,const char * from)235213e7ef1Schristos strcpyend(char *to, const char *from)
23610dd2532Schristos 
23710dd2532Schristos {
23810dd2532Schristos     while ((*to++ = *from++) != '\0');
23910dd2532Schristos     return(--to);
24010dd2532Schristos }
24110dd2532Schristos 
24210dd2532Schristos /*
24310dd2532Schristos  * char *
244213e7ef1Schristos  * homogenize(const char *str)
24510dd2532Schristos  *
24610dd2532Schristos  * Remove unwanted characters from "str" and make everything lower case.
24710dd2532Schristos  * Newly allocated string is returned: the original is not altered.
24810dd2532Schristos  */
24910dd2532Schristos 
homogenize(const char * str)250213e7ef1Schristos char *homogenize(const char *str)
25110dd2532Schristos 
25210dd2532Schristos {
25310dd2532Schristos     char *ans;
25410dd2532Schristos     char *fr;
25510dd2532Schristos     char *to;
25610dd2532Schristos     int ch;
25710dd2532Schristos 
25856a682bfSchristos     to = fr = ans = estrdup(str);
25910dd2532Schristos     while ((ch = *fr++) != '\0')
26010dd2532Schristos     {
26110dd2532Schristos 	if (isalnum(ch))
26210dd2532Schristos 	{
26310dd2532Schristos 	    *to++ = tolower(ch);
26410dd2532Schristos 	}
26510dd2532Schristos     }
26610dd2532Schristos 
26710dd2532Schristos     *to = '\0';
26810dd2532Schristos     return ans;
26910dd2532Schristos }
27010dd2532Schristos 
27110dd2532Schristos /*
27210dd2532Schristos  * string_index(string, array) - find string in array and return index
27310dd2532Schristos  */
27410dd2532Schristos 
27510dd2532Schristos int
string_index(const char * string,const char ** array)276213e7ef1Schristos string_index(const char *string, const char **array)
27710dd2532Schristos 
27810dd2532Schristos {
27910dd2532Schristos     register int i = 0;
28010dd2532Schristos 
28110dd2532Schristos     while (*array != NULL)
28210dd2532Schristos     {
28310dd2532Schristos 	if (strcmp(string, *array) == 0)
28410dd2532Schristos 	{
28510dd2532Schristos 	    return(i);
28610dd2532Schristos 	}
28710dd2532Schristos 	array++;
28810dd2532Schristos 	i++;
28910dd2532Schristos     }
29010dd2532Schristos     return(-1);
29110dd2532Schristos }
29210dd2532Schristos 
29310dd2532Schristos /*
29410dd2532Schristos  * char *string_list(char **strings)
29510dd2532Schristos  *
29610dd2532Schristos  * Create a comma-separated list of the strings in the NULL-terminated
29710dd2532Schristos  * "strings".  Returned string is malloc-ed and should be freed when the
29810dd2532Schristos  * caller is done.  Note that this is not an efficient function.
29910dd2532Schristos  */
30010dd2532Schristos 
string_list(const char ** strings)301213e7ef1Schristos char *string_list(const char **strings)
30210dd2532Schristos 
30310dd2532Schristos {
30410dd2532Schristos     int cnt = 0;
305213e7ef1Schristos     const char **pp;
306213e7ef1Schristos     const char *p;
30710dd2532Schristos     char *result = NULL;
30810dd2532Schristos     char *resp = NULL;
30910dd2532Schristos 
31010dd2532Schristos     pp = strings;
31110dd2532Schristos     while ((p = *pp++) != NULL)
31210dd2532Schristos     {
31310dd2532Schristos 	cnt += strlen(p) + 2;
31410dd2532Schristos     }
31510dd2532Schristos 
31610dd2532Schristos     if (cnt > 0)
31710dd2532Schristos     {
31856a682bfSchristos 	resp = result = emalloc(cnt);
31910dd2532Schristos 	pp = strings;
32010dd2532Schristos 	while ((p = *pp++) != NULL)
32110dd2532Schristos 	{
32210dd2532Schristos 	    resp = strcpyend(resp, p);
32310dd2532Schristos 	    if (*pp != NULL)
32410dd2532Schristos 	    {
32510dd2532Schristos 		resp = strcpyend(resp, ", ");
32610dd2532Schristos 	    }
32710dd2532Schristos 	}
32810dd2532Schristos     }
32910dd2532Schristos 
33010dd2532Schristos     return result;
33110dd2532Schristos }
33210dd2532Schristos 
33310dd2532Schristos /*
33410dd2532Schristos  * argparse(line, cntp) - parse arguments in string "line", separating them
33510dd2532Schristos  *	out into an argv-like array, and setting *cntp to the number of
33610dd2532Schristos  *	arguments encountered.  This is a simple parser that doesn't understand
33710dd2532Schristos  *	squat about quotes.
33810dd2532Schristos  */
33910dd2532Schristos 
34010dd2532Schristos char **
argparse(char * line,int * cntp)34110dd2532Schristos argparse(char *line, int *cntp)
34210dd2532Schristos 
34310dd2532Schristos {
34410dd2532Schristos     register char *from;
34510dd2532Schristos     register char *to;
34610dd2532Schristos     register int cnt;
34710dd2532Schristos     register int ch;
34810dd2532Schristos     int length;
34910dd2532Schristos     int lastch;
35010dd2532Schristos     register char **argv;
35110dd2532Schristos     char **argarray;
35210dd2532Schristos     char *args;
35310dd2532Schristos 
35410dd2532Schristos     /* unfortunately, the only real way to do this is to go thru the
35510dd2532Schristos        input string twice. */
35610dd2532Schristos 
35710dd2532Schristos     /* step thru the string counting the white space sections */
35810dd2532Schristos     from = line;
35910dd2532Schristos     lastch = cnt = length = 0;
36010dd2532Schristos     while ((ch = *from++) != '\0')
36110dd2532Schristos     {
36210dd2532Schristos 	length++;
36310dd2532Schristos 	if (ch == ' ' && lastch != ' ')
36410dd2532Schristos 	{
36510dd2532Schristos 	    cnt++;
36610dd2532Schristos 	}
36710dd2532Schristos 	lastch = ch;
36810dd2532Schristos     }
36910dd2532Schristos 
37010dd2532Schristos     /* add three to the count:  one for the initial "dummy" argument,
37110dd2532Schristos        one for the last argument and one for NULL */
37210dd2532Schristos     cnt += 3;
37310dd2532Schristos 
37410dd2532Schristos     /* allocate a char * array to hold the pointers */
37556a682bfSchristos     argarray = emalloc(cnt * sizeof(char *));
37610dd2532Schristos 
37710dd2532Schristos     /* allocate another array to hold the strings themselves */
37856a682bfSchristos     args = emalloc(length+2);
37910dd2532Schristos 
38010dd2532Schristos     /* initialization for main loop */
38110dd2532Schristos     from = line;
38210dd2532Schristos     to = args;
38310dd2532Schristos     argv = argarray;
38410dd2532Schristos     lastch = '\0';
38510dd2532Schristos 
38610dd2532Schristos     /* create a dummy argument to keep getopt happy */
38710dd2532Schristos     *argv++ = to;
38810dd2532Schristos     *to++ = '\0';
38910dd2532Schristos     cnt = 2;
39010dd2532Schristos 
39110dd2532Schristos     /* now build argv while copying characters */
39210dd2532Schristos     *argv++ = to;
39310dd2532Schristos     while ((ch = *from++) != '\0')
39410dd2532Schristos     {
39510dd2532Schristos 	if (ch != ' ')
39610dd2532Schristos 	{
39710dd2532Schristos 	    if (lastch == ' ')
39810dd2532Schristos 	    {
39910dd2532Schristos 		*to++ = '\0';
40010dd2532Schristos 		*argv++ = to;
40110dd2532Schristos 		cnt++;
40210dd2532Schristos 	    }
40310dd2532Schristos 	    *to++ = ch;
40410dd2532Schristos 	}
40510dd2532Schristos 	lastch = ch;
40610dd2532Schristos     }
40710dd2532Schristos     *to++ = '\0';
40810dd2532Schristos 
40910dd2532Schristos     /* set cntp and return the allocated array */
41010dd2532Schristos     *cntp = cnt;
41110dd2532Schristos     return(argarray);
41210dd2532Schristos }
41310dd2532Schristos 
41410dd2532Schristos /*
41510dd2532Schristos  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
41610dd2532Schristos  *	between array "old" and "new", putting the percentages i "out".
41710dd2532Schristos  *	"cnt" is size of each array and "diffs" is used for scratch space.
41810dd2532Schristos  *	The array "old" is updated on each call.
41910dd2532Schristos  *	The routine assumes modulo arithmetic.  This function is especially
42010dd2532Schristos  *	useful on BSD mchines for calculating cpu state percentages.
42110dd2532Schristos  */
42210dd2532Schristos 
42310dd2532Schristos long
percentages(int cnt,int * out,long * new,long * old,long * diffs)42410dd2532Schristos percentages(int cnt, int *out, long *new, long *old, long *diffs)
42510dd2532Schristos 
42610dd2532Schristos {
42710dd2532Schristos     register int i;
42810dd2532Schristos     register long change;
42910dd2532Schristos     register long total_change;
43010dd2532Schristos     register long *dp;
43110dd2532Schristos     long half_total;
43210dd2532Schristos 
43310dd2532Schristos     /* initialization */
43410dd2532Schristos     total_change = 0;
43510dd2532Schristos     dp = diffs;
43610dd2532Schristos 
43710dd2532Schristos     /* calculate changes for each state and the overall change */
43810dd2532Schristos     for (i = 0; i < cnt; i++)
43910dd2532Schristos     {
44010dd2532Schristos 	if ((change = *new - *old) < 0)
44110dd2532Schristos 	{
44210dd2532Schristos 	    /* this only happens when the counter wraps */
44310dd2532Schristos 	    change = (int)
44410dd2532Schristos 		((unsigned long)*new-(unsigned long)*old);
44510dd2532Schristos 	}
44610dd2532Schristos 	total_change += (*dp++ = change);
44710dd2532Schristos 	*old++ = *new++;
44810dd2532Schristos     }
44910dd2532Schristos 
45010dd2532Schristos     /* avoid divide by zero potential */
45110dd2532Schristos     if (total_change == 0)
45210dd2532Schristos     {
45310dd2532Schristos 	total_change = 1;
45410dd2532Schristos     }
45510dd2532Schristos 
45610dd2532Schristos     /* calculate percentages based on overall change, rounding up */
45710dd2532Schristos     half_total = total_change / 2l;
45810dd2532Schristos     for (i = 0; i < cnt; i++)
45910dd2532Schristos     {
46010dd2532Schristos 	*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
46110dd2532Schristos     }
46210dd2532Schristos 
46310dd2532Schristos     /* return the total in case the caller wants to use it */
46410dd2532Schristos     return(total_change);
46510dd2532Schristos }
46610dd2532Schristos 
46710dd2532Schristos /*
46810dd2532Schristos  * errmsg(errnum) - return an error message string appropriate to the
46910dd2532Schristos  *           error number "errnum".  This is a substitute for the System V
47010dd2532Schristos  *           function "strerror".  There appears to be no reliable way to
47110dd2532Schristos  *           determine if "strerror" exists at compile time, so I make do
47210dd2532Schristos  *           by providing something of similar functionality.  For those
47310dd2532Schristos  *           systems that have strerror and NOT errlist, define
47410dd2532Schristos  *           -DHAVE_STRERROR in the module file and this function will
47510dd2532Schristos  *           use strerror.
47610dd2532Schristos  */
47710dd2532Schristos 
47810dd2532Schristos /* externs referenced by errmsg */
47910dd2532Schristos 
48010dd2532Schristos #ifndef HAVE_STRERROR
48110dd2532Schristos #if !HAVE_DECL_SYS_ERRLIST
48210dd2532Schristos extern char *sys_errlist[];
48310dd2532Schristos #endif
48410dd2532Schristos 
48510dd2532Schristos extern int sys_nerr;
48610dd2532Schristos #endif
48710dd2532Schristos 
488213e7ef1Schristos const char *
errmsg(int errnum)48910dd2532Schristos errmsg(int errnum)
49010dd2532Schristos 
49110dd2532Schristos {
49210dd2532Schristos #ifdef HAVE_STRERROR
49310dd2532Schristos     char *msg = strerror(errnum);
49410dd2532Schristos     if (msg != NULL)
49510dd2532Schristos     {
49610dd2532Schristos 	return msg;
49710dd2532Schristos     }
49810dd2532Schristos #else
49910dd2532Schristos     if (errnum > 0 && errnum < sys_nerr)
50010dd2532Schristos     {
50110dd2532Schristos 	return((char *)(sys_errlist[errnum]));
50210dd2532Schristos     }
50310dd2532Schristos #endif
50410dd2532Schristos     return("No error");
50510dd2532Schristos }
50610dd2532Schristos 
50710dd2532Schristos /* format_percent(v) - format a double as a percentage in a manner that
50810dd2532Schristos  *		does not exceed 5 characters (excluding any trailing
50910dd2532Schristos  *		percent sign).  Since it is possible for the value
51010dd2532Schristos  *		to exceed 100%, we format such values with no fractional
51110dd2532Schristos  *		component to fit within the 5 characters.
51210dd2532Schristos  */
51310dd2532Schristos 
51410dd2532Schristos char *
format_percent(double v)51510dd2532Schristos format_percent(double v)
51610dd2532Schristos 
51710dd2532Schristos {
51810dd2532Schristos     static char result[10];
51910dd2532Schristos 
52010dd2532Schristos     /* enumerate the possibilities */
52110dd2532Schristos     if (v < 0 || v >= 100000.)
52210dd2532Schristos     {
52310dd2532Schristos 	/* we dont want to try extreme values */
52410dd2532Schristos 	strcpy(result, "  ???");
52510dd2532Schristos     }
52610dd2532Schristos     else if (v > 99.99)
52710dd2532Schristos     {
52810dd2532Schristos 	sprintf(result, "%5.0f", v);
52910dd2532Schristos     }
53010dd2532Schristos     else
53110dd2532Schristos     {
53210dd2532Schristos 	sprintf(result, "%5.2f", v);
53310dd2532Schristos     }
53410dd2532Schristos 
53510dd2532Schristos     return result;
53610dd2532Schristos }
53710dd2532Schristos 
53810dd2532Schristos /* format_time(seconds) - format number of seconds into a suitable
53910dd2532Schristos  *		display that will fit within 6 characters.  Note that this
54010dd2532Schristos  *		routine builds its string in a static area.  If it needs
54110dd2532Schristos  *		to be called more than once without overwriting previous data,
54210dd2532Schristos  *		then we will need to adopt a technique similar to the
54310dd2532Schristos  *		one used for format_k.
54410dd2532Schristos  */
54510dd2532Schristos 
54610dd2532Schristos /* Explanation:
54710dd2532Schristos    We want to keep the output within 6 characters.  For low values we use
54810dd2532Schristos    the format mm:ss.  For values that exceed 999:59, we switch to a format
54910dd2532Schristos    that displays hours and fractions:  hhh.tH.  For values that exceed
55010dd2532Schristos    999.9, we use hhhh.t and drop the "H" designator.  For values that
55110dd2532Schristos    exceed 9999.9, we use "???".
55210dd2532Schristos  */
55310dd2532Schristos 
55410dd2532Schristos char *
format_time(long seconds)55510dd2532Schristos format_time(long seconds)
55610dd2532Schristos 
55710dd2532Schristos {
55810dd2532Schristos     static char result[10];
55910dd2532Schristos 
56010dd2532Schristos     /* sanity protection */
56110dd2532Schristos     if (seconds < 0 || seconds > (99999l * 360l))
56210dd2532Schristos     {
56310dd2532Schristos 	strcpy(result, "   ???");
56410dd2532Schristos     }
56510dd2532Schristos     else if (seconds >= (1000l * 60l))
56610dd2532Schristos     {
56710dd2532Schristos 	/* alternate (slow) method displaying hours and tenths */
56810dd2532Schristos 	sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l));
56910dd2532Schristos 
57010dd2532Schristos 	/* It is possible that the sprintf took more than 6 characters.
57110dd2532Schristos 	   If so, then the "H" appears as result[6].  If not, then there
57210dd2532Schristos 	   is a \0 in result[6].  Either way, it is safe to step on.
57310dd2532Schristos 	 */
57410dd2532Schristos 	result[6] = '\0';
57510dd2532Schristos     }
57610dd2532Schristos     else
57710dd2532Schristos     {
57810dd2532Schristos 	/* standard method produces MMM:SS */
57910dd2532Schristos 	/* we avoid printf as must as possible to make this quick */
58010dd2532Schristos 	sprintf(result, "%3ld:%02ld", seconds / 60l, seconds % 60l);
58110dd2532Schristos     }
58210dd2532Schristos     return(result);
58310dd2532Schristos }
58410dd2532Schristos 
58510dd2532Schristos /*
58610dd2532Schristos  * format_k(amt) - format a kilobyte memory value, returning a string
58710dd2532Schristos  *		suitable for display.  Returns a pointer to a static
58810dd2532Schristos  *		area that changes each call.  "amt" is converted to a
58910dd2532Schristos  *		string with a trailing "K".  If "amt" is 10000 or greater,
59010dd2532Schristos  *		then it is formatted as megabytes (rounded) with a
59110dd2532Schristos  *		trailing "M".
59210dd2532Schristos  */
59310dd2532Schristos 
59410dd2532Schristos /*
59510dd2532Schristos  * Compromise time.  We need to return a string, but we don't want the
59610dd2532Schristos  * caller to have to worry about freeing a dynamically allocated string.
59710dd2532Schristos  * Unfortunately, we can't just return a pointer to a static area as one
59810dd2532Schristos  * of the common uses of this function is in a large call to sprintf where
59910dd2532Schristos  * it might get invoked several times.  Our compromise is to maintain an
60010dd2532Schristos  * array of strings and cycle thru them with each invocation.  We make the
60110dd2532Schristos  * array large enough to handle the above mentioned case.  The constant
60210dd2532Schristos  * NUM_STRINGS defines the number of strings in this array:  we can tolerate
60310dd2532Schristos  * up to NUM_STRINGS calls before we start overwriting old information.
60410dd2532Schristos  * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer
60510dd2532Schristos  * to convert the modulo operation into something quicker.  What a hack!
60610dd2532Schristos  */
60710dd2532Schristos 
60810dd2532Schristos #define NUM_STRINGS 8
60910dd2532Schristos 
61010dd2532Schristos char *
format_k(long amt)61110dd2532Schristos format_k(long amt)
61210dd2532Schristos 
61310dd2532Schristos {
614*9ded70a5Smrg     static char retarray[NUM_STRINGS][24];
615213e7ef1Schristos     static int idx = 0;
61610dd2532Schristos     register char *ret;
61710dd2532Schristos     register char tag = 'K';
61810dd2532Schristos 
619213e7ef1Schristos     ret = retarray[idx];
620213e7ef1Schristos     idx = (idx + 1) % NUM_STRINGS;
62110dd2532Schristos 
62210dd2532Schristos     if (amt >= 10000)
62310dd2532Schristos     {
62410dd2532Schristos 	amt = (amt + 512) / 1024;
62510dd2532Schristos 	tag = 'M';
62610dd2532Schristos 	if (amt >= 10000)
62710dd2532Schristos 	{
62810dd2532Schristos 	    amt = (amt + 512) / 1024;
62910dd2532Schristos 	    tag = 'G';
63010dd2532Schristos 	}
63110dd2532Schristos     }
63210dd2532Schristos 
633213e7ef1Schristos     snprintf(ret, sizeof(retarray[idx])-1, "%ld%c", amt, tag);
63410dd2532Schristos 
63510dd2532Schristos     return(ret);
63610dd2532Schristos }
63710dd2532Schristos 
63810dd2532Schristos /*
63910dd2532Schristos  * Time keeping functions.
64010dd2532Schristos  */
64110dd2532Schristos 
64210dd2532Schristos static struct timeval lasttime = { 0, 0 };
64310dd2532Schristos static unsigned int elapsed_msecs = 0;
64410dd2532Schristos 
64510dd2532Schristos void
time_get(struct timeval * tv)64610dd2532Schristos time_get(struct timeval *tv)
64710dd2532Schristos 
64810dd2532Schristos {
64910dd2532Schristos     /* get the current time */
65010dd2532Schristos #ifdef HAVE_GETTIMEOFDAY
65110dd2532Schristos     gettimeofday(tv, NULL);
65210dd2532Schristos #else
65310dd2532Schristos     tv->tv_sec = (long)time(NULL);
65410dd2532Schristos     tv->tv_usec = 0;
65510dd2532Schristos #endif
65610dd2532Schristos }
65710dd2532Schristos 
65810dd2532Schristos void
time_mark(struct timeval * tv)65910dd2532Schristos time_mark(struct timeval *tv)
66010dd2532Schristos 
66110dd2532Schristos {
66210dd2532Schristos     struct timeval thistime;
66310dd2532Schristos     struct timeval timediff;
66410dd2532Schristos 
66510dd2532Schristos     /* if the caller didnt provide one then use our own */
66610dd2532Schristos     if (tv == NULL)
66710dd2532Schristos     {
66810dd2532Schristos 	tv = &thistime;
66910dd2532Schristos     }
67010dd2532Schristos 
67110dd2532Schristos     /* get the current time */
67210dd2532Schristos #ifdef HAVE_GETTIMEOFDAY
67310dd2532Schristos     gettimeofday(tv, NULL);
67410dd2532Schristos #else
67510dd2532Schristos     tv->tv_sec = (long)time(NULL);
67610dd2532Schristos     tv->tv_usec = 0;
67710dd2532Schristos #endif
67810dd2532Schristos 
67910dd2532Schristos     /* calculate the difference */
68010dd2532Schristos     timediff.tv_sec = tv->tv_sec - lasttime.tv_sec;
68110dd2532Schristos     timediff.tv_usec = tv->tv_usec - lasttime.tv_usec;
68210dd2532Schristos     if (timediff.tv_usec < 0) {
68310dd2532Schristos 	timediff.tv_sec--;
68410dd2532Schristos 	timediff.tv_usec += 1000000;
68510dd2532Schristos     }
68610dd2532Schristos 
68710dd2532Schristos     /* convert to milliseconds */
68810dd2532Schristos     elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
68910dd2532Schristos     if (elapsed_msecs == 0)
69010dd2532Schristos     {
69110dd2532Schristos 	elapsed_msecs = 1;
69210dd2532Schristos     }
69310dd2532Schristos 
69410dd2532Schristos     /* save for next time */
69510dd2532Schristos     lasttime = *tv;
69610dd2532Schristos }
69710dd2532Schristos 
69810dd2532Schristos unsigned int
time_elapsed()69910dd2532Schristos time_elapsed()
70010dd2532Schristos 
70110dd2532Schristos {
70210dd2532Schristos     return elapsed_msecs;
70310dd2532Schristos }
70410dd2532Schristos 
70510dd2532Schristos unsigned int
diff_per_second(unsigned int x,unsigned int y)70610dd2532Schristos diff_per_second(unsigned int x, unsigned int y)
70710dd2532Schristos 
70810dd2532Schristos {
70910dd2532Schristos     return (y > x ? UINT_MAX - y + x + 1 : x - y) * 1000 / elapsed_msecs;
71010dd2532Schristos }
71110dd2532Schristos 
712a8f5847fSchristos void
double2tv(struct timeval * tv,double d)713a8f5847fSchristos double2tv(struct timeval *tv, double d)
714a8f5847fSchristos {
7150ca1e3e0Sdholland     double di;
7160ca1e3e0Sdholland 
7170ca1e3e0Sdholland     di = floor(d);
7180ca1e3e0Sdholland     tv->tv_sec = (time_t)di;
7190ca1e3e0Sdholland     tv->tv_usec = (int)ceil((d - di) * 1000000.0);
720a8f5847fSchristos }
721a8f5847fSchristos 
72210dd2532Schristos static int debug_on = 0;
72310dd2532Schristos 
72410dd2532Schristos #ifdef DEBUG
72510dd2532Schristos FILE *debugfile;
72610dd2532Schristos #endif
72710dd2532Schristos 
72810dd2532Schristos void
debug_set(int i)72910dd2532Schristos debug_set(int i)
73010dd2532Schristos 
73110dd2532Schristos {
73210dd2532Schristos     debug_on = i;
73310dd2532Schristos #ifdef DEBUG
73410dd2532Schristos     debugfile = fopen("/tmp/top.debug", "w");
73510dd2532Schristos #endif
73610dd2532Schristos }
73710dd2532Schristos 
73810dd2532Schristos #ifdef DEBUG
73910dd2532Schristos void
xdprintf(char * fmt,...)74010dd2532Schristos xdprintf(char *fmt, ...)
74110dd2532Schristos 
74210dd2532Schristos {
74310dd2532Schristos     va_list argp;
74410dd2532Schristos 
74510dd2532Schristos     va_start(argp, fmt);
74610dd2532Schristos 
74710dd2532Schristos     if (debug_on)
74810dd2532Schristos     {
74910dd2532Schristos 	vfprintf(debugfile, fmt, argp);
75010dd2532Schristos 	fflush(debugfile);
75110dd2532Schristos     }
75210dd2532Schristos 
75310dd2532Schristos     va_end(argp);
75410dd2532Schristos }
75510dd2532Schristos #endif
75610dd2532Schristos 
757