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