xref: /dragonfly/usr.bin/top/utils.c (revision dc4f0af1)
1*dc4f0af1Szrj /*
2*dc4f0af1Szrj  * Copyright (c) 1984 through 2008, William LeFebvre
3*dc4f0af1Szrj  * All rights reserved.
4*dc4f0af1Szrj  *
5*dc4f0af1Szrj  * Redistribution and use in source and binary forms, with or without
6*dc4f0af1Szrj  * modification, are permitted provided that the following conditions are met:
7*dc4f0af1Szrj  *
8*dc4f0af1Szrj  *     * Redistributions of source code must retain the above copyright
9*dc4f0af1Szrj  * notice, this list of conditions and the following disclaimer.
10*dc4f0af1Szrj  *
11*dc4f0af1Szrj  *     * Redistributions in binary form must reproduce the above
12*dc4f0af1Szrj  * copyright notice, this list of conditions and the following disclaimer
13*dc4f0af1Szrj  * in the documentation and/or other materials provided with the
14*dc4f0af1Szrj  * distribution.
15*dc4f0af1Szrj  *
16*dc4f0af1Szrj  *     * Neither the name of William LeFebvre nor the names of other
17*dc4f0af1Szrj  * contributors may be used to endorse or promote products derived from
18*dc4f0af1Szrj  * this software without specific prior written permission.
19*dc4f0af1Szrj  *
20*dc4f0af1Szrj  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*dc4f0af1Szrj  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*dc4f0af1Szrj  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*dc4f0af1Szrj  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*dc4f0af1Szrj  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*dc4f0af1Szrj  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*dc4f0af1Szrj  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*dc4f0af1Szrj  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*dc4f0af1Szrj  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*dc4f0af1Szrj  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*dc4f0af1Szrj  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*dc4f0af1Szrj  */
32*dc4f0af1Szrj 
33*dc4f0af1Szrj /*
34*dc4f0af1Szrj  *  Top users/processes display for Unix
35*dc4f0af1Szrj  *  Version 3
36*dc4f0af1Szrj  */
37*dc4f0af1Szrj 
38*dc4f0af1Szrj /*
39*dc4f0af1Szrj  *  This file contains various handy utilities used by top.
40*dc4f0af1Szrj  */
41*dc4f0af1Szrj 
42*dc4f0af1Szrj #include "os.h"
43*dc4f0af1Szrj #include <ctype.h>
44*dc4f0af1Szrj #ifdef HAVE_STDARG_H
45*dc4f0af1Szrj #include <stdarg.h>
46*dc4f0af1Szrj #else
47*dc4f0af1Szrj #undef DEBUG
48*dc4f0af1Szrj #endif
49*dc4f0af1Szrj #include "top.h"
50*dc4f0af1Szrj #include "utils.h"
51*dc4f0af1Szrj 
52*dc4f0af1Szrj static int
alldigits(char * s)53*dc4f0af1Szrj alldigits(char *s)
54*dc4f0af1Szrj 
55*dc4f0af1Szrj {
56*dc4f0af1Szrj     int ch;
57*dc4f0af1Szrj 
58*dc4f0af1Szrj     while ((ch = *s++) != '\0')
59*dc4f0af1Szrj     {
60*dc4f0af1Szrj 	if (!isdigit(ch))
61*dc4f0af1Szrj 	{
62*dc4f0af1Szrj 	    return 0;
63*dc4f0af1Szrj 	}
64*dc4f0af1Szrj     }
65*dc4f0af1Szrj     return 1;
66*dc4f0af1Szrj }
67*dc4f0af1Szrj 
68*dc4f0af1Szrj int
atoiwi(char * str)69*dc4f0af1Szrj atoiwi(char *str)
70*dc4f0af1Szrj 
71*dc4f0af1Szrj {
72*dc4f0af1Szrj     register int len;
73*dc4f0af1Szrj 
74*dc4f0af1Szrj     len = strlen(str);
75*dc4f0af1Szrj     if (len != 0)
76*dc4f0af1Szrj     {
77*dc4f0af1Szrj 	if (strncmp(str, "infinity", len) == 0 ||
78*dc4f0af1Szrj 	    strncmp(str, "all",      len) == 0 ||
79*dc4f0af1Szrj 	    strncmp(str, "maximum",  len) == 0)
80*dc4f0af1Szrj 	{
81*dc4f0af1Szrj 	    return(Infinity);
82*dc4f0af1Szrj 	}
83*dc4f0af1Szrj 	else if (alldigits(str))
84*dc4f0af1Szrj 	{
85*dc4f0af1Szrj 	    return(atoi(str));
86*dc4f0af1Szrj 	}
87*dc4f0af1Szrj 	else
88*dc4f0af1Szrj 	{
89*dc4f0af1Szrj 	    return(Invalid);
90*dc4f0af1Szrj 	}
91*dc4f0af1Szrj     }
92*dc4f0af1Szrj     return(0);
93*dc4f0af1Szrj }
94*dc4f0af1Szrj 
95*dc4f0af1Szrj /*
96*dc4f0af1Szrj  *  itoa - convert integer (decimal) to ascii string for positive numbers
97*dc4f0af1Szrj  *  	   only (we don't bother with negative numbers since we know we
98*dc4f0af1Szrj  *	   don't use them).
99*dc4f0af1Szrj  */
100*dc4f0af1Szrj 
101*dc4f0af1Szrj 				/*
102*dc4f0af1Szrj 				 * How do we know that 16 will suffice?
103*dc4f0af1Szrj 				 * Because the biggest number that we will
104*dc4f0af1Szrj 				 * ever convert will be 2^32-1, which is 10
105*dc4f0af1Szrj 				 * digits.
106*dc4f0af1Szrj 				 */
107*dc4f0af1Szrj 
108*dc4f0af1Szrj char *
itoa(int val)109*dc4f0af1Szrj itoa(int val)
110*dc4f0af1Szrj 
111*dc4f0af1Szrj {
112*dc4f0af1Szrj     register char *ptr;
113*dc4f0af1Szrj     static char buffer[16];	/* result is built here */
114*dc4f0af1Szrj     				/* 16 is sufficient since the largest number
115*dc4f0af1Szrj 				   we will ever convert will be 2^32-1,
116*dc4f0af1Szrj 				   which is 10 digits. */
117*dc4f0af1Szrj 
118*dc4f0af1Szrj     ptr = buffer + sizeof(buffer);
119*dc4f0af1Szrj     *--ptr = '\0';
120*dc4f0af1Szrj     if (val == 0)
121*dc4f0af1Szrj     {
122*dc4f0af1Szrj 	*--ptr = '0';
123*dc4f0af1Szrj     }
124*dc4f0af1Szrj     else while (val != 0)
125*dc4f0af1Szrj     {
126*dc4f0af1Szrj 	*--ptr = (val % 10) + '0';
127*dc4f0af1Szrj 	val /= 10;
128*dc4f0af1Szrj     }
129*dc4f0af1Szrj     return(ptr);
130*dc4f0af1Szrj }
131*dc4f0af1Szrj 
132*dc4f0af1Szrj /*
133*dc4f0af1Szrj  *  itoa7(val) - like itoa, except the number is right justified in a 7
134*dc4f0af1Szrj  *	character field.  This code is a duplication of itoa instead of
135*dc4f0af1Szrj  *	a front end to a more general routine for efficiency.
136*dc4f0af1Szrj  */
137*dc4f0af1Szrj 
138*dc4f0af1Szrj char *
itoa_w(int val,int w)139*dc4f0af1Szrj itoa_w(int val, int w)
140*dc4f0af1Szrj 
141*dc4f0af1Szrj {
142*dc4f0af1Szrj     char *ptr;
143*dc4f0af1Szrj     char *eptr;
144*dc4f0af1Szrj     static char buffer[16];	/* result is built here */
145*dc4f0af1Szrj     				/* 16 is sufficient since the largest number
146*dc4f0af1Szrj 				   we will ever convert will be 2^32-1,
147*dc4f0af1Szrj 				   which is 10 digits. */
148*dc4f0af1Szrj 
149*dc4f0af1Szrj     if (w > 15)
150*dc4f0af1Szrj     {
151*dc4f0af1Szrj 	w = 15;
152*dc4f0af1Szrj     }
153*dc4f0af1Szrj     eptr = ptr = buffer + sizeof(buffer);
154*dc4f0af1Szrj     *--ptr = '\0';
155*dc4f0af1Szrj     if (val == 0)
156*dc4f0af1Szrj     {
157*dc4f0af1Szrj 	*--ptr = '0';
158*dc4f0af1Szrj     }
159*dc4f0af1Szrj     else while (val != 0)
160*dc4f0af1Szrj     {
161*dc4f0af1Szrj 	*--ptr = (val % 10) + '0';
162*dc4f0af1Szrj 	val /= 10;
163*dc4f0af1Szrj     }
164*dc4f0af1Szrj     while (ptr >= eptr - w)
165*dc4f0af1Szrj     {
166*dc4f0af1Szrj 	*--ptr = ' ';
167*dc4f0af1Szrj     }
168*dc4f0af1Szrj     return(ptr);
169*dc4f0af1Szrj }
170*dc4f0af1Szrj 
171*dc4f0af1Szrj char *
itoa7(int val)172*dc4f0af1Szrj itoa7(int val)
173*dc4f0af1Szrj 
174*dc4f0af1Szrj {
175*dc4f0af1Szrj     return itoa_w(val, 7);
176*dc4f0af1Szrj }
177*dc4f0af1Szrj 
178*dc4f0af1Szrj /*
179*dc4f0af1Szrj  *  digits(val) - return number of decimal digits in val.  Only works for
180*dc4f0af1Szrj  *	positive numbers.  If val < 0 then digits(val) == 0, but
181*dc4f0af1Szrj  *      digits(0) == 1.
182*dc4f0af1Szrj  */
183*dc4f0af1Szrj 
184*dc4f0af1Szrj int
digits(int val)185*dc4f0af1Szrj digits(int val)
186*dc4f0af1Szrj 
187*dc4f0af1Szrj {
188*dc4f0af1Szrj     register int cnt = 0;
189*dc4f0af1Szrj 
190*dc4f0af1Szrj     if (val == 0)
191*dc4f0af1Szrj     {
192*dc4f0af1Szrj 	return 1;
193*dc4f0af1Szrj     }
194*dc4f0af1Szrj     while (val > 0)
195*dc4f0af1Szrj     {
196*dc4f0af1Szrj 	cnt++;
197*dc4f0af1Szrj 	val /= 10;
198*dc4f0af1Szrj     }
199*dc4f0af1Szrj     return(cnt);
200*dc4f0af1Szrj }
201*dc4f0af1Szrj 
202*dc4f0af1Szrj /*
203*dc4f0af1Szrj  *  printable(char *str) - make the string pointed to by "str" into one that is
204*dc4f0af1Szrj  *	printable (i.e.: all ascii), by converting all non-printable
205*dc4f0af1Szrj  *	characters into '?'.  Replacements are done in place and a pointer
206*dc4f0af1Szrj  *	to the original buffer is returned.
207*dc4f0af1Szrj  */
208*dc4f0af1Szrj 
209*dc4f0af1Szrj char *
printable(char * str)210*dc4f0af1Szrj printable(char *str)
211*dc4f0af1Szrj 
212*dc4f0af1Szrj {
213*dc4f0af1Szrj     register char *ptr;
214*dc4f0af1Szrj     register int ch;
215*dc4f0af1Szrj 
216*dc4f0af1Szrj     ptr = str;
217*dc4f0af1Szrj     while ((ch = *ptr) != '\0')
218*dc4f0af1Szrj     {
219*dc4f0af1Szrj 	if (!isprint(ch))
220*dc4f0af1Szrj 	{
221*dc4f0af1Szrj 	    *ptr = '?';
222*dc4f0af1Szrj 	}
223*dc4f0af1Szrj 	ptr++;
224*dc4f0af1Szrj     }
225*dc4f0af1Szrj     return(str);
226*dc4f0af1Szrj }
227*dc4f0af1Szrj 
228*dc4f0af1Szrj /*
229*dc4f0af1Szrj  *  strcpyend(to, from) - copy string "from" into "to" and return a pointer
230*dc4f0af1Szrj  *	to the END of the string "to".
231*dc4f0af1Szrj  */
232*dc4f0af1Szrj 
233*dc4f0af1Szrj char *
strcpyend(char * to,char * from)234*dc4f0af1Szrj strcpyend(char *to, char *from)
235*dc4f0af1Szrj 
236*dc4f0af1Szrj {
237*dc4f0af1Szrj     while ((*to++ = *from++) != '\0');
238*dc4f0af1Szrj     return(--to);
239*dc4f0af1Szrj }
240*dc4f0af1Szrj 
241*dc4f0af1Szrj /*
242*dc4f0af1Szrj  * char *
243*dc4f0af1Szrj  * homogenize(char *str)
244*dc4f0af1Szrj  *
245*dc4f0af1Szrj  * Remove unwanted characters from "str" and make everything lower case.
246*dc4f0af1Szrj  * Newly allocated string is returned: the original is not altered.
247*dc4f0af1Szrj  */
248*dc4f0af1Szrj 
homogenize(char * str)249*dc4f0af1Szrj char *homogenize(char *str)
250*dc4f0af1Szrj 
251*dc4f0af1Szrj {
252*dc4f0af1Szrj     char *ans;
253*dc4f0af1Szrj     char *fr;
254*dc4f0af1Szrj     char *to;
255*dc4f0af1Szrj     int ch;
256*dc4f0af1Szrj 
257*dc4f0af1Szrj     to = fr = ans = strdup(str);
258*dc4f0af1Szrj     while ((ch = *fr++) != '\0')
259*dc4f0af1Szrj     {
260*dc4f0af1Szrj 	if (isalnum(ch))
261*dc4f0af1Szrj 	{
262*dc4f0af1Szrj 	    *to++ = tolower(ch);
263*dc4f0af1Szrj 	}
264*dc4f0af1Szrj     }
265*dc4f0af1Szrj 
266*dc4f0af1Szrj     *to = '\0';
267*dc4f0af1Szrj     return ans;
268*dc4f0af1Szrj }
269*dc4f0af1Szrj 
270*dc4f0af1Szrj /*
271*dc4f0af1Szrj  * string_index(string, array) - find string in array and return index
272*dc4f0af1Szrj  */
273*dc4f0af1Szrj 
274*dc4f0af1Szrj int
string_index(char * string,char ** array)275*dc4f0af1Szrj string_index(char *string, char **array)
276*dc4f0af1Szrj 
277*dc4f0af1Szrj {
278*dc4f0af1Szrj     register int i = 0;
279*dc4f0af1Szrj 
280*dc4f0af1Szrj     while (*array != NULL)
281*dc4f0af1Szrj     {
282*dc4f0af1Szrj 	if (strcmp(string, *array) == 0)
283*dc4f0af1Szrj 	{
284*dc4f0af1Szrj 	    return(i);
285*dc4f0af1Szrj 	}
286*dc4f0af1Szrj 	array++;
287*dc4f0af1Szrj 	i++;
288*dc4f0af1Szrj     }
289*dc4f0af1Szrj     return(-1);
290*dc4f0af1Szrj }
291*dc4f0af1Szrj 
292*dc4f0af1Szrj /*
293*dc4f0af1Szrj  * char *string_list(char **strings)
294*dc4f0af1Szrj  *
295*dc4f0af1Szrj  * Create a comma-separated list of the strings in the NULL-terminated
296*dc4f0af1Szrj  * "strings".  Returned string is malloc-ed and should be freed when the
297*dc4f0af1Szrj  * caller is done.  Note that this is not an efficient function.
298*dc4f0af1Szrj  */
299*dc4f0af1Szrj 
string_list(char ** strings)300*dc4f0af1Szrj char *string_list(char **strings)
301*dc4f0af1Szrj 
302*dc4f0af1Szrj {
303*dc4f0af1Szrj     int cnt = 0;
304*dc4f0af1Szrj     char **pp;
305*dc4f0af1Szrj     char *p;
306*dc4f0af1Szrj     char *result = NULL;
307*dc4f0af1Szrj     char *resp = NULL;
308*dc4f0af1Szrj 
309*dc4f0af1Szrj     pp = strings;
310*dc4f0af1Szrj     while ((p = *pp++) != NULL)
311*dc4f0af1Szrj     {
312*dc4f0af1Szrj 	cnt += strlen(p) + 2;
313*dc4f0af1Szrj     }
314*dc4f0af1Szrj 
315*dc4f0af1Szrj     if (cnt > 0)
316*dc4f0af1Szrj     {
317*dc4f0af1Szrj 	resp = result = (char *)malloc(cnt);
318*dc4f0af1Szrj 	pp = strings;
319*dc4f0af1Szrj 	while ((p = *pp++) != NULL)
320*dc4f0af1Szrj 	{
321*dc4f0af1Szrj 	    resp = strcpyend(resp, p);
322*dc4f0af1Szrj 	    if (*pp != NULL)
323*dc4f0af1Szrj 	    {
324*dc4f0af1Szrj 		resp = strcpyend(resp, ", ");
325*dc4f0af1Szrj 	    }
326*dc4f0af1Szrj 	}
327*dc4f0af1Szrj     }
328*dc4f0af1Szrj 
329*dc4f0af1Szrj     return result;
330*dc4f0af1Szrj }
331*dc4f0af1Szrj 
332*dc4f0af1Szrj /*
333*dc4f0af1Szrj  * argparse(line, cntp) - parse arguments in string "line", separating them
334*dc4f0af1Szrj  *	out into an argv-like array, and setting *cntp to the number of
335*dc4f0af1Szrj  *	arguments encountered.  This is a simple parser that doesn't understand
336*dc4f0af1Szrj  *	squat about quotes.
337*dc4f0af1Szrj  */
338*dc4f0af1Szrj 
339*dc4f0af1Szrj char **
argparse(char * line,int * cntp)340*dc4f0af1Szrj argparse(char *line, int *cntp)
341*dc4f0af1Szrj 
342*dc4f0af1Szrj {
343*dc4f0af1Szrj     register char *from;
344*dc4f0af1Szrj     register char *to;
345*dc4f0af1Szrj     register int cnt;
346*dc4f0af1Szrj     register int ch;
347*dc4f0af1Szrj     int length;
348*dc4f0af1Szrj     int lastch;
349*dc4f0af1Szrj     register char **argv;
350*dc4f0af1Szrj     char **argarray;
351*dc4f0af1Szrj     char *args;
352*dc4f0af1Szrj 
353*dc4f0af1Szrj     /* unfortunately, the only real way to do this is to go thru the
354*dc4f0af1Szrj        input string twice. */
355*dc4f0af1Szrj 
356*dc4f0af1Szrj     /* step thru the string counting the white space sections */
357*dc4f0af1Szrj     from = line;
358*dc4f0af1Szrj     lastch = cnt = length = 0;
359*dc4f0af1Szrj     while ((ch = *from++) != '\0')
360*dc4f0af1Szrj     {
361*dc4f0af1Szrj 	length++;
362*dc4f0af1Szrj 	if (ch == ' ' && lastch != ' ')
363*dc4f0af1Szrj 	{
364*dc4f0af1Szrj 	    cnt++;
365*dc4f0af1Szrj 	}
366*dc4f0af1Szrj 	lastch = ch;
367*dc4f0af1Szrj     }
368*dc4f0af1Szrj 
369*dc4f0af1Szrj     /* add three to the count:  one for the initial "dummy" argument,
370*dc4f0af1Szrj        one for the last argument and one for NULL */
371*dc4f0af1Szrj     cnt += 3;
372*dc4f0af1Szrj 
373*dc4f0af1Szrj     /* allocate a char * array to hold the pointers */
374*dc4f0af1Szrj     argarray = (char **)malloc(cnt * sizeof(char *));
375*dc4f0af1Szrj 
376*dc4f0af1Szrj     /* allocate another array to hold the strings themselves */
377*dc4f0af1Szrj     args = (char *)malloc(length+2);
378*dc4f0af1Szrj 
379*dc4f0af1Szrj     /* initialization for main loop */
380*dc4f0af1Szrj     from = line;
381*dc4f0af1Szrj     to = args;
382*dc4f0af1Szrj     argv = argarray;
383*dc4f0af1Szrj     lastch = '\0';
384*dc4f0af1Szrj 
385*dc4f0af1Szrj     /* create a dummy argument to keep getopt happy */
386*dc4f0af1Szrj     *argv++ = to;
387*dc4f0af1Szrj     *to++ = '\0';
388*dc4f0af1Szrj     cnt = 2;
389*dc4f0af1Szrj 
390*dc4f0af1Szrj     /* now build argv while copying characters */
391*dc4f0af1Szrj     *argv++ = to;
392*dc4f0af1Szrj     while ((ch = *from++) != '\0')
393*dc4f0af1Szrj     {
394*dc4f0af1Szrj 	if (ch != ' ')
395*dc4f0af1Szrj 	{
396*dc4f0af1Szrj 	    if (lastch == ' ')
397*dc4f0af1Szrj 	    {
398*dc4f0af1Szrj 		*to++ = '\0';
399*dc4f0af1Szrj 		*argv++ = to;
400*dc4f0af1Szrj 		cnt++;
401*dc4f0af1Szrj 	    }
402*dc4f0af1Szrj 	    *to++ = ch;
403*dc4f0af1Szrj 	}
404*dc4f0af1Szrj 	lastch = ch;
405*dc4f0af1Szrj     }
406*dc4f0af1Szrj     *to++ = '\0';
407*dc4f0af1Szrj 
408*dc4f0af1Szrj     /* set cntp and return the allocated array */
409*dc4f0af1Szrj     *cntp = cnt;
410*dc4f0af1Szrj     return(argarray);
411*dc4f0af1Szrj }
412*dc4f0af1Szrj 
413*dc4f0af1Szrj /*
414*dc4f0af1Szrj  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
415*dc4f0af1Szrj  *	between array "old" and "new", putting the percentages i "out".
416*dc4f0af1Szrj  *	"cnt" is size of each array and "diffs" is used for scratch space.
417*dc4f0af1Szrj  *	The array "old" is updated on each call.
418*dc4f0af1Szrj  *	The routine assumes modulo arithmetic.  This function is especially
419*dc4f0af1Szrj  *	useful on BSD mchines for calculating cpu state percentages.
420*dc4f0af1Szrj  */
421*dc4f0af1Szrj 
422*dc4f0af1Szrj long
percentages(int cnt,int * out,long * new,long * old,long * diffs)423*dc4f0af1Szrj percentages(int cnt, int *out, long *new, long *old, long *diffs)
424*dc4f0af1Szrj 
425*dc4f0af1Szrj {
426*dc4f0af1Szrj     register int i;
427*dc4f0af1Szrj     register long change;
428*dc4f0af1Szrj     register long total_change;
429*dc4f0af1Szrj     register long *dp;
430*dc4f0af1Szrj     long half_total;
431*dc4f0af1Szrj 
432*dc4f0af1Szrj     /* initialization */
433*dc4f0af1Szrj     total_change = 0;
434*dc4f0af1Szrj     dp = diffs;
435*dc4f0af1Szrj 
436*dc4f0af1Szrj     /* calculate changes for each state and the overall change */
437*dc4f0af1Szrj     for (i = 0; i < cnt; i++)
438*dc4f0af1Szrj     {
439*dc4f0af1Szrj 	if ((change = *new - *old) < 0)
440*dc4f0af1Szrj 	{
441*dc4f0af1Szrj 	    /* this only happens when the counter wraps */
442*dc4f0af1Szrj 	    change = (int)
443*dc4f0af1Szrj 		((unsigned long)*new-(unsigned long)*old);
444*dc4f0af1Szrj 	}
445*dc4f0af1Szrj 	total_change += (*dp++ = change);
446*dc4f0af1Szrj 	*old++ = *new++;
447*dc4f0af1Szrj     }
448*dc4f0af1Szrj 
449*dc4f0af1Szrj     /* avoid divide by zero potential */
450*dc4f0af1Szrj     if (total_change == 0)
451*dc4f0af1Szrj     {
452*dc4f0af1Szrj 	total_change = 1;
453*dc4f0af1Szrj     }
454*dc4f0af1Szrj 
455*dc4f0af1Szrj     /* calculate percentages based on overall change, rounding up */
456*dc4f0af1Szrj     half_total = total_change / 2l;
457*dc4f0af1Szrj     for (i = 0; i < cnt; i++)
458*dc4f0af1Szrj     {
459*dc4f0af1Szrj 	*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
460*dc4f0af1Szrj     }
461*dc4f0af1Szrj 
462*dc4f0af1Szrj     /* return the total in case the caller wants to use it */
463*dc4f0af1Szrj     return(total_change);
464*dc4f0af1Szrj }
465*dc4f0af1Szrj 
466*dc4f0af1Szrj /*
467*dc4f0af1Szrj  * errmsg(errnum) - return an error message string appropriate to the
468*dc4f0af1Szrj  *           error number "errnum".  This is a substitute for the System V
469*dc4f0af1Szrj  *           function "strerror".  There appears to be no reliable way to
470*dc4f0af1Szrj  *           determine if "strerror" exists at compile time, so I make do
471*dc4f0af1Szrj  *           by providing something of similar functionality.  For those
472*dc4f0af1Szrj  *           systems that have strerror and NOT errlist, define
473*dc4f0af1Szrj  *           -DHAVE_STRERROR in the module file and this function will
474*dc4f0af1Szrj  *           use strerror.
475*dc4f0af1Szrj  */
476*dc4f0af1Szrj 
477*dc4f0af1Szrj /* externs referenced by errmsg */
478*dc4f0af1Szrj 
479*dc4f0af1Szrj #ifndef HAVE_STRERROR
480*dc4f0af1Szrj #if !HAVE_DECL_SYS_ERRLIST
481*dc4f0af1Szrj extern char *sys_errlist[];
482*dc4f0af1Szrj #endif
483*dc4f0af1Szrj 
484*dc4f0af1Szrj extern int sys_nerr;
485*dc4f0af1Szrj #endif
486*dc4f0af1Szrj 
487*dc4f0af1Szrj char *
errmsg(int errnum)488*dc4f0af1Szrj errmsg(int errnum)
489*dc4f0af1Szrj 
490*dc4f0af1Szrj {
491*dc4f0af1Szrj #ifdef HAVE_STRERROR
492*dc4f0af1Szrj     char *msg = strerror(errnum);
493*dc4f0af1Szrj     if (msg != NULL)
494*dc4f0af1Szrj     {
495*dc4f0af1Szrj 	return msg;
496*dc4f0af1Szrj     }
497*dc4f0af1Szrj #else
498*dc4f0af1Szrj     if (errnum > 0 && errnum < sys_nerr)
499*dc4f0af1Szrj     {
500*dc4f0af1Szrj 	return((char *)(sys_errlist[errnum]));
501*dc4f0af1Szrj     }
502*dc4f0af1Szrj #endif
503*dc4f0af1Szrj     return("No error");
504*dc4f0af1Szrj }
505*dc4f0af1Szrj 
506*dc4f0af1Szrj /* format_percent(v) - format a double as a percentage in a manner that
507*dc4f0af1Szrj  *		does not exceed 5 characters (excluding any trailing
508*dc4f0af1Szrj  *		percent sign).  Since it is possible for the value
509*dc4f0af1Szrj  *		to exceed 100%, we format such values with no fractional
510*dc4f0af1Szrj  *		component to fit within the 5 characters.
511*dc4f0af1Szrj  */
512*dc4f0af1Szrj 
513*dc4f0af1Szrj char *
format_percent(double v)514*dc4f0af1Szrj format_percent(double v)
515*dc4f0af1Szrj 
516*dc4f0af1Szrj {
517*dc4f0af1Szrj     static char result[10];
518*dc4f0af1Szrj 
519*dc4f0af1Szrj     /* enumerate the possibilities */
520*dc4f0af1Szrj     if (v < 0 || v >= 100000.)
521*dc4f0af1Szrj     {
522*dc4f0af1Szrj 	/* we dont want to try extreme values */
523*dc4f0af1Szrj 	strcpy(result, "  ???");
524*dc4f0af1Szrj     }
525*dc4f0af1Szrj     else if (v > 99.99)
526*dc4f0af1Szrj     {
527*dc4f0af1Szrj 	sprintf(result, "%5.0f", v);
528*dc4f0af1Szrj     }
529*dc4f0af1Szrj     else
530*dc4f0af1Szrj     {
531*dc4f0af1Szrj 	sprintf(result, "%5.2f", v);
532*dc4f0af1Szrj     }
533*dc4f0af1Szrj 
534*dc4f0af1Szrj     return result;
535*dc4f0af1Szrj }
536*dc4f0af1Szrj 
537*dc4f0af1Szrj /* format_time(seconds) - format number of seconds into a suitable
538*dc4f0af1Szrj  *		display that will fit within 6 characters.  Note that this
539*dc4f0af1Szrj  *		routine builds its string in a static area.  If it needs
540*dc4f0af1Szrj  *		to be called more than once without overwriting previous data,
541*dc4f0af1Szrj  *		then we will need to adopt a technique similar to the
542*dc4f0af1Szrj  *		one used for format_k.
543*dc4f0af1Szrj  */
544*dc4f0af1Szrj 
545*dc4f0af1Szrj /* Explanation:
546*dc4f0af1Szrj    We want to keep the output within 6 characters.  For low values we use
547*dc4f0af1Szrj    the format mm:ss.  For values that exceed 999:59, we switch to a format
548*dc4f0af1Szrj    that displays hours and fractions:  hhh.tH.  For values that exceed
549*dc4f0af1Szrj    999.9, we use hhhh.t and drop the "H" designator.  For values that
550*dc4f0af1Szrj    exceed 9999.9, we use "???".
551*dc4f0af1Szrj  */
552*dc4f0af1Szrj 
553*dc4f0af1Szrj void *
format_time(long seconds,char * result,int len)554*dc4f0af1Szrj format_time(long seconds, char *result, int len)
555*dc4f0af1Szrj 
556*dc4f0af1Szrj {
557*dc4f0af1Szrj     /* sanity protection */
558*dc4f0af1Szrj     if (seconds < 0 || seconds > (99999l * 360l))
559*dc4f0af1Szrj     {
560*dc4f0af1Szrj 	strcpy(result, "   ???");
561*dc4f0af1Szrj     }
562*dc4f0af1Szrj     else if (seconds >= (1000l * 60l))
563*dc4f0af1Szrj     {
564*dc4f0af1Szrj 	/* alternate (slow) method displaying hours and tenths */
565*dc4f0af1Szrj 	snprintf(result, len - 1, "%5.1fH", (double)seconds / (double)(60l * 60l));
566*dc4f0af1Szrj 
567*dc4f0af1Szrj 	/* It is possible that the sprintf took more than 6 characters.
568*dc4f0af1Szrj 	   If so, then the "H" appears as result[6].  If not, then there
569*dc4f0af1Szrj 	   is a \0 in result[6].  Either way, it is safe to step on.
570*dc4f0af1Szrj 	 */
571*dc4f0af1Szrj 	if (len / sizeof(result[0]) > 6)
572*dc4f0af1Szrj 	    result[6] = '\0';
573*dc4f0af1Szrj     }
574*dc4f0af1Szrj     else
575*dc4f0af1Szrj     {
576*dc4f0af1Szrj 	/* standard method produces MMM:SS */
577*dc4f0af1Szrj 	/* we avoid printf as must as possible to make this quick */
578*dc4f0af1Szrj 	snprintf(result, len - 1, "%3ld:%02ld", seconds / 60l, seconds % 60l);
579*dc4f0af1Szrj     }
580*dc4f0af1Szrj     return(result);
581*dc4f0af1Szrj }
582*dc4f0af1Szrj 
583*dc4f0af1Szrj /*
584*dc4f0af1Szrj  * format_k(amt) - format a kilobyte memory value, returning a string
585*dc4f0af1Szrj  *		suitable for display.  Returns a pointer to a static
586*dc4f0af1Szrj  *		area that changes each call.  "amt" is converted to a
587*dc4f0af1Szrj  *		string with a trailing "K".  If "amt" is 10000 or greater,
588*dc4f0af1Szrj  *		then it is formatted as megabytes (rounded) with a
589*dc4f0af1Szrj  *		trailing "M".
590*dc4f0af1Szrj  */
591*dc4f0af1Szrj 
592*dc4f0af1Szrj /*
593*dc4f0af1Szrj  * Compromise time.  We need to return a string, but we don't want the
594*dc4f0af1Szrj  * caller to have to worry about freeing a dynamically allocated string.
595*dc4f0af1Szrj  * Unfortunately, we can't just return a pointer to a static area as one
596*dc4f0af1Szrj  * of the common uses of this function is in a large call to sprintf where
597*dc4f0af1Szrj  * it might get invoked several times.  Our compromise is to maintain an
598*dc4f0af1Szrj  * array of strings and cycle thru them with each invocation.  We make the
599*dc4f0af1Szrj  * array large enough to handle the above mentioned case.  The constant
600*dc4f0af1Szrj  * NUM_STRINGS defines the number of strings in this array:  we can tolerate
601*dc4f0af1Szrj  * up to NUM_STRINGS calls before we start overwriting old information.
602*dc4f0af1Szrj  * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer
603*dc4f0af1Szrj  * to convert the modulo operation into something quicker.  What a hack!
604*dc4f0af1Szrj  */
605*dc4f0af1Szrj 
606*dc4f0af1Szrj #define NUM_STRINGS 8
607*dc4f0af1Szrj 
608*dc4f0af1Szrj char *
format_k(long amt)609*dc4f0af1Szrj format_k(long amt)
610*dc4f0af1Szrj 
611*dc4f0af1Szrj {
612*dc4f0af1Szrj     static char retarray[NUM_STRINGS][16];
613*dc4f0af1Szrj     static int index = 0;
614*dc4f0af1Szrj     register char *ret;
615*dc4f0af1Szrj     register char tag = 'K';
616*dc4f0af1Szrj 
617*dc4f0af1Szrj     ret = retarray[index];
618*dc4f0af1Szrj     index = (index + 1) % NUM_STRINGS;
619*dc4f0af1Szrj 
620*dc4f0af1Szrj     if (amt >= 10000)
621*dc4f0af1Szrj     {
622*dc4f0af1Szrj 	amt = (amt + 512) / 1024;
623*dc4f0af1Szrj 	tag = 'M';
624*dc4f0af1Szrj 	if (amt >= 10000)
625*dc4f0af1Szrj 	{
626*dc4f0af1Szrj 	    amt = (amt + 512) / 1024;
627*dc4f0af1Szrj 	    tag = 'G';
628*dc4f0af1Szrj 	}
629*dc4f0af1Szrj     }
630*dc4f0af1Szrj 
631*dc4f0af1Szrj     snprintf(ret, sizeof(retarray[index])-1, "%ld%c", amt, tag);
632*dc4f0af1Szrj 
633*dc4f0af1Szrj     return(ret);
634*dc4f0af1Szrj }
635*dc4f0af1Szrj 
636*dc4f0af1Szrj /*
637*dc4f0af1Szrj  * Time keeping functions.
638*dc4f0af1Szrj  */
639*dc4f0af1Szrj 
640*dc4f0af1Szrj static struct timeval lasttime = { 0, 0 };
641*dc4f0af1Szrj static unsigned int elapsed_msecs = 0;
642*dc4f0af1Szrj 
643*dc4f0af1Szrj void
time_get(struct timeval * tv)644*dc4f0af1Szrj time_get(struct timeval *tv)
645*dc4f0af1Szrj 
646*dc4f0af1Szrj {
647*dc4f0af1Szrj     /* get the current time */
648*dc4f0af1Szrj #ifdef HAVE_GETTIMEOFDAY
649*dc4f0af1Szrj     gettimeofday(tv, NULL);
650*dc4f0af1Szrj #else
651*dc4f0af1Szrj     tv->tv_sec = (long)time(NULL);
652*dc4f0af1Szrj     tv->tv_usec = 0;
653*dc4f0af1Szrj #endif
654*dc4f0af1Szrj }
655*dc4f0af1Szrj 
656*dc4f0af1Szrj void
time_mark(struct timeval * tv)657*dc4f0af1Szrj time_mark(struct timeval *tv)
658*dc4f0af1Szrj 
659*dc4f0af1Szrj {
660*dc4f0af1Szrj     struct timeval thistime;
661*dc4f0af1Szrj     struct timeval timediff;
662*dc4f0af1Szrj 
663*dc4f0af1Szrj     /* if the caller didnt provide one then use our own */
664*dc4f0af1Szrj     if (tv == NULL)
665*dc4f0af1Szrj     {
666*dc4f0af1Szrj 	tv = &thistime;
667*dc4f0af1Szrj     }
668*dc4f0af1Szrj 
669*dc4f0af1Szrj     /* get the current time */
670*dc4f0af1Szrj #ifdef HAVE_GETTIMEOFDAY
671*dc4f0af1Szrj     gettimeofday(tv, NULL);
672*dc4f0af1Szrj #else
673*dc4f0af1Szrj     tv->tv_sec = (long)time(NULL);
674*dc4f0af1Szrj     tv->tv_usec = 0;
675*dc4f0af1Szrj #endif
676*dc4f0af1Szrj 
677*dc4f0af1Szrj     /* calculate the difference */
678*dc4f0af1Szrj     timediff.tv_sec = tv->tv_sec - lasttime.tv_sec;
679*dc4f0af1Szrj     timediff.tv_usec = tv->tv_usec - lasttime.tv_usec;
680*dc4f0af1Szrj     if (timediff.tv_usec < 0) {
681*dc4f0af1Szrj 	timediff.tv_sec--;
682*dc4f0af1Szrj 	timediff.tv_usec += 1000000;
683*dc4f0af1Szrj     }
684*dc4f0af1Szrj 
685*dc4f0af1Szrj     /* convert to milliseconds */
686*dc4f0af1Szrj     elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
687*dc4f0af1Szrj     if (elapsed_msecs == 0)
688*dc4f0af1Szrj     {
689*dc4f0af1Szrj 	elapsed_msecs = 1;
690*dc4f0af1Szrj     }
691*dc4f0af1Szrj 
692*dc4f0af1Szrj     /* save for next time */
693*dc4f0af1Szrj     lasttime = *tv;
694*dc4f0af1Szrj }
695*dc4f0af1Szrj 
696*dc4f0af1Szrj unsigned int
time_elapsed()697*dc4f0af1Szrj time_elapsed()
698*dc4f0af1Szrj 
699*dc4f0af1Szrj {
700*dc4f0af1Szrj     return elapsed_msecs;
701*dc4f0af1Szrj }
702*dc4f0af1Szrj 
703*dc4f0af1Szrj unsigned int
diff_per_second(unsigned int x,unsigned int y)704*dc4f0af1Szrj diff_per_second(unsigned int x, unsigned int y)
705*dc4f0af1Szrj 
706*dc4f0af1Szrj {
707*dc4f0af1Szrj     return (y > x ? UINT_MAX - y + x + 1 : x - y) * 1000 / elapsed_msecs;
708*dc4f0af1Szrj }
709*dc4f0af1Szrj 
710*dc4f0af1Szrj static int debug_on = 0;
711*dc4f0af1Szrj 
712*dc4f0af1Szrj #ifdef DEBUG
713*dc4f0af1Szrj FILE *debugfile;
714*dc4f0af1Szrj #endif
715*dc4f0af1Szrj 
716*dc4f0af1Szrj void
debug_set(int i)717*dc4f0af1Szrj debug_set(int i)
718*dc4f0af1Szrj 
719*dc4f0af1Szrj {
720*dc4f0af1Szrj     debug_on = i;
721*dc4f0af1Szrj #ifdef DEBUG
722*dc4f0af1Szrj     debugfile = fopen("/tmp/top.debug", "w");
723*dc4f0af1Szrj #endif
724*dc4f0af1Szrj }
725*dc4f0af1Szrj 
726*dc4f0af1Szrj #ifdef DEBUG
727*dc4f0af1Szrj void
xdprintf(char * fmt,...)728*dc4f0af1Szrj xdprintf(char *fmt, ...)
729*dc4f0af1Szrj 
730*dc4f0af1Szrj {
731*dc4f0af1Szrj     va_list argp;
732*dc4f0af1Szrj 
733*dc4f0af1Szrj     va_start(argp, fmt);
734*dc4f0af1Szrj 
735*dc4f0af1Szrj     if (debug_on)
736*dc4f0af1Szrj     {
737*dc4f0af1Szrj 	vfprintf(debugfile, fmt, argp);
738*dc4f0af1Szrj 	fflush(debugfile);
739*dc4f0af1Szrj     }
740*dc4f0af1Szrj 
741*dc4f0af1Szrj     va_end(argp);
742*dc4f0af1Szrj }
743*dc4f0af1Szrj #endif
744*dc4f0af1Szrj 
745