[BACK]Return to display.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / top

Annotation of src/usr.bin/top/display.c, Revision 1.30

1.30    ! otto        1: /* $OpenBSD: display.c,v 1.29 2007/09/30 13:26:39 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:  *               lastline is valid
                    282:  */
1.12      pvalchev  283: void
                    284: i_procstates(int total, int *brkdn)
1.1       downsj    285: {
1.30    ! otto      286:        if (screen_length > 2 || !smart_terminal) {
        !           287:                int i;
        !           288:                char procstates_buffer[MAX_COLS];
        !           289:
        !           290:                move(1, 0);
        !           291:                clrtoeol();
        !           292:                /* write current number of processes and remember the value */
        !           293:                printwp("%d processes:", total);
1.1       downsj    294:
1.30    ! otto      295:                if (smart_terminal)
        !           296:                        move(1, 15);
        !           297:                else {
        !           298:                        /* put out enough spaces to get to column 15 */
        !           299:                        i = digits(total);
        !           300:                        while (i++ < 4) {
        !           301:                                if (putchar(' ') == EOF)
        !           302:                                        exit(1);
        !           303:                        }
1.25      otto      304:                }
1.14      deraadt   305:
1.30    ! otto      306:                /* format and print the process state summary */
        !           307:                summary_format(procstates_buffer, sizeof(procstates_buffer), brkdn,
        !           308:                    procstate_names);
1.1       downsj    309:
1.30    ! otto      310:                addstrp(procstates_buffer);
        !           311:                putn();
        !           312:        }
1.1       downsj    313: }
                    314:
                    315: /*
                    316:  *  *_cpustates(states, names) - print the cpu state percentages
                    317:  *
                    318:  *  Assumptions:  cursor is on the PREVIOUS line
                    319:  */
                    320:
                    321: /* cpustates_tag() calculates the correct tag to use to label the line */
                    322:
1.12      pvalchev  323: static char *
1.20      millert   324: cpustates_tag(int cpu)
1.1       downsj    325: {
1.30    ! otto      326:        if (screen_length > 3 || !smart_terminal) {
        !           327:                static char *tag;
        !           328:                static int cpulen, old_width;
        !           329:                int i;
        !           330:
        !           331:                if (cpulen == 0 && ncpu > 1) {
        !           332:                        /* compute length of the cpu string */
        !           333:                        for (i = ncpu; i > 0; cpulen++, i /= 10)
        !           334:                                continue;
        !           335:                }
1.20      millert   336:
1.30    ! otto      337:                if (old_width == screen_width) {
        !           338:                        if (ncpu > 1) {
        !           339:                                /* just store the cpu number in the tag */
        !           340:                                i = tag[3 + cpulen];
        !           341:                                snprintf(tag + 3, cpulen + 1, "%.*d", cpulen, cpu);
        !           342:                                tag[3 + cpulen] = i;
        !           343:                        }
        !           344:                } else {
        !           345:                        /*
        !           346:                         * use a long tag if it will fit, otherwise use short one.
        !           347:                         */
        !           348:                        free(tag);
        !           349:                        if (cpustate_total_length + 10 + cpulen >= screen_width)
        !           350:                                i = asprintf(&tag, "CPU%.*d: ", cpulen, cpu);
        !           351:                        else
        !           352:                                i = asprintf(&tag, "CPU%.*d states: ", cpulen, cpu);
        !           353:                        if (i == -1)
        !           354:                                tag = NULL;
        !           355:                        else
        !           356:                                old_width = screen_width;
1.20      millert   357:                }
1.30    ! otto      358:                return (tag);
        !           359:        } else
        !           360:                return ('\0');
1.1       downsj    361: }
                    362:
1.12      pvalchev  363: void
1.20      millert   364: i_cpustates(int64_t *ostates)
1.1       downsj    365: {
1.20      millert   366:        int i, cpu, value;
                    367:        int64_t *states;
1.14      deraadt   368:        char **names = cpustate_names, *thisname;
                    369:
1.20      millert   370:        for (cpu = 0; cpu < ncpu; cpu++) {
                    371:                /* now walk thru the names and print the line */
                    372:                names = cpustate_names;
                    373:                i = 0;
                    374:                states = ostates + (CPUSTATES * cpu);
1.30    ! otto      375:
        !           376:                if (screen_length > 2 + cpu || !smart_terminal) {
        !           377:                        move(2 + cpu, 0);
        !           378:                        clrtoeol();
        !           379:                        /* print tag and bump lastline */
        !           380:                        addstrp(cpustates_tag(cpu));
        !           381:
        !           382:                        while ((thisname = *names++) != NULL) {
        !           383:                                if (*thisname != '\0') {
        !           384:                                        /* retrieve the value and remember it */
        !           385:                                        value = *states++;
        !           386:
        !           387:                                        /* if percentage is >= 1000, print it as 100% */
        !           388:                                        printwp((value >= 1000 ? "%s%4.0f%% %s" :
        !           389:                                            "%s%4.1f%% %s"), i++ == 0 ? "" : ", ",
        !           390:                                            ((float) value) / 10., thisname);
        !           391:                                }
1.20      millert   392:                        }
1.30    ! otto      393:                        putn();
1.14      deraadt   394:                }
1.1       downsj    395:        }
                    396: }
                    397:
                    398: /*
                    399:  *  *_memory(stats) - print "Memory: " followed by the memory summary string
                    400:  *
                    401:  *  Assumptions:  cursor is on "lastline"
                    402:  *                for i_memory ONLY: cursor is on the previous line
                    403:  */
1.12      pvalchev  404: void
                    405: i_memory(int *stats)
1.1       downsj    406: {
1.30    ! otto      407:        if (screen_length > y_mem || !smart_terminal) {
        !           408:                char memory_buffer[MAX_COLS];
        !           409:
        !           410:                move(y_mem, 0);
        !           411:                clrtoeol();
        !           412:                addstrp("Memory: ");
1.25      otto      413:
1.30    ! otto      414:                /* format and print the memory summary */
        !           415:                summary_format(memory_buffer, sizeof(memory_buffer), stats,
        !           416:                    memory_names);
        !           417:                addstrp(memory_buffer);
        !           418:                putn();
        !           419:        }
1.1       downsj    420: }
                    421:
                    422: /*
                    423:  *  *_message() - print the next pending message line, or erase the one
                    424:  *                that is there.
                    425:  *
                    426:  *  Note that u_message is (currently) the same as i_message.
                    427:  *
                    428:  *  Assumptions:  lastline is consistent
                    429:  */
                    430:
                    431: /*
                    432:  *  i_message is funny because it gets its message asynchronously (with
                    433:  *     respect to screen updates).
                    434:  */
                    435:
1.14      deraadt   436: static char     next_msg[MAX_COLS + 5];
                    437: static int      msglen = 0;
                    438: /*
                    439:  * Invariant: msglen is always the length of the message currently displayed
                    440:  * on the screen (even when next_msg doesn't contain that message).
                    441:  */
1.1       downsj    442:
1.12      pvalchev  443: void
                    444: i_message(void)
1.1       downsj    445: {
1.25      otto      446:        /*
1.14      deraadt   447:        while (lastline < y_message) {
                    448:                if (fputc('\n', stdout) == EOF)
                    449:                        exit(1);
                    450:                lastline++;
                    451:        }
1.25      otto      452:        */
                    453:        move(y_message, 0);
1.14      deraadt   454:        if (next_msg[0] != '\0') {
1.25      otto      455:                standoutp();
                    456:                addstrp(next_msg);
                    457:                standendp();
                    458:                clrtoeol();
1.14      deraadt   459:                msglen = strlen(next_msg);
                    460:                next_msg[0] = '\0';
                    461:        } else if (msglen > 0) {
1.25      otto      462:                clrtoeol();
1.14      deraadt   463:                msglen = 0;
                    464:        }
1.1       downsj    465: }
                    466:
1.14      deraadt   467: static int      header_length;
1.1       downsj    468:
                    469: /*
                    470:  *  *_header(text) - print the header for the process area
                    471:  *
                    472:  *  Assumptions:  cursor is on the previous line and lastline is consistent
                    473:  */
                    474:
1.12      pvalchev  475: void
                    476: i_header(char *text)
1.1       downsj    477: {
1.14      deraadt   478:        header_length = strlen(text);
1.30    ! otto      479:        if (header_status == ON && (screen_length > y_header
        !           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:        } else if (header_status == ERASE) {
                    492:                header_status = OFF;
                    493:        }
1.1       downsj    494: }
                    495:
                    496: /*
                    497:  *  *_process(line, thisline) - print one process line
                    498:  *
                    499:  *  Assumptions:  lastline is consistent
                    500:  */
                    501:
1.12      pvalchev  502: void
1.25      otto      503: i_process(int line, char *thisline, int hl)
1.1       downsj    504: {
1.14      deraadt   505:        /* make sure we are on the correct line */
1.25      otto      506:        move(y_procs + line, 0);
1.1       downsj    507:
1.14      deraadt   508:        /* truncate the line to conform to our current screen width */
                    509:        thisline[display_width] = '\0';
1.1       downsj    510:
1.14      deraadt   511:        /* write the line out */
1.25      otto      512:        if (hl && smart_terminal)
                    513:                standoutp();
                    514:        addstrp(thisline);
                    515:        if (hl && smart_terminal)
                    516:                standendp();
                    517:        putn();
                    518:        clrtoeol();
1.1       downsj    519: }
                    520:
1.12      pvalchev  521: void
1.27      deraadt   522: u_endscreen(void)
1.1       downsj    523: {
1.14      deraadt   524:        if (smart_terminal) {
1.25      otto      525:                clrtobot();
1.14      deraadt   526:                /* move the cursor to a pleasant place */
1.25      otto      527:                move(y_idlecursor, x_idlecursor);
1.14      deraadt   528:        } else {
                    529:                /*
                    530:                 * separate this display from the next with some vertical
                    531:                 * room
                    532:                 */
                    533:                if (fputs("\n\n", stdout) == EOF)
                    534:                        exit(1);
1.1       downsj    535:        }
                    536: }
                    537:
1.12      pvalchev  538: void
                    539: display_header(int t)
1.1       downsj    540: {
1.14      deraadt   541:        if (t) {
                    542:                header_status = ON;
                    543:        } else if (header_status == ON) {
                    544:                header_status = ERASE;
                    545:        }
1.1       downsj    546: }
                    547:
1.12      pvalchev  548: void
1.14      deraadt   549: new_message(int type, const char *msgfmt,...)
                    550: {
                    551:        va_list ap;
                    552:        int i;
                    553:
                    554:        va_start(ap, msgfmt);
                    555:        /* first, format the message */
                    556:        vsnprintf(next_msg, sizeof(next_msg), msgfmt, ap);
                    557:        va_end(ap);
                    558:
                    559:        if (msglen > 0) {
                    560:                /* message there already -- can we clear it? */
1.25      otto      561:                /* yes -- write it and clear to end */
                    562:                i = strlen(next_msg);
                    563:                if ((type & MT_delayed) == 0) {
                    564:                        move(y_message, 0);
                    565:                        if (type & MT_standout)
                    566:                                standoutp();
                    567:                        addstrp(next_msg);
                    568:                        if (type & MT_standout)
                    569:                                standendp();
                    570:                        clrtoeol();
                    571:                        msglen = i;
                    572:                        next_msg[0] = '\0';
1.14      deraadt   573:                }
                    574:        } else {
                    575:                if ((type & MT_delayed) == 0) {
1.25      otto      576:                        move(y_message, 0);
                    577:                        if (type & MT_standout)
                    578:                                standoutp();
                    579:                        addstrp(next_msg);
1.14      deraadt   580:                        if (type & MT_standout)
1.25      otto      581:                                standendp();
                    582:                        clrtoeol();
1.14      deraadt   583:                        msglen = strlen(next_msg);
                    584:                        next_msg[0] = '\0';
1.5       deraadt   585:                }
1.1       downsj    586:        }
1.25      otto      587:        if (smart_terminal)
                    588:                refresh();
1.1       downsj    589: }
                    590:
1.12      pvalchev  591: void
                    592: clear_message(void)
1.1       downsj    593: {
1.25      otto      594:        move(y_message, 0);
                    595:        clrtoeol();
1.1       downsj    596: }
                    597:
1.25      otto      598:
                    599: static int
                    600: readlinedumb(char *buffer, int size, int numeric)
1.1       downsj    601: {
1.14      deraadt   602:        char *ptr = buffer, ch, cnt = 0, maxcnt = 0;
1.17      deraadt   603:        extern volatile sig_atomic_t leaveflag;
                    604:        ssize_t len;
1.14      deraadt   605:
                    606:        /* allow room for null terminator */
                    607:        size -= 1;
                    608:
                    609:        /* read loop */
1.19      deraadt   610:        while ((fflush(stdout), (len = read(STDIN_FILENO, ptr, 1)) > 0)) {
1.17      deraadt   611:
                    612:                if (len == 0 || leaveflag) {
                    613:                        end_screen();
                    614:                        exit(0);
                    615:                }
                    616:
1.14      deraadt   617:                /* newline means we are done */
                    618:                if ((ch = *ptr) == '\n')
                    619:                        break;
                    620:
                    621:                /* handle special editing characters */
                    622:                if (ch == ch_kill) {
                    623:                        /* return null string */
                    624:                        *buffer = '\0';
1.25      otto      625:                        putr();
1.14      deraadt   626:                        return (-1);
                    627:                } else if (ch == ch_erase) {
                    628:                        /* erase previous character */
                    629:                        if (cnt <= 0) {
                    630:                                /* none to erase! */
                    631:                                if (putchar('\7') == EOF)
                    632:                                        exit(1);
                    633:                        } else {
                    634:                                if (fputs("\b \b", stdout) == EOF)
                    635:                                        exit(1);
                    636:                                ptr--;
                    637:                                cnt--;
                    638:                        }
                    639:                }
                    640:                /* check for character validity and buffer overflow */
                    641:                else if (cnt == size || (numeric && !isdigit(ch)) ||
                    642:                    !isprint(ch)) {
                    643:                        /* not legal */
                    644:                        if (putchar('\7') == EOF)
                    645:                                exit(1);
                    646:                } else {
                    647:                        /* echo it and store it in the buffer */
                    648:                        if (putchar(ch) == EOF)
                    649:                                exit(1);
                    650:                        ptr++;
                    651:                        cnt++;
                    652:                        if (cnt > maxcnt)
                    653:                                maxcnt = cnt;
                    654:                }
1.1       downsj    655:        }
                    656:
1.14      deraadt   657:        /* all done -- null terminate the string */
                    658:        *ptr = '\0';
                    659:
                    660:        /* account for the extra characters in the message area */
1.25      otto      661:        msglen += cnt;
1.14      deraadt   662:
                    663:        /* return either inputted number or string length */
1.25      otto      664:        putr();
                    665:        return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
                    666: }
                    667:
                    668: int
                    669: readline(char *buffer, int size, int numeric)
                    670: {
                    671:        size_t cnt;
                    672:
                    673:        /* allow room for null terminator */
                    674:        size -= 1;
                    675:
                    676:        if (smart_terminal)
                    677:                getnstr(buffer, size);
                    678:        else
                    679:                return readlinedumb(buffer, size, numeric);
                    680:
                    681:        cnt = strlen(buffer);
                    682:        if (cnt > 0 && buffer[cnt - 1] == '\n')
                    683:                buffer[cnt - 1] = '\0';
1.14      deraadt   684:        return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
1.1       downsj    685: }
                    686:
                    687: /* internal support routines */
1.12      pvalchev  688: static int
                    689: string_count(char **pp)
1.1       downsj    690: {
1.14      deraadt   691:        int cnt;
1.1       downsj    692:
1.14      deraadt   693:        cnt = 0;
                    694:        while (*pp++ != NULL)
                    695:                cnt++;
                    696:        return (cnt);
1.1       downsj    697: }
                    698:
1.16      millert   699: #define        COPYLEFT(to, from)                              \
                    700:        do {                                            \
                    701:                len = strlcpy((to), (from), left);      \
                    702:                if (len >= left)                        \
                    703:                        return;                         \
                    704:                p += len;                               \
                    705:                left -= len;                            \
                    706:        } while (0)
                    707:
1.12      pvalchev  708: static void
1.16      millert   709: summary_format(char *buf, size_t left, int *numbers, char **names)
1.1       downsj    710: {
1.14      deraadt   711:        char *p, *thisname;
1.16      millert   712:        size_t len;
1.14      deraadt   713:        int num;
1.1       downsj    714:
1.14      deraadt   715:        /* format each number followed by its string */
1.16      millert   716:        p = buf;
1.14      deraadt   717:        while ((thisname = *names++) != NULL) {
                    718:                /* get the number to format */
                    719:                num = *numbers++;
                    720:
                    721:                if (num >= 0) {
                    722:                        /* is this number in kilobytes? */
                    723:                        if (thisname[0] == 'K') {
                    724:                                /* yes: format it as a memory value */
1.16      millert   725:                                COPYLEFT(p, format_k(num));
1.14      deraadt   726:
                    727:                                /*
                    728:                                 * skip over the K, since it was included by
                    729:                                 * format_k
                    730:                                 */
1.16      millert   731:                                COPYLEFT(p, thisname + 1);
1.14      deraadt   732:                        } else if (num > 0) {
1.16      millert   733:                                len = snprintf(p, left, "%d%s", num, thisname);
                    734:                                if (len == (size_t)-1 || len >= left)
                    735:                                        return;
                    736:                                p += len;
                    737:                                left -= len;
1.14      deraadt   738:                        }
1.16      millert   739:                } else {
                    740:                        /*
                    741:                         * Ignore negative numbers, but display corresponding
                    742:                         * string.
                    743:                         */
                    744:                        COPYLEFT(p, thisname);
1.14      deraadt   745:                }
1.1       downsj    746:        }
                    747:
1.14      deraadt   748:        /* if the last two characters in the string are ", ", delete them */
                    749:        p -= 2;
1.16      millert   750:        if (p >= buf && p[0] == ',' && p[1] == ' ')
1.14      deraadt   751:                *p = '\0';
1.1       downsj    752: }
                    753:
                    754: /*
                    755:  *  printable(str) - make the string pointed to by "str" into one that is
                    756:  *     printable (i.e.: all ascii), by converting all non-printable
                    757:  *     characters into '?'.  Replacements are done in place and a pointer
                    758:  *     to the original buffer is returned.
                    759:  */
1.12      pvalchev  760: char *
                    761: printable(char *str)
1.1       downsj    762: {
1.14      deraadt   763:        char *ptr, ch;
1.1       downsj    764:
1.14      deraadt   765:        ptr = str;
                    766:        while ((ch = *ptr) != '\0') {
                    767:                if (!isprint(ch))
                    768:                        *ptr = '?';
                    769:                ptr++;
1.1       downsj    770:        }
1.14      deraadt   771:        return (str);
1.25      otto      772: }
                    773:
                    774:
                    775: /*
                    776:  *  show_help() - display the help screen; invoked in response to
                    777:  *             either 'h' or '?'.
                    778:  */
                    779: void
                    780: show_help(void)
                    781: {
                    782:        if (smart_terminal) {
                    783:                clear();
                    784:                nl();
                    785:        }
                    786:        printwp("These single-character commands are available:\n"
                    787:            "\n"
                    788:            "^L           - redraw screen\n"
                    789:            "+            - reset any g, p, or u filters\n"
                    790:            "C            - toggle the display of command line arguments\n"
                    791:            "d count      - show `count' displays, then exit\n"
                    792:            "e            - list errors generated by last \"kill\" or \"renice\" command\n"
                    793:            "h | ?        - help; show this text\n"
                    794:            "g string     - filter on command name (g+ selects all commands)\n"
                    795:            "I | i        - toggle the display of idle processes\n"
                    796:            "k [-sig] pid - send signal `-sig' to process `pid'\n"
                    797:            "n|# count    - show `count' processes\n"
                    798:            "o field      - specify sort order (size, res, cpu, time, pri)\n"
                    799:            "P pid        - highlight process `pid' (P+ switches highlighting off)\n"
                    800:            "p pid        - display process by `pid' (p+ selects all processes)\n"
                    801:            "q            - quit\n"
                    802:            "r count pid  - renice process `pid' to nice value `count'\n"
                    803:            "S            - toggle the display of system processes\n"
                    804:            "s time       - change delay between displays to `time' seconds\n"
                    805:            "T            - toggle the display of threads\n"
                    806:            "u user       - display processes for `user' (u+ selects all users)\n"
                    807:            "\n");
                    808:
                    809:        if (smart_terminal) {
                    810:                nonl();
                    811:                refresh();
                    812:        }
                    813: }
                    814:
                    815: /*
                    816:  *  show_errors() - display on stdout the current log of errors.
                    817:  */
                    818: void
                    819: show_errors(void)
                    820: {
                    821:        struct errs *errp = errs;
                    822:        int cnt = 0;
                    823:
                    824:        if (smart_terminal) {
                    825:                clear();
                    826:                nl();
                    827:        }
                    828:        printwp("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
                    829:        while (cnt++ < errcnt) {
                    830:                printf("%5s: %s\n", errp->arg,
                    831:                    errp->err == 0 ? "Not a number" : strerror(errp->err));
                    832:                errp++;
                    833:        }
                    834:        if (smart_terminal) {
                    835:                nonl();
                    836:                refresh();
                    837:        }
                    838: }
                    839:
                    840: void
                    841: anykey(void)
                    842: {
                    843:        int ch;
1.28      deraadt   844:        ssize_t len;
1.25      otto      845:
                    846:        standoutp();
                    847:        addstrp("Hit any key to continue: ");
                    848:        standendp();
                    849:        if (smart_terminal)
                    850:                refresh();
                    851:        else
                    852:                fflush(stdout);
                    853:        while (1) {
                    854:                len = read(STDIN_FILENO, &ch, 1);
                    855:                if (len == -1 && errno == EINTR)
                    856:                        continue;
                    857:                if (len == 0)
                    858:                        exit(1);
                    859:                break;
                    860:        }
1.1       downsj    861: }