version 1.9, 2003/06/12 22:30:23 |
version 1.10, 2003/06/12 23:09:30 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
|
|
/* |
/* |
* Top users/processes display for Unix |
* Top users/processes display for Unix |
|
|
int |
int |
atoiwi(char *str) |
atoiwi(char *str) |
{ |
{ |
int len; |
int len; |
|
|
len = strlen(str); |
len = strlen(str); |
if (len != 0) |
if (len != 0) { |
{ |
if (strncmp(str, "infinity", len) == 0 || |
if (strncmp(str, "infinity", len) == 0 || |
strncmp(str, "all", len) == 0 || |
strncmp(str, "all", len) == 0 || |
strncmp(str, "maximum", len) == 0) { |
strncmp(str, "maximum", len) == 0) |
return (Infinity); |
{ |
} else if (str[0] == '-') |
return(Infinity); |
return (Invalid); |
|
else |
|
return (atoi(str)); |
} |
} |
else if (str[0] == '-') |
return (0); |
{ |
|
return(Invalid); |
|
} |
|
else |
|
{ |
|
return(atoi(str)); |
|
} |
|
} |
|
return(0); |
|
} |
} |
|
|
/* |
/* |
* itoa - convert integer (decimal) to ascii string for positive numbers |
* itoa - convert integer (decimal) to ascii string for positive numbers |
* only (we don't bother with negative numbers since we know we |
* only (we don't bother with negative numbers since we know we |
* don't use them). |
* don't use them). |
*/ |
*/ |
|
|
/* |
|
* How do we know that 16 will suffice? |
|
* Because the biggest number that we will |
|
* ever convert will be 2^32-1, which is 10 |
|
* digits. |
|
*/ |
|
|
|
char * |
char * |
itoa(int val) |
itoa(int val) |
{ |
{ |
char *ptr; |
static char buffer[16]; /* result is built here */ |
static char buffer[16]; /* result is built here */ |
char *ptr; |
/* 16 is sufficient since the largest number |
|
we will ever convert will be 2^32-1, |
|
which is 10 digits. */ |
|
|
|
ptr = buffer + sizeof(buffer); |
/* |
*--ptr = '\0'; |
* 16 is sufficient since the largest number we will ever convert |
if (val == 0) |
* will be 2^32-1, which is 10 digits. |
{ |
*/ |
*--ptr = '0'; |
ptr = buffer + sizeof(buffer); |
} |
*--ptr = '\0'; |
else while (val != 0) |
if (val == 0) { |
{ |
*--ptr = '0'; |
*--ptr = (val % 10) + '0'; |
} else { |
val /= 10; |
while (val != 0) { |
} |
*--ptr = (val % 10) + '0'; |
return(ptr); |
val /= 10; |
|
} |
|
} |
|
return (ptr); |
} |
} |
|
|
/* |
/* |
* itoa7(val) - like itoa, except the number is right justified in a 7 |
* itoa7(val) - like itoa, except the number is right justified in a 7 |
* character field. This code is a duplication of itoa instead of |
* character field. This code is a duplication of itoa instead of |
* a front end to a more general routine for efficiency. |
* a front end to a more general routine for efficiency. |
*/ |
*/ |
|
|
char * |
char * |
itoa7(int val) |
itoa7(int val) |
{ |
{ |
char *ptr; |
static char buffer[25]; /* result is built here */ |
static char buffer[25]; /* result is built here */ |
char *ptr; |
|
|
ptr = buffer + sizeof(buffer); |
ptr = buffer + sizeof(buffer); |
*--ptr = '\0'; |
*--ptr = '\0'; |
if (val == 0) |
if (val == 0) { |
{ |
*--ptr = '0'; |
*--ptr = '0'; |
} else { |
} |
while (val != 0) { |
else while (val != 0) |
*--ptr = (val % 10) + '0'; |
{ |
val /= 10; |
*--ptr = (val % 10) + '0'; |
} |
val /= 10; |
} |
} |
while (ptr > buffer + sizeof(buffer) - 7) |
while (ptr > buffer + sizeof(buffer) - 7) |
*--ptr = ' '; |
{ |
return (ptr); |
*--ptr = ' '; |
|
} |
|
return(ptr); |
|
} |
} |
|
|
/* |
/* |
* digits(val) - return number of decimal digits in val. Only works for |
* digits(val) - return number of decimal digits in val. Only works for |
* positive numbers. If val <= 0 then digits(val) == 0. |
* positive numbers. If val <= 0 then digits(val) == 0. |
*/ |
*/ |
|
|
int |
int |
digits(int val) |
digits(int val) |
{ |
{ |
int cnt = 0; |
int cnt = 0; |
|
|
while (val > 0) |
while (val > 0) { |
{ |
cnt++; |
cnt++; |
val /= 10; |
val /= 10; |
} |
} |
return (cnt); |
return(cnt); |
|
} |
} |
|
|
/* |
/* |
* strecpy(to, from) - copy string "from" into "to" and return a pointer |
* strecpy(to, from) - copy string "from" into "to" and return a pointer |
* to the END of the string "to". |
* to the END of the string "to". |
*/ |
*/ |
|
|
char * |
char * |
strecpy(char *to, char *from) |
strecpy(char *to, char *from) |
{ |
{ |
while ((*to++ = *from++) != '\0'); |
while ((*to++ = *from++) != '\0') |
return(--to); |
; |
|
return (--to); |
} |
} |
|
|
/* |
/* |
* string_index(string, array) - find string in array and return index |
* string_index(string, array) - find string in array and return index |
*/ |
*/ |
|
|
int |
int |
string_index(char *string, char **array) |
string_index(char *string, char **array) |
{ |
{ |
int i = 0; |
int i = 0; |
|
|
while (*array != NULL) |
while (*array != NULL) { |
{ |
if (strcmp(string, *array) == 0) |
if (strcmp(string, *array) == 0) |
return (i); |
{ |
array++; |
return(i); |
i++; |
} |
} |
array++; |
return (-1); |
i++; |
|
} |
|
return(-1); |
|
} |
} |
|
|
/* |
/* |
* argparse(line, cntp) - parse arguments in string "line", separating them |
* argparse(line, cntp) - parse arguments in string "line", separating them |
* out into an argv-like array, and setting *cntp to the number of |
* out into an argv-like array, and setting *cntp to the number of |
* arguments encountered. This is a simple parser that doesn't understand |
* arguments encountered. This is a simple parser that doesn't understand |
* squat about quotes. |
* squat about quotes. |
*/ |
*/ |
|
|
char ** |
char ** |
argparse(char *line, int *cntp) |
argparse(char *line, int *cntp) |
{ |
{ |
char *from; |
char **argv, **argarray, *args, *from, *to; |
char *to; |
int cnt, ch, length, lastch; |
int cnt; |
|
int ch; |
|
int length; |
|
int lastch; |
|
char **argv; |
|
char **argarray; |
|
char *args; |
|
|
|
/* unfortunately, the only real way to do this is to go thru the |
/* |
input string twice. */ |
* unfortunately, the only real way to do this is to go thru the |
|
* input string twice. |
|
*/ |
|
|
/* step thru the string counting the white space sections */ |
/* step thru the string counting the white space sections */ |
from = line; |
from = line; |
lastch = cnt = length = 0; |
lastch = cnt = length = 0; |
while ((ch = *from++) != '\0') |
while ((ch = *from++) != '\0') { |
{ |
length++; |
length++; |
if (ch == ' ' && lastch != ' ') |
if (ch == ' ' && lastch != ' ') |
cnt++; |
{ |
lastch = ch; |
cnt++; |
|
} |
} |
lastch = ch; |
|
} |
|
|
|
/* add three to the count: one for the initial "dummy" argument, |
/* |
one for the last argument and one for NULL */ |
* add three to the count: one for the initial "dummy" argument, one |
cnt += 3; |
* for the last argument and one for NULL |
|
*/ |
|
cnt += 3; |
|
|
/* allocate a char * array to hold the pointers */ |
/* allocate a char * array to hold the pointers */ |
argarray = (char **)malloc(cnt * sizeof(char *)); |
argarray = (char **) malloc(cnt * sizeof(char *)); |
|
|
/* allocate another array to hold the strings themselves */ |
/* allocate another array to hold the strings themselves */ |
args = (char *)malloc(length+2); |
args = (char *) malloc(length + 2); |
|
|
/* initialization for main loop */ |
/* initialization for main loop */ |
from = line; |
from = line; |
to = args; |
to = args; |
argv = argarray; |
argv = argarray; |
lastch = '\0'; |
lastch = '\0'; |
|
|
/* create a dummy argument to keep getopt happy */ |
/* create a dummy argument to keep getopt happy */ |
*argv++ = to; |
*argv++ = to; |
*to++ = '\0'; |
*to++ = '\0'; |
cnt = 2; |
cnt = 2; |
|
|
/* now build argv while copying characters */ |
/* now build argv while copying characters */ |
*argv++ = to; |
*argv++ = to; |
while ((ch = *from++) != '\0') |
while ((ch = *from++) != '\0') { |
{ |
if (ch != ' ') { |
if (ch != ' ') |
if (lastch == ' ') { |
{ |
*to++ = '\0'; |
if (lastch == ' ') |
*argv++ = to; |
{ |
cnt++; |
*to++ = '\0'; |
} |
*argv++ = to; |
*to++ = ch; |
cnt++; |
} |
} |
lastch = ch; |
*to++ = ch; |
|
} |
} |
lastch = ch; |
*to++ = '\0'; |
} |
|
*to++ = '\0'; |
|
|
|
/* set cntp and return the allocated array */ |
/* set cntp and return the allocated array */ |
*cntp = cnt; |
*cntp = cnt; |
return(argarray); |
return (argarray); |
} |
} |
|
|
/* |
/* |
* percentages(cnt, out, new, old, diffs) - calculate percentage change |
* percentages(cnt, out, new, old, diffs) - calculate percentage change |
* between array "old" and "new", putting the percentages i "out". |
* between array "old" and "new", putting the percentages i "out". |
* "cnt" is size of each array and "diffs" is used for scratch space. |
* "cnt" is size of each array and "diffs" is used for scratch space. |
* The array "old" is updated on each call. |
* The array "old" is updated on each call. |
* The routine assumes modulo arithmetic. This function is especially |
* The routine assumes modulo arithmetic. This function is especially |
* useful on BSD mchines for calculating cpu state percentages. |
* useful on BSD mchines for calculating cpu state percentages. |
*/ |
*/ |
|
|
int |
int |
percentages(int cnt, int *out, long *new, long *old, long *diffs) |
percentages(int cnt, int *out, long *new, long *old, long *diffs) |
{ |
{ |
int i; |
long change, total_change, *dp, half_total; |
long change; |
int i; |
long total_change; |
|
long *dp; |
|
long half_total; |
|
|
|
/* initialization */ |
/* initialization */ |
total_change = 0; |
total_change = 0; |
dp = diffs; |
dp = diffs; |
|
|
/* calculate changes for each state and the overall change */ |
/* calculate changes for each state and the overall change */ |
for (i = 0; i < cnt; i++) |
for (i = 0; i < cnt; i++) { |
{ |
if ((change = *new - *old) < 0) { |
if ((change = *new - *old) < 0) |
/* this only happens when the counter wraps */ |
{ |
change = ((unsigned int)*new - (unsigned int)*old); |
/* this only happens when the counter wraps */ |
} |
change = ((unsigned int)*new-(unsigned int)*old); |
total_change += (*dp++ = change); |
|
*old++ = *new++; |
} |
} |
total_change += (*dp++ = change); |
|
*old++ = *new++; |
|
} |
|
|
|
/* avoid divide by zero potential */ |
/* avoid divide by zero potential */ |
if (total_change == 0) |
if (total_change == 0) |
{ |
total_change = 1; |
total_change = 1; |
|
} |
|
|
|
/* calculate percentages based on overall change, rounding up */ |
/* calculate percentages based on overall change, rounding up */ |
half_total = total_change / 2l; |
half_total = total_change / 2l; |
for (i = 0; i < cnt; i++) |
for (i = 0; i < cnt; i++) |
{ |
*out++ = ((*diffs++ * 1000 + half_total) / total_change); |
*out++ = ((*diffs++ * 1000 + half_total) / total_change); |
|
} |
|
|
|
/* return the total in case the caller wants to use it */ |
/* return the total in case the caller wants to use it */ |
return(total_change); |
return (total_change); |
} |
} |
|
|
/* format_time(seconds) - format number of seconds into a suitable |
/* |
* display that will fit within 6 characters. Note that this |
* format_time(seconds) - format number of seconds into a suitable display |
* routine builds its string in a static area. If it needs |
* that will fit within 6 characters. Note that this routine builds its |
* to be called more than once without overwriting previous data, |
* string in a static area. If it needs to be called more than once without |
* then we will need to adopt a technique similar to the |
* overwriting previous data, then we will need to adopt a technique similar |
* one used for format_k. |
* to the one used for format_k. |
*/ |
*/ |
|
|
/* Explanation: |
/* |
We want to keep the output within 6 characters. For low values we use |
* Explanation: We want to keep the output within 6 characters. For low |
the format mm:ss. For values that exceed 999:59, we switch to a format |
* values we use the format mm:ss. For values that exceed 999:59, we switch |
that displays hours and fractions: hhh.tH. For values that exceed |
* to a format that displays hours and fractions: hhh.tH. For values that |
999.9, we use hhhh.t and drop the "H" designator. For values that |
* exceed 999.9, we use hhhh.t and drop the "H" designator. For values that |
exceed 9999.9, we use "???". |
* exceed 9999.9, we use "???". |
*/ |
*/ |
|
|
char * |
char * |
format_time(time_t seconds) |
format_time(time_t seconds) |
{ |
{ |
static char result[10]; |
static char result[10]; |
|
|
/* sanity protection */ |
/* sanity protection */ |
if (seconds < 0 || seconds > (99999l * 360l)) |
if (seconds < 0 || seconds > (99999l * 360l)) { |
{ |
strlcpy(result, " ???", sizeof result); |
strlcpy(result, " ???", sizeof result); |
} else if (seconds >= (1000l * 60l)) { |
} |
/* alternate (slow) method displaying hours and tenths */ |
else if (seconds >= (1000l * 60l)) |
snprintf(result, sizeof(result), "%5.1fH", |
{ |
(double) seconds / (double) (60l * 60l)); |
/* alternate (slow) method displaying hours and tenths */ |
|
snprintf(result, sizeof(result), "%5.1fH", |
|
(double)seconds / (double)(60l * 60l)); |
|
|
|
/* It is possible that the snprintf took more than 6 characters. |
/* |
If so, then the "H" appears as result[6]. If not, then there |
* It is possible that the snprintf took more than 6 |
is a \0 in result[6]. Either way, it is safe to step on. |
* characters. If so, then the "H" appears as result[6]. If |
*/ |
* not, then there is a \0 in result[6]. Either way, it is |
result[6] = '\0'; |
* safe to step on. |
} |
*/ |
else |
result[6] = '\0'; |
{ |
} else { |
/* standard method produces MMM:SS */ |
/* standard method produces MMM:SS */ |
/* we avoid printf as must as possible to make this quick */ |
/* we avoid printf as must as possible to make this quick */ |
snprintf(result, sizeof(result), "%3d:%02d", seconds / 60, |
snprintf(result, sizeof(result), "%3d:%02d", seconds / 60, |
seconds % 60); |
seconds % 60); |
} |
} |
return(result); |
return (result); |
} |
} |
|
|
/* |
/* |
* format_k(amt) - format a kilobyte memory value, returning a string |
* format_k(amt) - format a kilobyte memory value, returning a string |
* suitable for display. Returns a pointer to a static |
* suitable for display. Returns a pointer to a static |
* area that changes each call. "amt" is converted to a |
* area that changes each call. "amt" is converted to a |
* string with a trailing "K". If "amt" is 10000 or greater, |
* string with a trailing "K". If "amt" is 10000 or greater, |
* then it is formatted as megabytes (rounded) with a |
* then it is formatted as megabytes (rounded) with a |
* trailing "M". |
* trailing "M". |
*/ |
*/ |
|
|
/* |
/* |
|
|
char * |
char * |
format_k(int amt) |
format_k(int amt) |
{ |
{ |
static char retarray[NUM_STRINGS][16]; |
static char retarray[NUM_STRINGS][16]; |
static int index = 0; |
static int index = 0; |
char *p; |
char *p, *ret, tag = 'K'; |
char *ret; |
|
char tag = 'K'; |
|
|
|
p = ret = retarray[index]; |
p = ret = retarray[index]; |
index = (index + 1) % NUM_STRINGS; |
index = (index + 1) % NUM_STRINGS; |
|
|
if (amt >= 10000) |
if (amt >= 10000) { |
{ |
amt = (amt + 512) / 1024; |
amt = (amt + 512) / 1024; |
tag = 'M'; |
tag = 'M'; |
if (amt >= 10000) { |
if (amt >= 10000) |
amt = (amt + 512) / 1024; |
{ |
tag = 'G'; |
amt = (amt + 512) / 1024; |
} |
tag = 'G'; |
|
} |
} |
} |
p = strecpy(p, itoa(amt)); |
|
*p++ = tag; |
p = strecpy(p, itoa(amt)); |
*p = '\0'; |
*p++ = tag; |
return (ret); |
*p = '\0'; |
|
|
|
return(ret); |
|
} |
} |