Annotation of src/usr.bin/top/display.c, Revision 1.34
1.34 ! tedu 1: /* $OpenBSD: display.c,v 1.33 2007/11/30 10:39:01 otto Exp $ */
1.1 downsj 2:
3: /*
4: * Top users/processes display for Unix
5: * Version 3
6: *
1.11 deraadt 7: * Copyright (c) 1984, 1989, William LeFebvre, Rice University
8: * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
1.1 downsj 9: *
1.11 deraadt 10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22: * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
23: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1 downsj 29: */
30:
31: /*
32: * This file contains the routines that display information on the screen.
33: * Each section of the screen has two routines: one for initially writing
34: * all constant and dynamic text, and one for only updating the text that
35: * changes. The prefix "i_" is used on all the "initial" routines and the
36: * prefix "u_" is used for all the "updating" routines.
37: *
38: * ASSUMPTIONS:
39: * None of the "i_" routines use any of the termcap capabilities.
40: * In this way, those routines can be safely used on terminals that
1.18 otto 41: * have minimal (or nonexistent) terminal capabilities.
1.1 downsj 42: *
43: * The routines are called in this order: *_loadave, i_timeofday,
44: * *_procstates, *_cpustates, *_memory, *_message, *_header,
45: * *_process, u_endscreen.
46: */
47:
1.2 downsj 48: #include <sys/types.h>
1.20 millert 49: #include <sys/sched.h>
1.25 otto 50: #include <curses.h>
51: #include <errno.h>
1.2 downsj 52: #include <stdio.h>
1.1 downsj 53: #include <ctype.h>
1.20 millert 54: #include <err.h>
1.25 otto 55: #include <signal.h>
1.2 downsj 56: #include <stdlib.h>
57: #include <string.h>
58: #include <unistd.h>
1.1 downsj 59:
60: #include "screen.h" /* interface to screen package */
61: #include "layout.h" /* defines for screen position layout */
62: #include "display.h"
63: #include "top.h"
64: #include "boolean.h"
65: #include "machine.h" /* we should eliminate this!!! */
66: #include "utils.h"
67:
68: #ifdef DEBUG
1.14 deraadt 69: FILE *debug;
1.1 downsj 70: #endif
71:
1.14 deraadt 72: static int display_width = MAX_COLS;
73:
1.20 millert 74: static char *cpustates_tag(int);
1.14 deraadt 75: static int string_count(char **);
1.16 millert 76: static void summary_format(char *, size_t, int *, char **);
1.32 otto 77: static int readlinedumb(char *, int);
1.2 downsj 78:
1.1 downsj 79: #define lineindex(l) ((l)*display_width)
80:
1.18 otto 81: /* things initialized by display_init and used throughout */
1.1 downsj 82:
83: /* buffer of proc information lines for display updating */
1.14 deraadt 84: char *screenbuf = NULL;
1.1 downsj 85:
1.14 deraadt 86: static char **procstate_names;
87: static char **cpustate_names;
88: static char **memory_names;
89:
90: static int num_cpustates;
91:
92: static int *cpustate_columns;
93: static int cpustate_total_length;
94:
1.20 millert 95: /* display ips */
96: int y_mem;
97: int y_message;
98: int y_header;
99: int y_idlecursor;
100: int y_procs;
101: extern int ncpu;
1.34 ! tedu 102: extern int combine_cpus;
1.20 millert 103: int Header_lines;
104:
1.33 otto 105: int header_status = Yes;
1.1 downsj 106:
1.25 otto 107: static int
108: empty(void)
109: {
110: return OK;
111: }
112:
113: static int
114: myfputs(const char *s)
115: {
116: return fputs(s, stdout);
117: }
118:
119: static int (*addstrp)(const char *);
120: static int (*printwp)(const char *, ...);
121: static int (*standoutp)(void);
122: static int (*standendp)(void);
123:
1.12 pvalchev 124: int
125: display_resize(void)
1.1 downsj 126: {
1.14 deraadt 127: int display_lines;
1.34 ! tedu 128: int cpu_lines = (combine_cpus ? 1 : ncpu);
! 129:
! 130: y_mem = 2 + cpu_lines;
! 131: y_header = 4 + cpu_lines;
! 132: y_procs = 5 + cpu_lines;
! 133: Header_lines = 5 + cpu_lines;
1.1 downsj 134:
1.14 deraadt 135: /* calculate the current dimensions */
136: /* if operating in "dumb" mode, we only need one line */
137: display_lines = smart_terminal ? screen_length - Header_lines : 1;
138:
1.34 ! tedu 139: y_idlecursor = y_message = 3 + (combine_cpus ? 1 : ncpu);
1.30 otto 140: if (screen_length <= y_message)
141: y_idlecursor = y_message = screen_length - 1;
142:
1.14 deraadt 143: /*
144: * we don't want more than MAX_COLS columns, since the
145: * machine-dependent modules make static allocations based on
146: * MAX_COLS and we don't want to run off the end of their buffers
147: */
148: display_width = screen_width;
149: if (display_width >= MAX_COLS)
150: display_width = MAX_COLS - 1;
151:
152: /* return number of lines available */
153: /* for dumb terminals, pretend like we can show any amount */
154: return (smart_terminal ? display_lines : Largest);
1.1 downsj 155: }
156:
1.12 pvalchev 157: int
1.14 deraadt 158: display_init(struct statics * statics)
1.1 downsj 159: {
1.34 ! tedu 160: int display_lines, *ip, i;
1.14 deraadt 161: char **pp;
162:
1.25 otto 163: if (smart_terminal) {
164: addstrp = addstr;
165: printwp = (int(*)(const char *, ...))printw;
166: standoutp = standout;
167: standendp = standend;
168: } else {
169: addstrp = myfputs;
170: printwp = printf;
171: standoutp = empty;
172: standendp = empty;
173: }
174:
1.14 deraadt 175: /* call resize to do the dirty work */
176: display_lines = display_resize();
177:
178: /* only do the rest if we need to */
1.30 otto 179: /* save pointers and allocate space for names */
180: procstate_names = statics->procstate_names;
181:
182: cpustate_names = statics->cpustate_names;
183: num_cpustates = string_count(cpustate_names);
184:
185: cpustate_columns = calloc(num_cpustates, sizeof(int));
186: if (cpustate_columns == NULL)
187: err(1, NULL);
188:
189: memory_names = statics->memory_names;
190:
191: /* calculate starting columns where needed */
192: cpustate_total_length = 0;
193: pp = cpustate_names;
194: ip = cpustate_columns;
195: while (*pp != NULL) {
196: if ((i = strlen(*pp++)) > 0) {
197: *ip++ = cpustate_total_length;
198: cpustate_total_length += i + 8;
1.20 millert 199: }
1.30 otto 200: }
1.14 deraadt 201:
1.30 otto 202: if (display_lines < 0)
203: display_lines = 0;
1.14 deraadt 204:
205: /* return number of lines available */
206: return (display_lines);
1.1 downsj 207: }
208:
1.12 pvalchev 209: void
210: i_loadave(pid_t mpid, double *avenrun)
1.1 downsj 211: {
1.30 otto 212: if (screen_length > 1 || !smart_terminal) {
213: int i;
1.14 deraadt 214:
1.30 otto 215: move(0, 0);
216: clrtoeol();
1.1 downsj 217:
1.30 otto 218: addstrp("load averages");
219: /* mpid == -1 implies this system doesn't have an _mpid */
220: if (mpid != -1)
221: printwp("last pid: %5ld; ", (long) mpid);
1.1 downsj 222:
1.30 otto 223: for (i = 0; i < 3; i++)
224: printwp("%c %5.2f", i == 0 ? ':' : ',', avenrun[i]);
225: }
1.1 downsj 226: }
227:
1.14 deraadt 228: /*
229: * Display the current time.
230: * "ctime" always returns a string that looks like this:
231: *
232: * Sun Sep 16 01:03:52 1973
233: * 012345678901234567890123
234: * 1 2
235: *
236: * We want indices 11 thru 18 (length 8).
237: */
238:
1.12 pvalchev 239: void
1.14 deraadt 240: i_timeofday(time_t * tod)
1.1 downsj 241: {
1.30 otto 242: if (screen_length > 1 || !smart_terminal) {
243: if (smart_terminal) {
244: move(0, screen_width - 8);
245: } else {
246: if (fputs(" ", stdout) == EOF)
247: exit(1);
248: }
1.1 downsj 249: #ifdef DEBUG
1.30 otto 250: {
251: char *foo;
252: foo = ctime(tod);
253: addstrp(foo);
254: }
255: #endif
256: printwp("%-8.8s", &(ctime(tod)[11]));
257: putn();
1.14 deraadt 258: }
1.1 downsj 259: }
260:
261: /*
262: * *_procstates(total, brkdn, names) - print the process summary line
263: *
264: * Assumptions: cursor is at the beginning of the line on entry
265: */
1.12 pvalchev 266: void
267: i_procstates(int total, int *brkdn)
1.1 downsj 268: {
1.30 otto 269: if (screen_length > 2 || !smart_terminal) {
270: int i;
271: char procstates_buffer[MAX_COLS];
272:
273: move(1, 0);
274: clrtoeol();
275: /* write current number of processes and remember the value */
276: printwp("%d processes:", total);
1.1 downsj 277:
1.30 otto 278: if (smart_terminal)
279: move(1, 15);
280: else {
281: /* put out enough spaces to get to column 15 */
282: i = digits(total);
283: while (i++ < 4) {
284: if (putchar(' ') == EOF)
285: exit(1);
286: }
1.25 otto 287: }
1.14 deraadt 288:
1.30 otto 289: /* format and print the process state summary */
290: summary_format(procstates_buffer, sizeof(procstates_buffer), brkdn,
291: procstate_names);
1.1 downsj 292:
1.30 otto 293: addstrp(procstates_buffer);
294: putn();
295: }
1.1 downsj 296: }
297:
298: /*
299: * *_cpustates(states, names) - print the cpu state percentages
300: *
301: * Assumptions: cursor is on the PREVIOUS line
302: */
303:
304: /* cpustates_tag() calculates the correct tag to use to label the line */
305:
1.12 pvalchev 306: static char *
1.20 millert 307: cpustates_tag(int cpu)
1.1 downsj 308: {
1.30 otto 309: if (screen_length > 3 || !smart_terminal) {
310: static char *tag;
311: static int cpulen, old_width;
312: int i;
313:
314: if (cpulen == 0 && ncpu > 1) {
315: /* compute length of the cpu string */
316: for (i = ncpu; i > 0; cpulen++, i /= 10)
317: continue;
318: }
1.20 millert 319:
1.30 otto 320: if (old_width == screen_width) {
321: if (ncpu > 1) {
322: /* just store the cpu number in the tag */
323: i = tag[3 + cpulen];
324: snprintf(tag + 3, cpulen + 1, "%.*d", cpulen, cpu);
325: tag[3 + cpulen] = i;
326: }
327: } else {
328: /*
329: * use a long tag if it will fit, otherwise use short one.
330: */
331: free(tag);
332: if (cpustate_total_length + 10 + cpulen >= screen_width)
333: i = asprintf(&tag, "CPU%.*d: ", cpulen, cpu);
334: else
335: i = asprintf(&tag, "CPU%.*d states: ", cpulen, cpu);
336: if (i == -1)
337: tag = NULL;
338: else
339: old_width = screen_width;
1.20 millert 340: }
1.30 otto 341: return (tag);
342: } else
1.34 ! tedu 343: return ("\0");
1.1 downsj 344: }
345:
1.12 pvalchev 346: void
1.20 millert 347: i_cpustates(int64_t *ostates)
1.1 downsj 348: {
1.34 ! tedu 349: int i, first, cpu;
! 350: double value;
1.20 millert 351: int64_t *states;
1.34 ! tedu 352: char **names, *thisname;
! 353:
! 354: if (combine_cpus) {
! 355: static double *values;
! 356: if (!values) {
! 357: values = calloc(num_cpustates, sizeof(*values));
! 358: if (!values)
! 359: err(1, NULL);
! 360: }
! 361: memset(values, 0, num_cpustates * sizeof(*values));
! 362: for (cpu = 0; cpu < ncpu; cpu++) {
! 363: names = cpustate_names;
! 364: states = ostates + (CPUSTATES * cpu);
! 365: i = 0;
! 366: while ((thisname = *names++) != NULL) {
! 367: if (*thisname != '\0') {
! 368: /* retrieve the value and remember it */
! 369: values[i++] += *states++;
! 370: }
! 371: }
! 372: }
! 373: if (screen_length > 2 || !smart_terminal) {
! 374: names = cpustate_names;
! 375: i = 0;
! 376: first = 0;
! 377: move(2, 0);
! 378: clrtoeol();
! 379: addstrp("All CPUs: ");
1.14 deraadt 380:
1.34 ! tedu 381: while ((thisname = *names++) != NULL) {
! 382: if (*thisname != '\0') {
! 383: value = values[i++] / ncpu;
! 384: /* if percentage is >= 1000, print it as 100% */
! 385: printwp((value >= 1000 ? "%s%4.0f%% %s" :
! 386: "%s%4.1f%% %s"), first++ == 0 ? "" : ", ",
! 387: value / 10., thisname);
! 388: }
! 389: }
! 390: putn();
! 391: }
! 392: return;
! 393: }
1.20 millert 394: for (cpu = 0; cpu < ncpu; cpu++) {
395: /* now walk thru the names and print the line */
396: names = cpustate_names;
1.34 ! tedu 397: first = 0;
1.20 millert 398: states = ostates + (CPUSTATES * cpu);
1.30 otto 399:
400: if (screen_length > 2 + cpu || !smart_terminal) {
401: move(2 + cpu, 0);
402: clrtoeol();
403: addstrp(cpustates_tag(cpu));
404:
405: while ((thisname = *names++) != NULL) {
406: if (*thisname != '\0') {
407: /* retrieve the value and remember it */
408: value = *states++;
409:
410: /* if percentage is >= 1000, print it as 100% */
411: printwp((value >= 1000 ? "%s%4.0f%% %s" :
1.34 ! tedu 412: "%s%4.1f%% %s"), first++ == 0 ? "" : ", ",
! 413: value / 10., thisname);
1.30 otto 414: }
1.20 millert 415: }
1.30 otto 416: putn();
1.14 deraadt 417: }
1.1 downsj 418: }
419: }
420:
421: /*
422: * *_memory(stats) - print "Memory: " followed by the memory summary string
423: */
1.12 pvalchev 424: void
425: i_memory(int *stats)
1.1 downsj 426: {
1.30 otto 427: if (screen_length > y_mem || !smart_terminal) {
428: char memory_buffer[MAX_COLS];
429:
430: move(y_mem, 0);
431: clrtoeol();
432: addstrp("Memory: ");
1.25 otto 433:
1.30 otto 434: /* format and print the memory summary */
435: summary_format(memory_buffer, sizeof(memory_buffer), stats,
436: memory_names);
437: addstrp(memory_buffer);
438: putn();
439: }
1.1 downsj 440: }
441:
442: /*
443: * *_message() - print the next pending message line, or erase the one
444: * that is there.
445: */
446:
447: /*
448: * i_message is funny because it gets its message asynchronously (with
449: * respect to screen updates).
450: */
451:
1.14 deraadt 452: static char next_msg[MAX_COLS + 5];
1.31 otto 453: static int msgon = 0;
1.1 downsj 454:
1.12 pvalchev 455: void
456: i_message(void)
1.1 downsj 457: {
1.25 otto 458: move(y_message, 0);
1.14 deraadt 459: if (next_msg[0] != '\0') {
1.25 otto 460: standoutp();
461: addstrp(next_msg);
462: standendp();
463: clrtoeol();
1.31 otto 464: msgon = TRUE;
1.14 deraadt 465: next_msg[0] = '\0';
1.31 otto 466: } else if (msgon) {
1.25 otto 467: clrtoeol();
1.31 otto 468: msgon = FALSE;
1.14 deraadt 469: }
1.1 downsj 470: }
471:
472: /*
473: * *_header(text) - print the header for the process area
474: */
475:
1.12 pvalchev 476: void
477: i_header(char *text)
1.1 downsj 478: {
1.33 otto 479: if (header_status == Yes && (screen_length > y_header
1.30 otto 480: || !smart_terminal)) {
1.25 otto 481: if (!smart_terminal) {
482: putn();
483: if (fputs(text, stdout) == EOF)
484: exit(1);
485: putn();
486: } else {
487: move(y_header, 0);
488: clrtoeol();
489: addstrp(text);
490: }
1.14 deraadt 491: }
1.1 downsj 492: }
493:
494: /*
495: * *_process(line, thisline) - print one process line
496: */
497:
1.12 pvalchev 498: void
1.25 otto 499: i_process(int line, char *thisline, int hl)
1.1 downsj 500: {
1.14 deraadt 501: /* make sure we are on the correct line */
1.25 otto 502: move(y_procs + line, 0);
1.1 downsj 503:
1.14 deraadt 504: /* truncate the line to conform to our current screen width */
505: thisline[display_width] = '\0';
1.1 downsj 506:
1.14 deraadt 507: /* write the line out */
1.25 otto 508: if (hl && smart_terminal)
509: standoutp();
510: addstrp(thisline);
511: if (hl && smart_terminal)
512: standendp();
513: putn();
514: clrtoeol();
1.1 downsj 515: }
516:
1.12 pvalchev 517: void
1.27 deraadt 518: u_endscreen(void)
1.1 downsj 519: {
1.14 deraadt 520: if (smart_terminal) {
1.25 otto 521: clrtobot();
1.14 deraadt 522: /* move the cursor to a pleasant place */
1.25 otto 523: move(y_idlecursor, x_idlecursor);
1.14 deraadt 524: } else {
525: /*
526: * separate this display from the next with some vertical
527: * room
528: */
529: if (fputs("\n\n", stdout) == EOF)
530: exit(1);
1.1 downsj 531: }
532: }
533:
1.12 pvalchev 534: void
1.33 otto 535: display_header(int status)
1.1 downsj 536: {
1.33 otto 537: header_status = status;
1.1 downsj 538: }
539:
1.12 pvalchev 540: void
1.14 deraadt 541: new_message(int type, const char *msgfmt,...)
542: {
543: va_list ap;
544:
545: va_start(ap, msgfmt);
546: /* first, format the message */
547: vsnprintf(next_msg, sizeof(next_msg), msgfmt, ap);
548: va_end(ap);
549:
1.31 otto 550: if (next_msg[0] != '\0') {
1.14 deraadt 551: /* message there already -- can we clear it? */
1.25 otto 552: /* yes -- write it and clear to end */
553: if ((type & MT_delayed) == 0) {
554: move(y_message, 0);
555: if (type & MT_standout)
556: standoutp();
557: addstrp(next_msg);
558: if (type & MT_standout)
559: standendp();
560: clrtoeol();
1.31 otto 561: msgon = TRUE;
1.14 deraadt 562: next_msg[0] = '\0';
1.31 otto 563: if (smart_terminal)
564: refresh();
1.5 deraadt 565: }
1.1 downsj 566: }
567: }
568:
1.12 pvalchev 569: void
570: clear_message(void)
1.1 downsj 571: {
1.25 otto 572: move(y_message, 0);
573: clrtoeol();
1.1 downsj 574: }
575:
1.25 otto 576:
577: static int
1.32 otto 578: readlinedumb(char *buffer, int size)
1.1 downsj 579: {
1.14 deraadt 580: char *ptr = buffer, ch, cnt = 0, maxcnt = 0;
1.17 deraadt 581: extern volatile sig_atomic_t leaveflag;
582: ssize_t len;
1.14 deraadt 583:
584: /* allow room for null terminator */
585: size -= 1;
586:
587: /* read loop */
1.19 deraadt 588: while ((fflush(stdout), (len = read(STDIN_FILENO, ptr, 1)) > 0)) {
1.17 deraadt 589:
590: if (len == 0 || leaveflag) {
591: end_screen();
592: exit(0);
593: }
594:
1.14 deraadt 595: /* newline means we are done */
596: if ((ch = *ptr) == '\n')
597: break;
598:
599: /* handle special editing characters */
600: if (ch == ch_kill) {
601: /* return null string */
602: *buffer = '\0';
1.25 otto 603: putr();
1.14 deraadt 604: return (-1);
605: } else if (ch == ch_erase) {
606: /* erase previous character */
607: if (cnt <= 0) {
608: /* none to erase! */
609: if (putchar('\7') == EOF)
610: exit(1);
611: } else {
612: if (fputs("\b \b", stdout) == EOF)
613: exit(1);
614: ptr--;
615: cnt--;
616: }
617: }
618: /* check for character validity and buffer overflow */
1.32 otto 619: else if (cnt == size || !isprint(ch)) {
1.14 deraadt 620: /* not legal */
621: if (putchar('\7') == EOF)
622: exit(1);
623: } else {
624: /* echo it and store it in the buffer */
625: if (putchar(ch) == EOF)
626: exit(1);
627: ptr++;
628: cnt++;
629: if (cnt > maxcnt)
630: maxcnt = cnt;
631: }
1.1 downsj 632: }
633:
1.14 deraadt 634: /* all done -- null terminate the string */
635: *ptr = '\0';
636:
637: /* return either inputted number or string length */
1.25 otto 638: putr();
1.32 otto 639: return (cnt == 0 ? -1 : cnt);
1.25 otto 640: }
641:
642: int
1.32 otto 643: readline(char *buffer, int size)
1.25 otto 644: {
645: size_t cnt;
646:
647: /* allow room for null terminator */
648: size -= 1;
649:
650: if (smart_terminal)
651: getnstr(buffer, size);
652: else
1.32 otto 653: return readlinedumb(buffer, size);
1.25 otto 654:
655: cnt = strlen(buffer);
656: if (cnt > 0 && buffer[cnt - 1] == '\n')
657: buffer[cnt - 1] = '\0';
1.32 otto 658: return (cnt == 0 ? -1 : cnt);
1.1 downsj 659: }
660:
661: /* internal support routines */
1.12 pvalchev 662: static int
663: string_count(char **pp)
1.1 downsj 664: {
1.14 deraadt 665: int cnt;
1.1 downsj 666:
1.14 deraadt 667: cnt = 0;
668: while (*pp++ != NULL)
669: cnt++;
670: return (cnt);
1.1 downsj 671: }
672:
1.16 millert 673: #define COPYLEFT(to, from) \
674: do { \
675: len = strlcpy((to), (from), left); \
676: if (len >= left) \
677: return; \
678: p += len; \
679: left -= len; \
680: } while (0)
681:
1.12 pvalchev 682: static void
1.16 millert 683: summary_format(char *buf, size_t left, int *numbers, char **names)
1.1 downsj 684: {
1.14 deraadt 685: char *p, *thisname;
1.16 millert 686: size_t len;
1.14 deraadt 687: int num;
1.1 downsj 688:
1.14 deraadt 689: /* format each number followed by its string */
1.16 millert 690: p = buf;
1.14 deraadt 691: while ((thisname = *names++) != NULL) {
692: /* get the number to format */
693: num = *numbers++;
694:
695: if (num >= 0) {
696: /* is this number in kilobytes? */
697: if (thisname[0] == 'K') {
698: /* yes: format it as a memory value */
1.16 millert 699: COPYLEFT(p, format_k(num));
1.14 deraadt 700:
701: /*
702: * skip over the K, since it was included by
703: * format_k
704: */
1.16 millert 705: COPYLEFT(p, thisname + 1);
1.14 deraadt 706: } else if (num > 0) {
1.16 millert 707: len = snprintf(p, left, "%d%s", num, thisname);
708: if (len == (size_t)-1 || len >= left)
709: return;
710: p += len;
711: left -= len;
1.14 deraadt 712: }
1.16 millert 713: } else {
714: /*
715: * Ignore negative numbers, but display corresponding
716: * string.
717: */
718: COPYLEFT(p, thisname);
1.14 deraadt 719: }
1.1 downsj 720: }
721:
1.14 deraadt 722: /* if the last two characters in the string are ", ", delete them */
723: p -= 2;
1.16 millert 724: if (p >= buf && p[0] == ',' && p[1] == ' ')
1.14 deraadt 725: *p = '\0';
1.1 downsj 726: }
727:
728: /*
729: * printable(str) - make the string pointed to by "str" into one that is
730: * printable (i.e.: all ascii), by converting all non-printable
731: * characters into '?'. Replacements are done in place and a pointer
732: * to the original buffer is returned.
733: */
1.12 pvalchev 734: char *
735: printable(char *str)
1.1 downsj 736: {
1.14 deraadt 737: char *ptr, ch;
1.1 downsj 738:
1.14 deraadt 739: ptr = str;
740: while ((ch = *ptr) != '\0') {
741: if (!isprint(ch))
742: *ptr = '?';
743: ptr++;
1.1 downsj 744: }
1.14 deraadt 745: return (str);
1.25 otto 746: }
747:
748:
749: /*
750: * show_help() - display the help screen; invoked in response to
751: * either 'h' or '?'.
752: */
753: void
754: show_help(void)
755: {
756: if (smart_terminal) {
757: clear();
758: nl();
759: }
760: printwp("These single-character commands are available:\n"
761: "\n"
762: "^L - redraw screen\n"
763: "+ - reset any g, p, or u filters\n"
764: "C - toggle the display of command line arguments\n"
765: "d count - show `count' displays, then exit\n"
766: "e - list errors generated by last \"kill\" or \"renice\" command\n"
767: "h | ? - help; show this text\n"
768: "g string - filter on command name (g+ selects all commands)\n"
769: "I | i - toggle the display of idle processes\n"
770: "k [-sig] pid - send signal `-sig' to process `pid'\n"
771: "n|# count - show `count' processes\n"
772: "o field - specify sort order (size, res, cpu, time, pri)\n"
773: "P pid - highlight process `pid' (P+ switches highlighting off)\n"
774: "p pid - display process by `pid' (p+ selects all processes)\n"
775: "q - quit\n"
776: "r count pid - renice process `pid' to nice value `count'\n"
777: "S - toggle the display of system processes\n"
778: "s time - change delay between displays to `time' seconds\n"
779: "T - toggle the display of threads\n"
780: "u user - display processes for `user' (u+ selects all users)\n"
781: "\n");
782:
783: if (smart_terminal) {
784: nonl();
785: refresh();
786: }
787: }
788:
789: /*
790: * show_errors() - display on stdout the current log of errors.
791: */
792: void
793: show_errors(void)
794: {
795: struct errs *errp = errs;
796: int cnt = 0;
797:
798: if (smart_terminal) {
799: clear();
800: nl();
801: }
802: printwp("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
803: while (cnt++ < errcnt) {
804: printf("%5s: %s\n", errp->arg,
805: errp->err == 0 ? "Not a number" : strerror(errp->err));
806: errp++;
807: }
808: if (smart_terminal) {
809: nonl();
810: refresh();
811: }
812: }
813:
814: void
815: anykey(void)
816: {
817: int ch;
1.28 deraadt 818: ssize_t len;
1.25 otto 819:
820: standoutp();
821: addstrp("Hit any key to continue: ");
822: standendp();
823: if (smart_terminal)
824: refresh();
825: else
826: fflush(stdout);
827: while (1) {
828: len = read(STDIN_FILENO, &ch, 1);
829: if (len == -1 && errno == EINTR)
830: continue;
831: if (len == 0)
832: exit(1);
833: break;
834: }
1.1 downsj 835: }