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: }