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