[BACK]Return to utils.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / top

Annotation of src/usr.bin/top/utils.c, Revision 1.1

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