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