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

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