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