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

Revision 9084, 10.0 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9083, 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" with one important difference:  the string
324 *           returned by this function does NOT end in a newline!
325 *           N.B.:  there appears to be no reliable way to determine if
326 *           "strerror" exists at compile time, so I make do by providing
327 *           something of similar functionality.
328 */
329
330/* externs referenced by errmsg */
331
332extern char *sys_errlist[];
333extern int sys_nerr;
334
335char *errmsg(errnum)
336
337int errnum;
338
339{
340    if (errnum > 0 && errnum < sys_nerr)
341    {
342        return(sys_errlist[errnum]);
343    }
344    return("No error");
345}
346
347/* format_time(seconds) - format number of seconds into a suitable
348 *              display that will fit within 6 characters.  Note that this
349 *              routine builds its string in a static area.  If it needs
350 *              to be called more than once without overwriting previous data,
351 *              then we will need to adopt a technique similar to the
352 *              one used for format_k.
353 */
354
355/* Explanation:
356   We want to keep the output within 6 characters.  For low values we use
357   the format mm:ss.  For values that exceed 999:59, we switch to a format
358   that displays hours and fractions:  hhh.tH.  For values that exceed
359   999.9, we use hhhh.t and drop the "H" designator.  For values that
360   exceed 9999.9, we use "???".
361 */
362
363char *format_time(seconds)
364
365long seconds;
366
367{
368    register int value;
369    register int digit;
370    register char *ptr;
371    static char result[10];
372
373    /* sanity protection */
374    if (seconds < 0 || seconds > (99999l * 360l))
375    {
376        strcpy(result, "   ???");
377    }
378    else if (seconds >= (1000l * 60l))
379    {
380        /* alternate (slow) method displaying hours and tenths */
381        sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l));
382
383        /* It is possible that the sprintf took more than 6 characters.
384           If so, then the "H" appears as result[6].  If not, then there
385           is a \0 in result[6].  Either way, it is safe to step on.
386         */
387        result[6] = '\0';
388    }
389    else
390    {
391        /* standard method produces MMM:SS */
392        /* we avoid printf as must as possible to make this quick */
393        sprintf(result, "%3d:%02d", seconds / 60l, seconds % 60l);
394    }
395    return(result);
396}
397
398/*
399 * format_k(amt) - format a kilobyte memory value, returning a string
400 *              suitable for display.  Returns a pointer to a static
401 *              area that changes each call.  "amt" is converted to a
402 *              string with a trailing "K".  If "amt" is 10000 or greater,
403 *              then it is formatted as megabytes (rounded) with a
404 *              trailing "M".
405 */
406
407/*
408 * Compromise time.  We need to return a string, but we don't want the
409 * caller to have to worry about freeing a dynamically allocated string.
410 * Unfortunately, we can't just return a pointer to a static area as one
411 * of the common uses of this function is in a large call to sprintf where
412 * it might get invoked several times.  Our compromise is to maintain an
413 * array of strings and cycle thru them with each invocation.  We make the
414 * array large enough to handle the above mentioned case.  The constant
415 * NUM_STRINGS defines the number of strings in this array:  we can tolerate
416 * up to NUM_STRINGS calls before we start overwriting old information.
417 * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer
418 * to convert the modulo operation into something quicker.  What a hack!
419 */
420
421#define NUM_STRINGS 8
422
423char *format_k(amt)
424
425int amt;
426
427{
428    static char retarray[NUM_STRINGS][16];
429    static int index = 0;
430    register char *p;
431    register char *ret;
432    register char tag = 'K';
433
434    p = ret = retarray[index];
435    index = (index + 1) % NUM_STRINGS;
436
437    if (amt >= 10000)
438    {
439        amt = (amt + 512) / 1024;
440        tag = 'M';
441        if (amt >= 10000)
442        {
443            amt = (amt + 512) / 1024;
444            tag = 'G';
445        }
446    }
447
448    p = strecpy(p, itoa(amt));
449    *p++ = tag;
450    *p = '\0';
451
452    return(ret);
453}
Note: See TracBrowser for help on using the repository browser.