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

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