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