[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.26

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