source: trunk/third/top/utils.c @ 16185

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