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