Annotation of src/usr.bin/top/display.c, Revision 1.32
1.32 ! otto 1: /* $OpenBSD: display.c,v 1.31 2007/11/01 19:10:32 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_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
1.32 ! otto 562: readlinedumb(char *buffer, int size)
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 */
1.32 ! otto 603: else if (cnt == size || !isprint(ch)) {
1.14 deraadt 604: /* not legal */
605: if (putchar('\7') == EOF)
606: exit(1);
607: } else {
608: /* echo it and store it in the buffer */
609: if (putchar(ch) == EOF)
610: exit(1);
611: ptr++;
612: cnt++;
613: if (cnt > maxcnt)
614: maxcnt = cnt;
615: }
1.1 downsj 616: }
617:
1.14 deraadt 618: /* all done -- null terminate the string */
619: *ptr = '\0';
620:
621: /* return either inputted number or string length */
1.25 otto 622: putr();
1.32 ! otto 623: return (cnt == 0 ? -1 : cnt);
1.25 otto 624: }
625:
626: int
1.32 ! otto 627: readline(char *buffer, int size)
1.25 otto 628: {
629: size_t cnt;
630:
631: /* allow room for null terminator */
632: size -= 1;
633:
634: if (smart_terminal)
635: getnstr(buffer, size);
636: else
1.32 ! otto 637: return readlinedumb(buffer, size);
1.25 otto 638:
639: cnt = strlen(buffer);
640: if (cnt > 0 && buffer[cnt - 1] == '\n')
641: buffer[cnt - 1] = '\0';
1.32 ! otto 642: return (cnt == 0 ? -1 : cnt);
1.1 downsj 643: }
644:
645: /* internal support routines */
1.12 pvalchev 646: static int
647: string_count(char **pp)
1.1 downsj 648: {
1.14 deraadt 649: int cnt;
1.1 downsj 650:
1.14 deraadt 651: cnt = 0;
652: while (*pp++ != NULL)
653: cnt++;
654: return (cnt);
1.1 downsj 655: }
656:
1.16 millert 657: #define COPYLEFT(to, from) \
658: do { \
659: len = strlcpy((to), (from), left); \
660: if (len >= left) \
661: return; \
662: p += len; \
663: left -= len; \
664: } while (0)
665:
1.12 pvalchev 666: static void
1.16 millert 667: summary_format(char *buf, size_t left, int *numbers, char **names)
1.1 downsj 668: {
1.14 deraadt 669: char *p, *thisname;
1.16 millert 670: size_t len;
1.14 deraadt 671: int num;
1.1 downsj 672:
1.14 deraadt 673: /* format each number followed by its string */
1.16 millert 674: p = buf;
1.14 deraadt 675: while ((thisname = *names++) != NULL) {
676: /* get the number to format */
677: num = *numbers++;
678:
679: if (num >= 0) {
680: /* is this number in kilobytes? */
681: if (thisname[0] == 'K') {
682: /* yes: format it as a memory value */
1.16 millert 683: COPYLEFT(p, format_k(num));
1.14 deraadt 684:
685: /*
686: * skip over the K, since it was included by
687: * format_k
688: */
1.16 millert 689: COPYLEFT(p, thisname + 1);
1.14 deraadt 690: } else if (num > 0) {
1.16 millert 691: len = snprintf(p, left, "%d%s", num, thisname);
692: if (len == (size_t)-1 || len >= left)
693: return;
694: p += len;
695: left -= len;
1.14 deraadt 696: }
1.16 millert 697: } else {
698: /*
699: * Ignore negative numbers, but display corresponding
700: * string.
701: */
702: COPYLEFT(p, thisname);
1.14 deraadt 703: }
1.1 downsj 704: }
705:
1.14 deraadt 706: /* if the last two characters in the string are ", ", delete them */
707: p -= 2;
1.16 millert 708: if (p >= buf && p[0] == ',' && p[1] == ' ')
1.14 deraadt 709: *p = '\0';
1.1 downsj 710: }
711:
712: /*
713: * printable(str) - make the string pointed to by "str" into one that is
714: * printable (i.e.: all ascii), by converting all non-printable
715: * characters into '?'. Replacements are done in place and a pointer
716: * to the original buffer is returned.
717: */
1.12 pvalchev 718: char *
719: printable(char *str)
1.1 downsj 720: {
1.14 deraadt 721: char *ptr, ch;
1.1 downsj 722:
1.14 deraadt 723: ptr = str;
724: while ((ch = *ptr) != '\0') {
725: if (!isprint(ch))
726: *ptr = '?';
727: ptr++;
1.1 downsj 728: }
1.14 deraadt 729: return (str);
1.25 otto 730: }
731:
732:
733: /*
734: * show_help() - display the help screen; invoked in response to
735: * either 'h' or '?'.
736: */
737: void
738: show_help(void)
739: {
740: if (smart_terminal) {
741: clear();
742: nl();
743: }
744: printwp("These single-character commands are available:\n"
745: "\n"
746: "^L - redraw screen\n"
747: "+ - reset any g, p, or u filters\n"
748: "C - toggle the display of command line arguments\n"
749: "d count - show `count' displays, then exit\n"
750: "e - list errors generated by last \"kill\" or \"renice\" command\n"
751: "h | ? - help; show this text\n"
752: "g string - filter on command name (g+ selects all commands)\n"
753: "I | i - toggle the display of idle processes\n"
754: "k [-sig] pid - send signal `-sig' to process `pid'\n"
755: "n|# count - show `count' processes\n"
756: "o field - specify sort order (size, res, cpu, time, pri)\n"
757: "P pid - highlight process `pid' (P+ switches highlighting off)\n"
758: "p pid - display process by `pid' (p+ selects all processes)\n"
759: "q - quit\n"
760: "r count pid - renice process `pid' to nice value `count'\n"
761: "S - toggle the display of system processes\n"
762: "s time - change delay between displays to `time' seconds\n"
763: "T - toggle the display of threads\n"
764: "u user - display processes for `user' (u+ selects all users)\n"
765: "\n");
766:
767: if (smart_terminal) {
768: nonl();
769: refresh();
770: }
771: }
772:
773: /*
774: * show_errors() - display on stdout the current log of errors.
775: */
776: void
777: show_errors(void)
778: {
779: struct errs *errp = errs;
780: int cnt = 0;
781:
782: if (smart_terminal) {
783: clear();
784: nl();
785: }
786: printwp("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
787: while (cnt++ < errcnt) {
788: printf("%5s: %s\n", errp->arg,
789: errp->err == 0 ? "Not a number" : strerror(errp->err));
790: errp++;
791: }
792: if (smart_terminal) {
793: nonl();
794: refresh();
795: }
796: }
797:
798: void
799: anykey(void)
800: {
801: int ch;
1.28 deraadt 802: ssize_t len;
1.25 otto 803:
804: standoutp();
805: addstrp("Hit any key to continue: ");
806: standendp();
807: if (smart_terminal)
808: refresh();
809: else
810: fflush(stdout);
811: while (1) {
812: len = read(STDIN_FILENO, &ch, 1);
813: if (len == -1 && errno == EINTR)
814: continue;
815: if (len == 0)
816: exit(1);
817: break;
818: }
1.1 downsj 819: }