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