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

1.16    ! millert     1: /* $OpenBSD: display.c,v 1.15 2003/06/18 08:36:31 deraadt Exp $         */
1.1       downsj      2:
                      3: /*
                      4:  *  Top users/processes display for Unix
                      5:  *  Version 3
                      6:  *
1.11      deraadt     7:  * Copyright (c) 1984, 1989, William LeFebvre, Rice University
                      8:  * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
1.1       downsj      9:  *
1.11      deraadt    10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     20:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     21:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     22:  * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT,
                     23:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     24:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     25:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     26:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     27:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     28:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.1       downsj     29:  */
                     30:
                     31: /*
                     32:  *  This file contains the routines that display information on the screen.
                     33:  *  Each section of the screen has two routines:  one for initially writing
                     34:  *  all constant and dynamic text, and one for only updating the text that
                     35:  *  changes.  The prefix "i_" is used on all the "initial" routines and the
                     36:  *  prefix "u_" is used for all the "updating" routines.
                     37:  *
                     38:  *  ASSUMPTIONS:
                     39:  *        None of the "i_" routines use any of the termcap capabilities.
                     40:  *        In this way, those routines can be safely used on terminals that
                     41:  *        have minimal (or nonexistant) terminal capabilities.
                     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>
                     49: #include <stdio.h>
1.1       downsj     50: #include <ctype.h>
1.2       downsj     51: #include <stdlib.h>
                     52: #include <string.h>
                     53: #include <term.h>
1.1       downsj     54: #include <time.h>
1.2       downsj     55: #include <unistd.h>
1.13      pvalchev   56: #include <stdarg.h>
1.1       downsj     57:
                     58: #include "screen.h"            /* interface to screen package */
                     59: #include "layout.h"            /* defines for screen position layout */
                     60: #include "display.h"
                     61: #include "top.h"
                     62: #include "top.local.h"
                     63: #include "boolean.h"
                     64: #include "machine.h"           /* we should eliminate this!!! */
                     65: #include "utils.h"
                     66:
                     67: #ifdef DEBUG
1.14      deraadt    68: FILE           *debug;
1.1       downsj     69: #endif
                     70:
1.14      deraadt    71: static pid_t    lmpid = 0;
                     72: static int      last_hi = 0;   /* used in u_process and u_endscreen */
                     73: static int      lastline = 0;
                     74: static int      display_width = MAX_COLS;
                     75:
                     76: static char    *cpustates_tag(void);
                     77: static int      string_count(char **);
1.16    ! millert    78: static void     summary_format(char *, size_t, int *, char **);
1.14      deraadt    79: static void     line_update(char *, char *, int, int);
1.2       downsj     80:
1.1       downsj     81: #define lineindex(l) ((l)*display_width)
                     82:
                     83: /* things initialized by display_init and used thruout */
                     84:
                     85: /* buffer of proc information lines for display updating */
1.14      deraadt    86: char           *screenbuf = NULL;
1.1       downsj     87:
1.14      deraadt    88: static char   **procstate_names;
                     89: static char   **cpustate_names;
                     90: static char   **memory_names;
                     91:
                     92: static int      num_procstates;
                     93: static int      num_cpustates;
                     94:
                     95: static int     *lprocstates;
                     96: static int     *lcpustates;
                     97:
                     98: static int     *cpustate_columns;
                     99: static int      cpustate_total_length;
                    100:
                    101: static enum {
                    102:        OFF, ON, ERASE
                    103: } header_status = ON;
1.1       downsj    104:
1.12      pvalchev  105: int
                    106: display_resize(void)
1.1       downsj    107: {
1.14      deraadt   108:        int display_lines;
1.1       downsj    109:
1.14      deraadt   110:        /* first, deallocate any previous buffer that may have been there */
                    111:        if (screenbuf != NULL)
                    112:                free(screenbuf);
                    113:
                    114:        /* calculate the current dimensions */
                    115:        /* if operating in "dumb" mode, we only need one line */
                    116:        display_lines = smart_terminal ? screen_length - Header_lines : 1;
                    117:
                    118:        /*
                    119:         * we don't want more than MAX_COLS columns, since the
                    120:         * machine-dependent modules make static allocations based on
                    121:         * MAX_COLS and we don't want to run off the end of their buffers
                    122:         */
                    123:        display_width = screen_width;
                    124:        if (display_width >= MAX_COLS)
                    125:                display_width = MAX_COLS - 1;
                    126:
                    127:        /* now, allocate space for the screen buffer */
                    128:        screenbuf = (char *) malloc(display_lines * display_width);
                    129:        if (screenbuf == (char *) NULL)
                    130:                return (-1);
                    131:
                    132:        /* return number of lines available */
                    133:        /* for dumb terminals, pretend like we can show any amount */
                    134:        return (smart_terminal ? display_lines : Largest);
1.1       downsj    135: }
                    136:
1.12      pvalchev  137: int
1.14      deraadt   138: display_init(struct statics * statics)
1.1       downsj    139: {
1.14      deraadt   140:        int display_lines, *ip, i;
                    141:        char **pp;
                    142:
                    143:        /* call resize to do the dirty work */
                    144:        display_lines = display_resize();
                    145:
                    146:        /* only do the rest if we need to */
                    147:        if (display_lines > -1) {
                    148:                /* save pointers and allocate space for names */
                    149:                procstate_names = statics->procstate_names;
                    150:                num_procstates = string_count(procstate_names);
                    151:                lprocstates = (int *) malloc(num_procstates * sizeof(int));
                    152:
                    153:                cpustate_names = statics->cpustate_names;
                    154:                num_cpustates = string_count(cpustate_names);
                    155:                lcpustates = (int *) malloc(num_cpustates * sizeof(int));
                    156:                cpustate_columns = (int *) malloc(num_cpustates * sizeof(int));
                    157:
                    158:                memory_names = statics->memory_names;
                    159:
                    160:                /* calculate starting columns where needed */
                    161:                cpustate_total_length = 0;
                    162:                pp = cpustate_names;
                    163:                ip = cpustate_columns;
                    164:                while (*pp != NULL) {
                    165:                        if ((i = strlen(*pp++)) > 0) {
                    166:                                *ip++ = cpustate_total_length;
                    167:                                cpustate_total_length += i + 8;
                    168:                        }
                    169:                }
1.1       downsj    170:        }
1.14      deraadt   171:        /* return number of lines available */
                    172:        return (display_lines);
1.1       downsj    173: }
                    174:
1.12      pvalchev  175: void
                    176: i_loadave(pid_t mpid, double *avenrun)
1.1       downsj    177: {
1.14      deraadt   178:        int i;
                    179:
                    180:        /* i_loadave also clears the screen, since it is first */
                    181:        clear();
1.1       downsj    182:
1.14      deraadt   183:        /* mpid == -1 implies this system doesn't have an _mpid */
                    184:        if (mpid != -1)
                    185:                printf("last pid: %5ld;  ", (long) mpid);
1.1       downsj    186:
1.14      deraadt   187:        printf("load averages");
                    188:
                    189:        for (i = 0; i < 3; i++)
                    190:                printf("%c %5.2f", i == 0 ? ':' : ',', avenrun[i]);
                    191:
                    192:        lmpid = mpid;
1.1       downsj    193: }
                    194:
1.12      pvalchev  195: void
                    196: u_loadave(pid_t mpid, double *avenrun)
1.1       downsj    197: {
1.14      deraadt   198:        int i;
1.1       downsj    199:
1.14      deraadt   200:        if (mpid != -1) {
                    201:                /* change screen only when value has really changed */
                    202:                if (mpid != lmpid) {
                    203:                        Move_to(x_lastpid, y_lastpid);
                    204:                        printf("%5ld", (long) mpid);
                    205:                        lmpid = mpid;
                    206:                }
                    207:                /* i remembers x coordinate to move to */
                    208:                i = x_loadave;
                    209:        } else
                    210:                i = x_loadave_nompid;
                    211:
                    212:        /* move into position for load averages */
                    213:        Move_to(i, y_loadave);
                    214:
                    215:        /* display new load averages */
                    216:        /* we should optimize this and only display changes */
                    217:        for (i = 0; i < 3; i++)
                    218:                printf("%s%5.2f", i == 0 ? "" : ", ", avenrun[i]);
1.1       downsj    219: }
                    220:
1.14      deraadt   221: /*
                    222:  *  Display the current time.
                    223:  *  "ctime" always returns a string that looks like this:
                    224:  *
                    225:  *     Sun Sep 16 01:03:52 1973
                    226:  *      012345678901234567890123
                    227:  *               1         2
                    228:  *
                    229:  *  We want indices 11 thru 18 (length 8).
                    230:  */
                    231:
1.12      pvalchev  232: void
1.14      deraadt   233: i_timeofday(time_t * tod)
1.1       downsj    234: {
1.14      deraadt   235:
                    236:        if (smart_terminal) {
                    237:                Move_to(screen_width - 8, 0);
                    238:        } else {
                    239:                if (fputs("    ", stdout) == EOF)
                    240:                        exit(1);
                    241:        }
1.1       downsj    242: #ifdef DEBUG
1.14      deraadt   243:        {
                    244:                char *foo;
                    245:                foo = ctime(tod);
                    246:                if (fputs(foo, stdout) == EOF)
                    247:                        exit(1);
                    248:        }
1.1       downsj    249: #endif
1.14      deraadt   250:        printf("%-8.8s\n", &(ctime(tod)[11]));
                    251:        lastline = 1;
1.1       downsj    252: }
                    253:
1.14      deraadt   254: static int      ltotal = 0;
                    255: static char     procstates_buffer[128];
1.1       downsj    256:
                    257: /*
                    258:  *  *_procstates(total, brkdn, names) - print the process summary line
                    259:  *
                    260:  *  Assumptions:  cursor is at the beginning of the line on entry
                    261:  *               lastline is valid
                    262:  */
1.12      pvalchev  263: void
                    264: i_procstates(int total, int *brkdn)
1.1       downsj    265: {
1.14      deraadt   266:        int i;
1.1       downsj    267:
1.14      deraadt   268:        /* write current number of processes and remember the value */
                    269:        printf("%d processes:", total);
                    270:        ltotal = total;
                    271:
                    272:        /* put out enough spaces to get to column 15 */
                    273:        i = digits(total);
                    274:        while (i++ < 4) {
                    275:                if (putchar(' ') == EOF)
                    276:                        exit(1);
                    277:        }
                    278:
                    279:        /* format and print the process state summary */
1.16    ! millert   280:        summary_format(procstates_buffer, sizeof(procstates_buffer), brkdn,
        !           281:            procstate_names);
1.14      deraadt   282:        if (fputs(procstates_buffer, stdout) == EOF)
1.5       deraadt   283:                exit(1);
1.1       downsj    284:
1.14      deraadt   285:        /* save the numbers for next time */
                    286:        memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
1.1       downsj    287: }
                    288:
1.12      pvalchev  289: void
                    290: u_procstates(int total, int *brkdn)
1.1       downsj    291: {
1.14      deraadt   292:        static char new[128];
                    293:        int i;
1.1       downsj    294:
1.14      deraadt   295:        /* update number of processes only if it has changed */
                    296:        if (ltotal != total) {
                    297:                /* move and overwrite */
1.1       downsj    298: #if (x_procstate == 0)
1.14      deraadt   299:                Move_to(x_procstate, y_procstate);
1.1       downsj    300: #else
1.14      deraadt   301:                /* cursor is already there...no motion needed */
                    302:                /* assert(lastline == 1); */
1.1       downsj    303: #endif
1.14      deraadt   304:                printf("%d", total);
1.1       downsj    305:
1.14      deraadt   306:                /* if number of digits differs, rewrite the label */
                    307:                if (digits(total) != digits(ltotal)) {
                    308:                        if (fputs(" processes:", stdout) == EOF)
                    309:                                exit(1);
                    310:                        /* put out enough spaces to get to column 15 */
                    311:                        i = digits(total);
                    312:                        while (i++ < 4) {
                    313:                                if (putchar(' ') == EOF)
                    314:                                        exit(1);
                    315:                        }
                    316:                        /* cursor may end up right where we want it!!! */
                    317:                }
                    318:                /* save new total */
                    319:                ltotal = total;
                    320:        }
                    321:        /* see if any of the state numbers has changed */
                    322:        if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) {
                    323:                /* format and update the line */
1.16    ! millert   324:                summary_format(new, sizeof(new), brkdn, procstate_names);
1.14      deraadt   325:                line_update(procstates_buffer, new, x_brkdn, y_brkdn);
                    326:                memcpy(lprocstates, brkdn, num_procstates * sizeof(int));
1.1       downsj    327:        }
                    328: }
                    329:
                    330: /*
                    331:  *  *_cpustates(states, names) - print the cpu state percentages
                    332:  *
                    333:  *  Assumptions:  cursor is on the PREVIOUS line
                    334:  */
                    335:
1.14      deraadt   336: static int      cpustates_column;
1.1       downsj    337:
                    338: /* cpustates_tag() calculates the correct tag to use to label the line */
                    339:
1.12      pvalchev  340: static char *
                    341: cpustates_tag(void)
1.1       downsj    342: {
1.14      deraadt   343:        static char *short_tag = "CPU: ";
                    344:        static char *long_tag = "CPU states: ";
                    345:        char *use;
                    346:
                    347:        /*
                    348:         * if length + strlen(long_tag) >= screen_width, then we have to use
                    349:         * the shorter tag (we subtract 2 to account for ": ")
                    350:         */
                    351:        if (cpustate_total_length + (int) strlen(long_tag) - 2 >= screen_width)
                    352:                use = short_tag;
                    353:        else
                    354:                use = long_tag;
1.1       downsj    355:
1.14      deraadt   356:        /* set cpustates_column accordingly then return result */
                    357:        cpustates_column = strlen(use);
                    358:        return (use);
1.1       downsj    359: }
                    360:
1.12      pvalchev  361: void
                    362: i_cpustates(int *states)
1.1       downsj    363: {
1.14      deraadt   364:        int i = 0, value;
                    365:        char **names = cpustate_names, *thisname;
                    366:
                    367:        /* print tag and bump lastline */
                    368:        printf("\n%s", cpustates_tag());
                    369:        lastline++;
1.1       downsj    370:
1.14      deraadt   371:        /* now walk thru the names and print the line */
                    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% */
                    378:                        printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
                    379:                            i++ == 0 ? "" : ", ",
                    380:                            ((float) value) / 10.,
                    381:                            thisname);
                    382:                }
1.1       downsj    383:        }
                    384:
1.14      deraadt   385:        /* copy over values into "last" array */
                    386:        memcpy(lcpustates, states, num_cpustates * sizeof(int));
1.1       downsj    387: }
                    388:
1.12      pvalchev  389: void
                    390: u_cpustates(int *states)
1.1       downsj    391: {
1.14      deraadt   392:        char **names = cpustate_names, *thisname;
                    393:        int value, *lp, *colp;
                    394:
                    395:        Move_to(cpustates_column, y_cpustates);
                    396:        lastline = y_cpustates;
                    397:        lp = lcpustates;
                    398:        colp = cpustate_columns;
                    399:
                    400:        /* we could be much more optimal about this */
                    401:        while ((thisname = *names++) != NULL) {
                    402:                if (*thisname != '\0') {
                    403:                        /* did the value change since last time? */
                    404:                        if (*lp != *states) {
                    405:                                /* yes, move and change */
                    406:                                Move_to(cpustates_column + *colp, y_cpustates);
                    407:                                lastline = y_cpustates;
                    408:
                    409:                                /* retrieve value and remember it */
                    410:                                value = *states;
                    411:
                    412:                                /* if percentage is >= 1000, print it as 100% */
                    413:                                printf((value >= 1000 ? "%4.0f" : "%4.1f"),
                    414:                                    ((double) value) / 10.);
                    415:
                    416:                                /* remember it for next time */
                    417:                                *lp = *states;
                    418:                        }
                    419:                }
                    420:                /* increment and move on */
                    421:                lp++;
                    422:                states++;
                    423:                colp++;
                    424:        }
1.1       downsj    425: }
                    426:
1.12      pvalchev  427: void
                    428: z_cpustates(void)
1.1       downsj    429: {
1.14      deraadt   430:        char **names = cpustate_names, *thisname;
                    431:        int i = 0, *lp;
                    432:
                    433:        /* show tag and bump lastline */
                    434:        printf("\n%s", cpustates_tag());
                    435:        lastline++;
                    436:
                    437:        while ((thisname = *names++) != NULL) {
                    438:                if (*thisname != '\0')
                    439:                        printf("%s    %% %s", i++ == 0 ? "" : ", ", thisname);
1.1       downsj    440:        }
                    441:
1.14      deraadt   442:        /* fill the "last" array with all -1s, to insure correct updating */
                    443:        lp = lcpustates;
                    444:        i = num_cpustates;
                    445:        while (--i >= 0)
                    446:                *lp++ = -1;
1.1       downsj    447: }
                    448:
1.14      deraadt   449: static char     memory_buffer[MAX_COLS];
                    450:
1.1       downsj    451: /*
                    452:  *  *_memory(stats) - print "Memory: " followed by the memory summary string
                    453:  *
                    454:  *  Assumptions:  cursor is on "lastline"
                    455:  *                for i_memory ONLY: cursor is on the previous line
                    456:  */
1.12      pvalchev  457: void
                    458: i_memory(int *stats)
1.1       downsj    459: {
1.14      deraadt   460:        if (fputs("\nMemory: ", stdout) == EOF)
                    461:                exit(1);
                    462:        lastline++;
                    463:
                    464:        /* format and print the memory summary */
1.16    ! millert   465:        summary_format(memory_buffer, sizeof(memory_buffer), stats,
        !           466:            memory_names);
1.14      deraadt   467:        if (fputs(memory_buffer, stdout) == EOF)
                    468:                exit(1);
1.1       downsj    469: }
                    470:
1.12      pvalchev  471: void
                    472: u_memory(int *stats)
1.1       downsj    473: {
1.14      deraadt   474:        static char new[MAX_COLS];
1.1       downsj    475:
1.14      deraadt   476:        /* format the new line */
1.16    ! millert   477:        summary_format(new, sizeof(new), stats, memory_names);
1.14      deraadt   478:        line_update(memory_buffer, new, x_mem, y_mem);
1.1       downsj    479: }
                    480:
                    481: /*
                    482:  *  *_message() - print the next pending message line, or erase the one
                    483:  *                that is there.
                    484:  *
                    485:  *  Note that u_message is (currently) the same as i_message.
                    486:  *
                    487:  *  Assumptions:  lastline is consistent
                    488:  */
                    489:
                    490: /*
                    491:  *  i_message is funny because it gets its message asynchronously (with
                    492:  *     respect to screen updates).
                    493:  */
                    494:
1.14      deraadt   495: static char     next_msg[MAX_COLS + 5];
                    496: static int      msglen = 0;
                    497: /*
                    498:  * Invariant: msglen is always the length of the message currently displayed
                    499:  * on the screen (even when next_msg doesn't contain that message).
                    500:  */
1.1       downsj    501:
1.12      pvalchev  502: void
                    503: i_message(void)
1.1       downsj    504: {
1.14      deraadt   505:        while (lastline < y_message) {
                    506:                if (fputc('\n', stdout) == EOF)
                    507:                        exit(1);
                    508:                lastline++;
                    509:        }
                    510:        if (next_msg[0] != '\0') {
                    511:                standout(next_msg);
                    512:                msglen = strlen(next_msg);
                    513:                next_msg[0] = '\0';
                    514:        } else if (msglen > 0) {
                    515:                (void) clear_eol(msglen);
                    516:                msglen = 0;
                    517:        }
1.1       downsj    518: }
                    519:
1.12      pvalchev  520: void
                    521: u_message(void)
1.1       downsj    522: {
1.14      deraadt   523:        i_message();
1.1       downsj    524: }
                    525:
1.14      deraadt   526: static int      header_length;
1.1       downsj    527:
                    528: /*
                    529:  *  *_header(text) - print the header for the process area
                    530:  *
                    531:  *  Assumptions:  cursor is on the previous line and lastline is consistent
                    532:  */
                    533:
1.12      pvalchev  534: void
                    535: i_header(char *text)
1.1       downsj    536: {
1.14      deraadt   537:        header_length = strlen(text);
                    538:        if (header_status == ON) {
                    539:                if (putchar('\n') == EOF)
                    540:                        exit(1);
                    541:                if (fputs(text, stdout) == EOF)
                    542:                        exit(1);
                    543:                lastline++;
                    544:        } else if (header_status == ERASE) {
                    545:                header_status = OFF;
                    546:        }
1.1       downsj    547: }
                    548:
1.14      deraadt   549: /* ARGSUSED */
1.12      pvalchev  550: void
                    551: u_header(char *text)
1.1       downsj    552: {
1.14      deraadt   553:        if (header_status == ERASE) {
                    554:                if (putchar('\n') == EOF)
                    555:                        exit(1);
                    556:                lastline++;
                    557:                clear_eol(header_length);
                    558:                header_status = OFF;
                    559:        }
1.1       downsj    560: }
                    561:
                    562: /*
                    563:  *  *_process(line, thisline) - print one process line
                    564:  *
                    565:  *  Assumptions:  lastline is consistent
                    566:  */
                    567:
1.12      pvalchev  568: void
                    569: i_process(int line, char *thisline)
1.1       downsj    570: {
1.16    ! millert   571:        char *base;
        !           572:        size_t len;
1.1       downsj    573:
1.14      deraadt   574:        /* make sure we are on the correct line */
                    575:        while (lastline < y_procs + line) {
                    576:                if (putchar('\n') == EOF)
                    577:                        exit(1);
                    578:                lastline++;
                    579:        }
1.1       downsj    580:
1.14      deraadt   581:        /* truncate the line to conform to our current screen width */
                    582:        thisline[display_width] = '\0';
1.1       downsj    583:
1.14      deraadt   584:        /* write the line out */
                    585:        if (fputs(thisline, stdout) == EOF)
                    586:                exit(1);
1.1       downsj    587:
1.14      deraadt   588:        /* copy it in to our buffer */
                    589:        base = smart_terminal ? screenbuf + lineindex(line) : screenbuf;
1.16    ! millert   590:        len = strlcpy(base, thisline, display_width);
        !           591:        if (len < (size_t)display_width) {
        !           592:                /* zero fill the rest of it */
        !           593:                memset(base + len, 0, display_width - len);
        !           594:        }
1.1       downsj    595: }
                    596:
1.12      pvalchev  597: void
                    598: u_process(int linenum, char *linebuf)
1.1       downsj    599: {
1.14      deraadt   600:        int screen_line = linenum + Header_lines;
1.16    ! millert   601:        char *bufferline;
        !           602:        size_t len;
1.14      deraadt   603:
                    604:        /* remember a pointer to the current line in the screen buffer */
                    605:        bufferline = &screenbuf[lineindex(linenum)];
                    606:
                    607:        /* truncate the line to conform to our current screen width */
                    608:        linebuf[display_width] = '\0';
                    609:
                    610:        /* is line higher than we went on the last display? */
                    611:        if (linenum >= last_hi) {
                    612:                /* yes, just ignore screenbuf and write it out directly */
                    613:                /* get positioned on the correct line */
                    614:                if (screen_line - lastline == 1) {
                    615:                        if (putchar('\n') == EOF)
                    616:                                exit(1);
                    617:                        lastline++;
                    618:                } else {
                    619:                        Move_to(0, screen_line);
                    620:                        lastline = screen_line;
                    621:                }
1.1       downsj    622:
1.14      deraadt   623:                /* now write the line */
                    624:                if (fputs(linebuf, stdout) == EOF)
                    625:                        exit(1);
1.1       downsj    626:
1.14      deraadt   627:                /* copy it in to the buffer */
1.16    ! millert   628:                len = strlcpy(bufferline, linebuf, display_width);
        !           629:                if (len < (size_t)display_width) {
        !           630:                        /* zero fill the rest of it */
        !           631:                        memset(bufferline + len, 0, display_width - len);
        !           632:                }
1.14      deraadt   633:        } else {
                    634:                line_update(bufferline, linebuf, 0, linenum + Header_lines);
                    635:        }
1.1       downsj    636: }
                    637:
1.12      pvalchev  638: void
                    639: u_endscreen(int hi)
1.1       downsj    640: {
1.14      deraadt   641:        int screen_line = hi + Header_lines, i;
1.1       downsj    642:
1.14      deraadt   643:        if (smart_terminal) {
                    644:                if (hi < last_hi) {
                    645:                        /* need to blank the remainder of the screen */
                    646:                        /*
                    647:                         * but only if there is any screen left below this
                    648:                         * line
                    649:                         */
                    650:                        if (lastline + 1 < screen_length) {
                    651:                                /*
                    652:                                 * efficiently move to the end of currently
                    653:                                 * displayed info
                    654:                                 */
                    655:                                if (screen_line - lastline < 5) {
                    656:                                        while (lastline < screen_line) {
                    657:                                                if (putchar('\n') == EOF)
                    658:                                                        exit(1);
                    659:                                                lastline++;
                    660:                                        }
                    661:                                } else {
                    662:                                        Move_to(0, screen_line);
                    663:                                        lastline = screen_line;
                    664:                                }
                    665:
                    666:                                if (clear_to_end) {
                    667:                                        /* we can do this the easy way */
                    668:                                        putcap(clear_to_end);
                    669:                                } else {
                    670:                                        /* use clear_eol on each line */
                    671:                                        i = hi;
                    672:                                        while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) {
                    673:                                                if (putchar('\n') == EOF)
                    674:                                                        exit(1);
                    675:                                        }
                    676:                                }
                    677:                        }
1.1       downsj    678:                }
1.14      deraadt   679:                last_hi = hi;
1.1       downsj    680:
1.14      deraadt   681:                /* move the cursor to a pleasant place */
                    682:                Move_to(x_idlecursor, y_idlecursor);
                    683:                lastline = y_idlecursor;
                    684:        } else {
                    685:                /*
                    686:                 * separate this display from the next with some vertical
                    687:                 * room
                    688:                 */
                    689:                if (fputs("\n\n", stdout) == EOF)
                    690:                        exit(1);
1.1       downsj    691:        }
                    692: }
                    693:
1.12      pvalchev  694: void
                    695: display_header(int t)
1.1       downsj    696: {
1.14      deraadt   697:        if (t) {
                    698:                header_status = ON;
                    699:        } else if (header_status == ON) {
                    700:                header_status = ERASE;
                    701:        }
1.1       downsj    702: }
                    703:
1.12      pvalchev  704: void
1.14      deraadt   705: new_message(int type, const char *msgfmt,...)
                    706: {
                    707:        va_list ap;
                    708:        int i;
                    709:
                    710:        va_start(ap, msgfmt);
                    711:        /* first, format the message */
                    712:        vsnprintf(next_msg, sizeof(next_msg), msgfmt, ap);
                    713:        va_end(ap);
                    714:
                    715:        if (msglen > 0) {
                    716:                /* message there already -- can we clear it? */
                    717:                if (!overstrike) {
                    718:                        /* yes -- write it and clear to end */
                    719:                        i = strlen(next_msg);
                    720:                        if ((type & MT_delayed) == 0) {
                    721:                                if (type & MT_standout)
                    722:                                        standout(next_msg);
                    723:                                else {
                    724:                                        if (fputs(next_msg, stdout) == EOF)
                    725:                                                exit(1);
                    726:                                }
                    727:                                (void) clear_eol(msglen - i);
                    728:                                msglen = i;
                    729:                                next_msg[0] = '\0';
                    730:                        }
                    731:                }
                    732:        } else {
                    733:                if ((type & MT_delayed) == 0) {
                    734:                        if (type & MT_standout)
                    735:                                standout(next_msg);
                    736:                        else {
                    737:                                if (fputs(next_msg, stdout) == EOF)
                    738:                                        exit(1);
                    739:                        }
                    740:                        msglen = strlen(next_msg);
                    741:                        next_msg[0] = '\0';
1.5       deraadt   742:                }
1.1       downsj    743:        }
                    744: }
                    745:
1.12      pvalchev  746: void
                    747: clear_message(void)
1.1       downsj    748: {
1.14      deraadt   749:        if (clear_eol(msglen) == 1) {
                    750:                if (putchar('\r') == EOF)
                    751:                        exit(1);
                    752:        }
1.1       downsj    753: }
                    754:
1.12      pvalchev  755: int
                    756: readline(char *buffer, int size, int numeric)
1.1       downsj    757: {
1.14      deraadt   758:        char *ptr = buffer, ch, cnt = 0, maxcnt = 0;
                    759:
                    760:        /* allow room for null terminator */
                    761:        size -= 1;
                    762:
                    763:        /* read loop */
                    764:        while ((fflush(stdout), read(0, ptr, 1) > 0)) {
                    765:                /* newline means we are done */
                    766:                if ((ch = *ptr) == '\n')
                    767:                        break;
                    768:
                    769:                /* handle special editing characters */
                    770:                if (ch == ch_kill) {
                    771:                        /* kill line -- account for overstriking */
                    772:                        if (overstrike)
                    773:                                msglen += maxcnt;
                    774:
                    775:                        /* return null string */
                    776:                        *buffer = '\0';
                    777:                        if (putchar('\r') == EOF)
                    778:                                exit(1);
                    779:                        return (-1);
                    780:                } else if (ch == ch_erase) {
                    781:                        /* erase previous character */
                    782:                        if (cnt <= 0) {
                    783:                                /* none to erase! */
                    784:                                if (putchar('\7') == EOF)
                    785:                                        exit(1);
                    786:                        } else {
                    787:                                if (fputs("\b \b", stdout) == EOF)
                    788:                                        exit(1);
                    789:                                ptr--;
                    790:                                cnt--;
                    791:                        }
                    792:                }
                    793:                /* check for character validity and buffer overflow */
                    794:                else if (cnt == size || (numeric && !isdigit(ch)) ||
                    795:                    !isprint(ch)) {
                    796:                        /* not legal */
                    797:                        if (putchar('\7') == EOF)
                    798:                                exit(1);
                    799:                } else {
                    800:                        /* echo it and store it in the buffer */
                    801:                        if (putchar(ch) == EOF)
                    802:                                exit(1);
                    803:                        ptr++;
                    804:                        cnt++;
                    805:                        if (cnt > maxcnt)
                    806:                                maxcnt = cnt;
                    807:                }
1.1       downsj    808:        }
                    809:
1.14      deraadt   810:        /* all done -- null terminate the string */
                    811:        *ptr = '\0';
                    812:
                    813:        /* account for the extra characters in the message area */
                    814:        /* (if terminal overstrikes, remember the furthest they went) */
                    815:        msglen += overstrike ? maxcnt : cnt;
                    816:
                    817:        /* return either inputted number or string length */
                    818:        if (putchar('\r') == EOF)
1.5       deraadt   819:                exit(1);
1.14      deraadt   820:        return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
1.1       downsj    821: }
                    822:
                    823: /* internal support routines */
1.12      pvalchev  824: static int
                    825: string_count(char **pp)
1.1       downsj    826: {
1.14      deraadt   827:        int cnt;
1.1       downsj    828:
1.14      deraadt   829:        cnt = 0;
                    830:        while (*pp++ != NULL)
                    831:                cnt++;
                    832:        return (cnt);
1.1       downsj    833: }
                    834:
1.16    ! millert   835: #define        COPYLEFT(to, from)                              \
        !           836:        do {                                            \
        !           837:                len = strlcpy((to), (from), left);      \
        !           838:                if (len >= left)                        \
        !           839:                        return;                         \
        !           840:                p += len;                               \
        !           841:                left -= len;                            \
        !           842:        } while (0)
        !           843:
1.12      pvalchev  844: static void
1.16    ! millert   845: summary_format(char *buf, size_t left, int *numbers, char **names)
1.1       downsj    846: {
1.14      deraadt   847:        char *p, *thisname;
1.16    ! millert   848:        size_t len;
1.14      deraadt   849:        int num;
1.1       downsj    850:
1.14      deraadt   851:        /* format each number followed by its string */
1.16    ! millert   852:        p = buf;
1.14      deraadt   853:        while ((thisname = *names++) != NULL) {
                    854:                /* get the number to format */
                    855:                num = *numbers++;
                    856:
                    857:                if (num >= 0) {
                    858:                        /* is this number in kilobytes? */
                    859:                        if (thisname[0] == 'K') {
                    860:                                /* yes: format it as a memory value */
1.16    ! millert   861:                                COPYLEFT(p, format_k(num));
1.14      deraadt   862:
                    863:                                /*
                    864:                                 * skip over the K, since it was included by
                    865:                                 * format_k
                    866:                                 */
1.16    ! millert   867:                                COPYLEFT(p, thisname + 1);
1.14      deraadt   868:                        } else if (num > 0) {
1.16    ! millert   869:                                len = snprintf(p, left, "%d%s", num, thisname);
        !           870:                                if (len == (size_t)-1 || len >= left)
        !           871:                                        return;
        !           872:                                p += len;
        !           873:                                left -= len;
1.14      deraadt   874:                        }
1.16    ! millert   875:                } else {
        !           876:                        /*
        !           877:                         * Ignore negative numbers, but display corresponding
        !           878:                         * string.
        !           879:                         */
        !           880:                        COPYLEFT(p, thisname);
1.14      deraadt   881:                }
1.1       downsj    882:        }
                    883:
1.14      deraadt   884:        /* if the last two characters in the string are ", ", delete them */
                    885:        p -= 2;
1.16    ! millert   886:        if (p >= buf && p[0] == ',' && p[1] == ' ')
1.14      deraadt   887:                *p = '\0';
1.1       downsj    888: }
                    889:
1.12      pvalchev  890: static void
                    891: line_update(char *old, char *new, int start, int line)
1.1       downsj    892: {
1.14      deraadt   893:        int ch, diff, newcol = start + 1, lastcol = start;
                    894:        char cursor_on_line = No, *current;
1.1       downsj    895:
1.14      deraadt   896:        /* compare the two strings and only rewrite what has changed */
                    897:        current = old;
1.1       downsj    898: #ifdef DEBUG
1.14      deraadt   899:        fprintf(debug, "line_update, starting at %d\n", start);
                    900:        fputs(old, debug);
                    901:        fputc('\n', debug);
                    902:        fputs(new, debug);
                    903:        fputs("\n-\n", debug);
1.1       downsj    904: #endif
                    905:
1.14      deraadt   906:        /* start things off on the right foot               */
                    907:        /* this is to make sure the invariants get set up right */
                    908:        if ((ch = *new++) != *old) {
                    909:                if (line - lastline == 1 && start == 0) {
                    910:                        if (putchar('\n') == EOF)
                    911:                                exit(1);
                    912:                } else
                    913:                        Move_to(start, line);
                    914:
                    915:                cursor_on_line = Yes;
                    916:                if (putchar(ch) == EOF)
                    917:                        exit(1);
                    918:                *old = ch;
                    919:                lastcol = 1;
1.1       downsj    920:        }
                    921:        old++;
                    922:
1.14      deraadt   923:        /*
                    924:         *  main loop -- check each character.  If the old and new aren't the
                    925:         *      same, then update the display.  When the distance from the
                    926:         *      current cursor position to the new change is small enough,
                    927:         *      the characters that belong there are written to move the
                    928:         *      cursor over.
                    929:         *
                    930:         *      Invariants:
                    931:         *          lastcol is the column where the cursor currently is sitting
                    932:         *              (always one beyond the end of the last mismatch).
                    933:         */
                    934:        do {
                    935:                if ((ch = *new++) != *old) {
                    936:                        /* new character is different from old    */
                    937:                        /* make sure the cursor is on top of this character */
                    938:                        diff = newcol - lastcol;
                    939:                        if (diff > 0) {
                    940:                                /*
                    941:                                 * some motion is required--figure out which
                    942:                                 * is shorter
                    943:                                 */
                    944:                                if (diff < 6 && cursor_on_line) {
                    945:                                        /*
                    946:                                         * overwrite old stuff--get it out of
                    947:                                         * the old buffer
                    948:                                         */
                    949:                                        printf("%.*s", diff, &current[lastcol - start]);
                    950:                                } else {
                    951:                                        /* use cursor addressing */
                    952:                                        Move_to(newcol, line);
                    953:                                        cursor_on_line = Yes;
                    954:                                }
                    955:                                /* remember where the cursor is */
                    956:                                lastcol = newcol + 1;
                    957:                        } else {
                    958:                                /* already there, update position */
                    959:                                lastcol++;
                    960:                        }
                    961:
                    962:                        /* write what we need to */
                    963:                        if (ch == '\0') {
                    964:                                /*
                    965:                                 * at the end--terminate with a
                    966:                                 * clear-to-end-of-line
                    967:                                 */
                    968:                                (void) clear_eol(strlen(old));
                    969:                        } else {
                    970:                                /* write the new character */
                    971:                                if (putchar(ch) == EOF)
                    972:                                        exit(1);
                    973:                        }
                    974:                        /* put the new character in the screen buffer */
                    975:                        *old = ch;
                    976:                }
                    977:                /* update working column and screen buffer pointer */
                    978:                newcol++;
                    979:                old++;
                    980:        } while (ch != '\0');
                    981:
                    982:        /* zero out the rest of the line buffer -- MUST BE DONE! */
                    983:        diff = display_width - newcol;
                    984:        if (diff > 0)
                    985:                memset(old, 0, diff);
                    986:
                    987:        /* remember where the current line is */
                    988:        if (cursor_on_line)
                    989:                lastline = line;
1.1       downsj    990: }
                    991:
                    992: /*
                    993:  *  printable(str) - make the string pointed to by "str" into one that is
                    994:  *     printable (i.e.: all ascii), by converting all non-printable
                    995:  *     characters into '?'.  Replacements are done in place and a pointer
                    996:  *     to the original buffer is returned.
                    997:  */
1.12      pvalchev  998: char *
                    999: printable(char *str)
1.1       downsj   1000: {
1.14      deraadt  1001:        char *ptr, ch;
1.1       downsj   1002:
1.14      deraadt  1003:        ptr = str;
                   1004:        while ((ch = *ptr) != '\0') {
                   1005:                if (!isprint(ch))
                   1006:                        *ptr = '?';
                   1007:                ptr++;
1.1       downsj   1008:        }
1.14      deraadt  1009:        return (str);
1.1       downsj   1010: }