home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / utils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  9.5 KB  |  418 lines

  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.  
  19. int atoiwi(str)
  20.  
  21. char *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.  
  60. char *itoa(val)
  61.  
  62. register 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.  
  91. char *itoa7(val)
  92.  
  93. register 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.  
  125. int digits(val)
  126.  
  127. int 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.  
  145. char *strecpy(to, from)
  146.  
  147. register char *to;
  148. register char *from;
  149.  
  150. {
  151.     while ((*to++ = *from++) != '\0');
  152.     return(--to);
  153. }
  154.  
  155. /*
  156.  * argparse(line, cntp) - parse arguments in string "line", separating them
  157.  *    put into an argv-like array, and setting *cntp to the number of
  158.  *    arguments encountered.  This is a simple parser that doesn't understand
  159.  *    squat about quotes.
  160.  */
  161.  
  162. char **argparse(line, cntp)
  163.  
  164. char *line;
  165. int *cntp;
  166.  
  167. {
  168.     register char *from;
  169.     register char *to;
  170.     register int cnt;
  171.     register int ch;
  172.     int length;
  173.     int lastch;
  174.     register char **argv;
  175.     char **argarray;
  176.     char *args;
  177.  
  178.     /* unfortunately, the only real way to do this is to go thru the
  179.        input string twice. */
  180.  
  181.     /* step thru the string counting the white space sections */
  182.     from = line;
  183.     lastch = cnt = length = 0;
  184.     while ((ch = *from++) != '\0')
  185.     {
  186.     length++;
  187.     if (ch == ' ' && lastch != ' ')
  188.     {
  189.         cnt++;
  190.     }
  191.     lastch = ch;
  192.     }
  193.  
  194.     /* add three to the count:  one for the initial "dummy" argument,
  195.        one for the last argument and one for NULL */
  196.     cnt += 3;
  197.  
  198.     /* allocate a char * array to hold the pointers */
  199.     argarray = (char **)malloc(cnt * sizeof(char *));
  200.  
  201.     /* allocate another array to hold the strings themselves */
  202.     args = (char *)malloc(length+2);
  203.  
  204.     /* initialization for main loop */
  205.     from = line;
  206.     to = args;
  207.     argv = argarray;
  208.     lastch = '\0';
  209.  
  210.     /* create a dummy argument to keep getopt happy */
  211.     *argv++ = to;
  212.     *to++ = '\0';
  213.     cnt = 2;
  214.  
  215.     /* now build argv while copying characters */
  216.     *argv++ = to;
  217.     while ((ch = *from++) != '\0')
  218.     {
  219.     if (ch != ' ')
  220.     {
  221.         if (lastch == ' ')
  222.         {
  223.         *to++ = '\0';
  224.         *argv++ = to;
  225.         cnt++;
  226.         }
  227.         *to++ = ch;
  228.     }
  229.     lastch = ch;
  230.     }
  231.  
  232.     /* set cntp and return the allocated array */
  233.     *cntp = cnt;
  234.     return(argarray);
  235. }
  236.  
  237. /*
  238.  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
  239.  *    between array "old" and "new", putting the percentages i "out".
  240.  *    "cnt" is size of each array and "diffs" is used for scratch space.
  241.  *    The array "old" is updated on each call.
  242.  *    The routine assumes modulo arithmetic.  This function is especially
  243.  *    useful on BSD mchines for calculating cpu state percentages.
  244.  */
  245.  
  246. long percentages(cnt, out, new, old, diffs)
  247.  
  248. int cnt;
  249. int *out;
  250. register long *new;
  251. register long *old;
  252. long *diffs;
  253.  
  254. {
  255.     register int i;
  256.     register long change;
  257.     register long total_change;
  258.     register long *dp;
  259.     long half_total;
  260.  
  261.     /* initialization */
  262.     total_change = 0;
  263.     dp = diffs;
  264.  
  265.     /* calculate changes for each state and the overall change */
  266.     for (i = 0; i < cnt; i++)
  267.     {
  268.     if ((change = *new - *old) < 0)
  269.     {
  270.         /* this only happens when the counter wraps */
  271.         change = (int)
  272.         ((unsigned long)*new-(unsigned long)*old);
  273.     }
  274.     total_change += (*dp++ = change);
  275.     *old++ = *new++;
  276.     }
  277.  
  278.     /* calculate percentages based on overall change, rounding up */
  279.     half_total = total_change / 2l;
  280.     for (i = 0; i < cnt; i++)
  281.     {
  282.     *out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
  283.     }
  284.  
  285.     /* return the total in case the caller wants to use it */
  286.     return(total_change);
  287. }
  288.  
  289. /*
  290.  * errmsg(errnum) - return an error message string appropriate to the
  291.  *           error number "errnum".  This is a substitute for the System V
  292.  *           function "strerror" with one important difference:  the string
  293.  *           returned by this function does NOT end in a newline!
  294.  *           N.B.:  there appears to be no reliable way to determine if
  295.  *           "strerror" exists at compile time, so I make do by providing
  296.  *           something of similar functionality.
  297.  */
  298.  
  299. /* externs referenced by errmsg */
  300.  
  301. extern char *sys_errlist[];
  302. extern int sys_nerr;
  303.  
  304. char *errmsg(errnum)
  305.  
  306. int errnum;
  307.  
  308. {
  309.     if (errnum > 0 && errnum < sys_nerr)
  310.     {
  311.     return(sys_errlist[errnum]);
  312.     }
  313.     return("No error");
  314. }
  315.  
  316. /* format_time(seconds) - format number of seconds into a suitable
  317.  *        display that will fit within 6 characters.  Note that this
  318.  *        routine builds its string in a static area.  If it needs
  319.  *        to be called more than once without overwriting previous data,
  320.  *        then we will need to adopt a technique similar to the
  321.  *        one used for format_k.
  322.  */
  323.  
  324. /* Explanation:
  325.    We want to keep the output within 6 characters.  For low values we use
  326.    the format mm:ss.  For values that exceed 999:59, we switch to a format
  327.    that displays hours and fractions:  hhh.tH.  For values that exceed
  328.    999.9, we use hhhh.t and drop the "H" designator.  For values that
  329.    exceed 9999.9, we use "???".
  330.  */
  331.  
  332. char *format_time(seconds)
  333.  
  334. long seconds;
  335.  
  336. {
  337.     register int value;
  338.     register int digit;
  339.     register char *ptr;
  340.     static char result[10];
  341.  
  342.     /* sanity protection */
  343.     if (seconds < 0 || seconds > (99999l * 360l))
  344.     {
  345.     strcpy(result, "   ???");
  346.     }
  347.     else if (seconds >= (1000l * 60l))
  348.     {
  349.     /* alternate (slow) method displaying hours and tenths */
  350.     sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l));
  351.  
  352.     /* It is possible that the sprintf took more than 6 characters.
  353.        If so, then the "H" appears as result[6].  If not, then there
  354.        is a \0 in result[6].  Either way, it is safe to step on.
  355.      */
  356.     result[6] = '\0';
  357.     }
  358.     else
  359.     {
  360.     /* standard method produces MMM:SS */
  361.     /* we avoid printf as must as possible to make this quick */
  362.     sprintf(result, "%3d:%02d", seconds / 60l, seconds % 60l);
  363.     }
  364.     return(result);
  365. }
  366.  
  367. /*
  368.  * format_k(amt) - format a kilobyte memory value, returning a string
  369.  *        suitable for display.  Returns a pointer to a static
  370.  *        area that changes each call.  "amt" is converted to a
  371.  *        string with a trailing "K".  If "amt" is 10000 or greater,
  372.  *        then it is formatted as megabytes (rounded) with a
  373.  *        trailing "M".
  374.  */
  375.  
  376. /*
  377.  * Compromise time.  We need to return a string, but we don't want the
  378.  * caller to have to worry about freeing a dynamically allocated string.
  379.  * Unfortunately, we can't just return a pointer to a static area as one
  380.  * of the common uses of this function is in a large call to sprintf where
  381.  * it might get invoked several times.  Our compromise is to maintain an
  382.  * array of strings and cycle thru them with each invocation.  We make the
  383.  * array large enough to handle the above mentioned case.  The constant
  384.  * NUM_STRINGS defines the number of strings in this array:  we can tolerate
  385.  * up to NUM_STRINGS calls before we start overwriting old information.
  386.  * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer
  387.  * to convert the modulo operation into something quicker.  What a hack!
  388.  */
  389.  
  390. #define NUM_STRINGS 8
  391.  
  392. char *format_k(amt)
  393.  
  394. int amt;
  395.  
  396. {
  397.     static char retarray[NUM_STRINGS][16];
  398.     static int index = 0;
  399.     register char *p;
  400.     register char *ret;
  401.     register char tag = 'K';
  402.  
  403.     p = ret = retarray[index];
  404.     index = (index + 1) % NUM_STRINGS;
  405.  
  406.     if (amt >= 10000)
  407.     {
  408.     amt = (amt + 500) / 1000;
  409.     tag = 'M';
  410.     }
  411.  
  412.     p = strecpy(p, itoa(amt));
  413.     *p++ = tag;
  414.     *p = '\0';
  415.  
  416.     return(ret);
  417. }
  418.