libm: Fix typos in Makefile comments.
[dragonfly.git] / contrib / top / utils.c
1 /*
2  *  Top users/processes display for Unix
3  *  Version 3
4  *
5  *  This program may be freely redistributed,
6  *  but this entire comment MUST remain intact.
7  *
8  *  Copyright (c) 1984, 1989, William LeFebvre, Rice University
9  *  Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
10  *
11  * $FreeBSD: src/contrib/top/utils.c,v 1.3.6.1 2002/08/11 17:09:25 dwmalone Exp $
12  * $DragonFly: src/contrib/top/utils.c,v 1.3 2003/07/11 23:33:24 dillon Exp $
13  */
14
15 /*
16  *  This file contains various handy utilities used by top.
17  */
18
19 #include "top.h"
20 #include "os.h"
21 #include "utils.h"
22
23 int
24 atoiwi(const char *str)
25 {
26     int len;
27
28     len = strlen(str);
29     if (len != 0)
30     {
31         if (strncmp(str, "infinity", len) == 0 ||
32             strncmp(str, "all",      len) == 0 ||
33             strncmp(str, "maximum",  len) == 0)
34         {
35             return(Infinity);
36         }
37         else if (str[0] == '-')
38         {
39             return(Invalid);
40         }
41         else
42         {
43             return(atoi(str));
44         }
45     }
46     return(0);
47 }
48
49 /*
50  *  ltoa - convert integer (decimal) to ascii string for positive numbers
51  *         only (we don't bother with negative numbers since we know we
52  *         don't use them).
53  */
54 char *
55 ltoa(long val)
56 {
57     char *ptr;
58     static char buffer[32];
59
60     ptr = buffer + sizeof(buffer);
61     *--ptr = '\0';
62     if (val == 0)
63     {
64         *--ptr = '0';
65     }
66     else while (val != 0)
67     {
68         *--ptr = (val % 10) + '0';
69         val /= 10;
70     }
71     return(ptr);
72 }
73
74 /*
75  *  ltoa7(val) - like ltoa, except the number is right justified in a 7
76  *      character field.  This code is a duplication of ltoa instead of
77  *      a front end to a more general routine for efficiency.
78  */
79
80 char *
81 ltoa7(long val)
82 {
83     char *ptr;
84     static char buffer[32];     /* result is built here */
85                                 /* 16 is sufficient since the largest number
86                                    we will ever convert will be 2^32-1,
87                                    which is 10 digits. */
88
89     ptr = buffer + sizeof(buffer);
90     *--ptr = '\0';
91     if (val == 0)
92     {
93         *--ptr = '0';
94     }
95     else while (val != 0)
96     {
97         *--ptr = (val % 10) + '0';
98         val /= 10;
99     }
100     while (ptr > buffer + sizeof(buffer) - 7)
101     {
102         *--ptr = ' ';
103     }
104     return(ptr);
105 }
106
107 /*
108  *  digits(val) - return number of decimal digits in val.  Only works for
109  *      positive numbers.  If val <= 0 then digits(val) == 0.
110  */
111
112 int
113 digits(long val)
114 {
115     int cnt = 0;
116
117     while (val > 0)
118     {
119         cnt++;
120         val /= 10;
121     }
122     return(cnt);
123 }
124
125 /*
126  *  strecpy(to, from) - copy string "from" into "to" and return a pointer
127  *      to the END of the string "to".
128  */
129
130 char *
131 strecpy(char *to, const char *from)
132 {
133     while ((*to++ = *from++) != '\0');
134     return(--to);
135 }
136
137 /*
138  * string_index(string, array) - find string in array and return index
139  */
140
141 int
142 string_index(char *string, const char **array)
143 {
144     register int i = 0;
145
146     while (*array != NULL)
147     {
148         if (strcmp(string, *array) == 0)
149         {
150             return(i);
151         }
152         array++;
153         i++;
154     }
155     return(-1);
156 }
157
158 /*
159  * argparse(line, cntp) - parse arguments in string "line", separating them
160  *      out into an argv-like array, and setting *cntp to the number of
161  *      arguments encountered.  This is a simple parser that doesn't understand
162  *      squat about quotes.
163  */
164
165 char **
166 argparse(char *line, int *cntp)
167 {
168     char *from;
169     char *to;
170     int cnt;
171     int ch;
172     int length;
173     int lastch;
174     register char **argv;
175     char **argarray;
176     char *args;
177
178     /* unfortunately, the only real way to do this is to go thru the
179        input string twice. */
180
181     /* step thru the string counting the white space sections */
182     from = line;
183     lastch = cnt = length = 0;
184     while ((ch = *from++) != '\0')
185     {
186         length++;
187         if (ch == ' ' && lastch != ' ')
188         {
189             cnt++;
190         }
191         lastch = ch;
192     }
193
194     /* add three to the count:  one for the initial "dummy" argument,
195        one for the last argument and one for NULL */
196     cnt += 3;
197
198     /* allocate a char * array to hold the pointers */
199     argarray = (char **)malloc(cnt * sizeof(char *));
200
201     /* allocate another array to hold the strings themselves */
202     args = (char *)malloc(length+2);
203
204     /* initialization for main loop */
205     from = line;
206     to = args;
207     argv = argarray;
208     lastch = '\0';
209
210     /* create a dummy argument to keep getopt happy */
211     *argv++ = to;
212     *to++ = '\0';
213     cnt = 2;
214
215     /* now build argv while copying characters */
216     *argv++ = to;
217     while ((ch = *from++) != '\0')
218     {
219         if (ch != ' ')
220         {
221             if (lastch == ' ')
222             {
223                 *to++ = '\0';
224                 *argv++ = to;
225                 cnt++;
226             }
227             *to++ = ch;
228         }
229         lastch = ch;
230     }
231     *to++ = '\0';
232
233     /* set cntp and return the allocated array */
234     *cntp = cnt;
235     return(argarray);
236 }
237
238 /*
239  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
240  *      between array "old" and "new", putting the percentages i "out".
241  *      "cnt" is size of each array and "diffs" is used for scratch space.
242  *      The array "old" is updated on each call.
243  *      The routine assumes modulo arithmetic.  This function is especially
244  *      useful on BSD mchines for calculating cpu state percentages.
245  */
246
247 long
248 percentages(int cnt, int *out, long *new, long *old, long *diffs)
249 {
250     register int i;
251     register long change;
252     register long total_change;
253     register long *dp;
254     long half_total;
255
256     /* initialization */
257     total_change = 0;
258     dp = diffs;
259
260     /* calculate changes for each state and the overall change */
261     for (i = 0; i < cnt; i++)
262     {
263         if ((change = *new - *old) < 0)
264         {
265             /* this only happens when the counter wraps */
266             change = (int)
267                 ((unsigned long)*new-(unsigned long)*old);
268         }
269         total_change += (*dp++ = change);
270         *old++ = *new++;
271     }
272
273     /* avoid divide by zero potential */
274     if (total_change == 0)
275     {
276         total_change = 1;
277     }
278
279     /* calculate percentages based on overall change, rounding up */
280     half_total = total_change / 2l;
281
282     /* Do not divide by 0. Causes Floating point exception */
283     if(total_change) {
284         for (i = 0; i < cnt; i++)
285         {
286           *out++ = (int)((*diffs++ * 1000LL + half_total) / total_change);
287         }
288     }
289
290     /* return the total in case the caller wants to use it */
291     return(total_change);
292 }
293
294 /*
295  * errmsg(errnum) - return an error message string appropriate to the
296  *           error number "errnum".  This is a substitute for the System V
297  *           function "strerror".  There appears to be no reliable way to
298  *           determine if "strerror" exists at compile time, so I make do
299  *           by providing something of similar functionality.  For those
300  *           systems that have strerror and NOT errlist, define
301  *           -DHAVE_STRERROR in the module file and this function will
302  *           use strerror.
303  */
304
305 /* externs referenced by errmsg */
306
307 #ifndef HAVE_STRERROR
308 #ifndef SYS_ERRLIST_DECLARED
309 #define SYS_ERRLIST_DECLARED
310 extern char *sys_errlist[];
311 #endif
312
313 extern int sys_nerr;
314 #endif
315
316 const char *
317 errmsg(int errnum)
318 {
319 #ifdef HAVE_STRERROR
320     char *msg = strerror(errnum);
321     if (msg != NULL)
322     {
323         return msg;
324     }
325 #else
326     if (errnum > 0 && errnum < sys_nerr)
327     {
328         return((char *)sys_errlist[errnum]);
329     }
330 #endif
331     return("No error");
332 }
333
334 /* format_time(seconds) - format number of seconds into a suitable
335  *              display that will fit within 6 characters.  Note that this
336  *              routine builds its string in a static area.  If it needs
337  *              to be called more than once without overwriting previous data,
338  *              then we will need to adopt a technique similar to the
339  *              one used for format_k.
340  */
341
342 /* Explanation:
343    We want to keep the output within 6 characters.  For low values we use
344    the format mm:ss.  For values that exceed 999:59, we switch to a format
345    that displays hours and fractions:  hhh.tH.  For values that exceed
346    999.9, we use hhhh.t and drop the "H" designator.  For values that
347    exceed 9999.9, we use "???".
348  */
349
350 char *format_time(long seconds)
351 {
352     static char result[10];
353
354     /* sanity protection */
355     if (seconds < 0 || seconds > (99999l * 360l))
356     {
357         strcpy(result, "   ???");
358     }
359     else if (seconds >= (1000l * 60l))
360     {
361         /* alternate (slow) method displaying hours and tenths */
362         sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l));
363
364         /* It is possible that the sprintf took more than 6 characters.
365            If so, then the "H" appears as result[6].  If not, then there
366            is a \0 in result[6].  Either way, it is safe to step on.
367          */
368         result[6] = '\0';
369     }
370     else
371     {
372         /* standard method produces MMM:SS */
373         /* we avoid printf as must as possible to make this quick */
374         snprintf(result, sizeof(result), "%3ld:%02ld",
375             (long)(seconds / 60), (long)(seconds % 60));
376     }
377     return(result);
378 }
379
380 /*
381  * format_k(amt) - format a kilobyte memory value, returning a string
382  *              suitable for display.  Returns a pointer to a static
383  *              area that changes each call.  "amt" is converted to a
384  *              string with a trailing "K".  If "amt" is 10000 or greater,
385  *              then it is formatted as megabytes (rounded) with a
386  *              trailing "M".
387  */
388
389 /*
390  * Compromise time.  We need to return a string, but we don't want the
391  * caller to have to worry about freeing a dynamically allocated string.
392  * Unfortunately, we can't just return a pointer to a static area as one
393  * of the common uses of this function is in a large call to sprintf where
394  * it might get invoked several times.  Our compromise is to maintain an
395  * array of strings and cycle thru them with each invocation.  We make the
396  * array large enough to handle the above mentioned case.  The constant
397  * NUM_STRINGS defines the number of strings in this array:  we can tolerate
398  * up to NUM_STRINGS calls before we start overwriting old information.
399  * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer
400  * to convert the modulo operation into something quicker.  What a hack!
401  */
402
403 #define NUM_STRINGS 16
404
405 char *
406 format_k(long amt)
407 {
408     static char retarray[NUM_STRINGS][16];
409     static int xindex = 0;
410     char *p;
411     char *ret;
412     char tag = 'K';
413
414     p = ret = retarray[xindex];
415     xindex = (xindex + 1) % NUM_STRINGS;
416
417     if (amt >= 10000)
418     {
419         amt = (amt + 512) / 1024;
420         tag = 'M';
421         if (amt >= 10000)
422         {
423             amt = (amt + 512) / 1024;
424             tag = 'G';
425         }
426     }
427
428     p = strecpy(p, ltoa(amt));
429     *p++ = tag;
430     *p = '\0';
431
432     return(ret);
433 }
434
435 char *
436 format_k2(long amt)
437 {
438     static char retarray[NUM_STRINGS][32];
439     static int xindex = 0;
440     char *p;
441     char *ret;
442     char tag = 'K';
443
444     p = ret = retarray[xindex];
445     xindex = (xindex + 1) % NUM_STRINGS;
446
447     if (amt >= 100000)
448     {
449         amt = (amt + 512) / 1024;
450         tag = 'M';
451         if (amt >= 100000)
452         {
453             amt = (amt + 512) / 1024;
454             tag = 'G';
455         }
456     }
457     p = strecpy(p, ltoa(amt));
458     *p++ = tag;
459     *p = '\0';
460
461     return(ret);
462 }