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

Annotation of src/usr.bin/systat/engine.c, Revision 1.28

1.28    ! martijn     1: /* $OpenBSD: engine.c,v 1.27 2021/02/06 06:19:28 tb Exp $       */
1.1       canacar     2: /*
                      3:  * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17:
                     18:
1.10      chl        19: #include <sys/ioctl.h>
1.1       canacar    20: #include <sys/types.h>
                     21: #include <sys/queue.h>
                     22:
                     23: #include <ctype.h>
                     24: #include <curses.h>
                     25: #include <signal.h>
                     26: #include <stdlib.h>
                     27: #include <string.h>
1.8       canacar    28: #include <term.h>
1.1       canacar    29: #include <unistd.h>
1.12      lum        30: #include <err.h>
1.1       canacar    31:
1.8       canacar    32: /* XXX These are defined in term.h and conflict with our variable names */
                     33: #ifdef columns
                     34: #undef columns
                     35: #endif
                     36:
                     37: #ifdef lines
                     38: #undef lines
                     39: #endif
                     40:
1.1       canacar    41: #include "engine.h"
                     42:
1.18      deraadt    43: #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
1.1       canacar    44:
                     45: /* circular linked list of views */
1.17      krw        46: TAILQ_HEAD(view_list, view_ent) view_head =
                     47:                                  TAILQ_HEAD_INITIALIZER(view_head);
1.1       canacar    48: struct view_ent {
                     49:        field_view *view;
1.17      krw        50:        TAILQ_ENTRY(view_ent) entries;
1.1       canacar    51: };
                     52:
                     53: useconds_t udelay = 5000000;
                     54: int dispstart = 0;
1.25      martijn    55: int humanreadable = 0;
1.1       canacar    56: int interactive = 1;
1.15      reyk       57: int averageonly = 0;
1.1       canacar    58: int maxprint = 0;
                     59: int paused = 0;
                     60: int rawmode = 0;
                     61: int rawwidth = DEFAULT_WIDTH;
                     62: int sortdir = 1;
                     63: int columns, lines;
                     64: u_int32_t num_disp = 0;
                     65: int max_disp = -1;
                     66:
                     67: volatile sig_atomic_t gotsig_close = 0;
                     68: volatile sig_atomic_t gotsig_resize = 0;
                     69: volatile sig_atomic_t gotsig_alarm = 0;
                     70: int need_update = 0;
                     71: int need_sort = 0;
1.14      mpf        72: int separate_thousands = 0;
1.1       canacar    73:
                     74: SCREEN *screen;
                     75:
                     76: field_view *curr_view = NULL;
                     77: struct view_ent *curr_view_ent = NULL;
                     78: struct view_manager *curr_mgr = NULL;
                     79:
                     80: int curr_line = 0;
                     81: int home_line = 0;
                     82:
                     83: /* line buffer for raw mode */
                     84: char linebuf[MAX_LINE_BUF];
                     85: int linepos = 0;
                     86:
                     87: /* temp storage for state printing */
                     88: char tmp_buf[MAX_LINE_BUF];
                     89:
                     90: char cmdbuf[MAX_LINE_BUF];
                     91: int cmd_len = -1;
                     92: struct command *curr_cmd = NULL;
                     93: char *curr_message = NULL;
1.28    ! martijn    94: enum message_mode message_mode = MESSAGE_NONE;
        !            95: int message_cont = 1;
1.1       canacar    96:
                     97: void print_cmdline(void);
                     98:
                     99:
                    100: /* screen output functions */
                    101:
                    102: char * tb_ptr = NULL;
                    103: int tb_len = 0;
                    104:
                    105: void
                    106: tb_start(void)
                    107: {
                    108:        tb_ptr = tmp_buf;
                    109:        tb_len = sizeof(tmp_buf);
                    110:        tb_ptr[0] = '\0';
                    111: }
                    112:
                    113: void
                    114: tb_end(void)
                    115: {
                    116:        tb_ptr = NULL;
                    117:        tb_len = 0;
                    118: }
                    119:
                    120: int
                    121: tbprintf(char *format, ...)
                    122:        GCC_PRINTFLIKE(1,2)       /* defined in curses.h */
                    123: {
                    124:        int len;
                    125:        va_list arg;
                    126:
                    127:        if (tb_ptr == NULL || tb_len <= 0)
                    128:                return 0;
                    129:
                    130:        va_start(arg, format);
1.20      deraadt   131:        len = vsnprintf(tb_ptr, tb_len, format, arg);
1.1       canacar   132:        va_end(arg);
1.26      jasper    133:
1.1       canacar   134:        if (len > tb_len)
                    135:                tb_end();
                    136:        else if (len > 0) {
                    137:                tb_ptr += len;
                    138:                tb_len -= len;
                    139:        }
1.14      mpf       140:
                    141:        return len;
                    142: }
                    143:
                    144: int
                    145: tbprintft(char *format, ...)
                    146:        GCC_PRINTFLIKE(1,2)       /* defined in curses.h */
                    147: {
                    148:        int len;
                    149:        va_list arg;
                    150:        char buf[MAX_LINE_BUF];
                    151:
                    152:        if (tb_ptr == NULL || tb_len <= 0)
                    153:                return 0;
                    154:
                    155:        va_start(arg, format);
                    156:        len = vsnprintf(buf, tb_len, format, arg);
                    157:        va_end(arg);
                    158:
                    159:        if (len > tb_len)
                    160:                tb_end();
                    161:        else if (len > 0) {
                    162:                int d, s;
                    163:                int digits, curdigit;
                    164:
                    165:                if (!separate_thousands) {
                    166:                        strlcpy(tb_ptr, buf, tb_len);
                    167:                        return len;
                    168:                }
                    169:
                    170:                /* count until we hit a non digit. (e.g. the prefix) */
                    171:                for (digits = 0; digits < len; digits++)
1.16      deraadt   172:                        if (!isdigit((unsigned char)buf[digits]))
1.14      mpf       173:                                break;
                    174:
                    175:                curdigit = digits;
                    176:                d = s = 0;
                    177:                /* insert thousands separators while copying */
                    178:                while (curdigit && d < tb_len) {
                    179:                        if (curdigit < digits && curdigit % 3 == 0)
                    180:                                tb_ptr[d++] = ',';
                    181:                        tb_ptr[d++] = buf[s++];
                    182:                        curdigit--;
                    183:                }
                    184:                /* copy the remaining non-digits */
                    185:                while (len > digits && d < tb_len) {
                    186:                        tb_ptr[d++] = buf[s++];
                    187:                        digits++;
                    188:                }
                    189:                tb_ptr[d] = '\0';
                    190:                tb_ptr += d;
                    191:                tb_len -= d;
                    192:                len = d;
                    193:        }
1.1       canacar   194:        return len;
                    195: }
                    196:
                    197: void
                    198: move_horiz(int offset)
                    199: {
                    200:        if (rawmode) {
                    201:                if (offset <= 0)
                    202:                        linepos = 0;
                    203:                else if (offset >= MAX_LINE_BUF)
                    204:                        linepos = MAX_LINE_BUF - 1;
                    205:                else
                    206:                        linepos = offset;
                    207:        } else {
                    208:                move(curr_line, offset);
                    209:        }
                    210: }
                    211:
                    212: void
                    213: print_str(int len, const char *str)
                    214: {
                    215:        if (len <= 0)
                    216:                return;
                    217:
                    218:        if (rawmode) {
1.18      deraadt   219:                int length = MINIMUM(len, MAX_LINE_BUF - linepos);
1.1       canacar   220:                if (length <= 0)
                    221:                        return;
                    222:                bcopy(str, &linebuf[linepos], length);
                    223:                linepos += length;
                    224:        } else
                    225:                addnstr(str, len);
                    226: }
                    227:
                    228: void
                    229: clear_linebuf(void)
                    230: {
                    231:        memset(linebuf, ' ', MAX_LINE_BUF);
                    232: }
                    233:
                    234: void
                    235: end_line(void)
                    236: {
                    237:        if (rawmode) {
                    238:                linebuf[rawwidth] = '\0';
                    239:                printf("%s\n", linebuf);
                    240:                clear_linebuf();
                    241:        }
                    242:        curr_line++;
                    243: }
                    244:
                    245: void
                    246: end_page(void)
                    247: {
                    248:        if (rawmode) {
                    249:                linepos = 0;
                    250:                clear_linebuf();
1.24      solene    251:                fflush(stdout);
1.1       canacar   252:        } else {
                    253:                move(home_line, 0);
                    254:                print_cmdline();
                    255:                refresh();
                    256:        }
                    257:        curr_line = 0;
                    258: }
                    259:
                    260: /* field output functions */
                    261:
                    262: void
                    263: print_fld_str(field_def *fld, const char *str)
                    264: {
1.7       canacar   265:        int len, offset;
1.1       canacar   266:        char *cpos;
                    267:
                    268:        if (str == NULL || fld == NULL)
                    269:                return;
                    270:
                    271:        if (fld->start < 0)
                    272:                return;
                    273:
                    274:        len = strlen(str);
                    275:
                    276:        if (len >= fld->width) {
                    277:                move_horiz(fld->start);
                    278:                print_str(fld->width, str);
                    279:        } else {
                    280:                switch (fld->align) {
                    281:                case FLD_ALIGN_RIGHT:
                    282:                        move_horiz(fld->start + (fld->width - len));
                    283:                        break;
                    284:                case FLD_ALIGN_CENTER:
                    285:                        move_horiz(fld->start + (fld->width - len) / 2);
                    286:                        break;
                    287:                case FLD_ALIGN_COLUMN:
                    288:                        if ((cpos = strchr(str, ':')) == NULL) {
1.7       canacar   289:                                offset = (fld->width - len) / 2;
1.1       canacar   290:                        } else {
1.7       canacar   291:                                offset = (fld->width / 2) - (cpos - str);
                    292:                                if (offset < 0)
                    293:                                        offset = 0;
                    294:                                else if (offset > (fld->width - len))
                    295:                                        offset = fld->width - len;
1.1       canacar   296:                        }
1.7       canacar   297:                        move_horiz(fld->start + offset);
1.1       canacar   298:                        break;
                    299:                default:
                    300:                        move_horiz(fld->start);
                    301:                        break;
                    302:                }
                    303:                print_str(len, str);
                    304:        }
                    305: }
                    306:
                    307: void
                    308: print_bar_title(field_def *fld)
                    309: {
                    310:        char buf[16];
1.7       canacar   311:        int len, i, d, tr, tw, val, pos, cur;
1.1       canacar   312:
                    313:        int divs[] = {20, 10, 5, 4, 3, 2, 1, 0};
                    314:
                    315:        if (fld->width < 1)
                    316:                return;
                    317:
                    318:        len = snprintf(buf, sizeof(buf), " %d\\", fld->arg);
                    319:        if (len >= sizeof(buf))
                    320:                return;
                    321:
                    322:        for (i = 0; divs[i]; i++)
                    323:                if (divs[i] * len <= fld->width)
                    324:                        break;
                    325:
                    326:        if (divs[i] == 0) {
                    327:                print_fld_str(fld, "*****");
                    328:                return;
                    329:        }
                    330:
1.7       canacar   331:        d = divs[i];
1.1       canacar   332:
                    333:        val = 0;
                    334:        pos = 0;
1.7       canacar   335:        tr = fld->arg % d;
                    336:        tw = fld->width % d;
1.1       canacar   337:
                    338:        tb_start();
                    339:        cur = 0;
1.7       canacar   340:        for(i = 0; i < d; i++) {
1.1       canacar   341:                tw += fld->width;
                    342:                tr += fld->arg;
                    343:
1.7       canacar   344:                while (tr >= d) {
1.1       canacar   345:                        val++;
1.7       canacar   346:                        tr -= d;
1.1       canacar   347:                }
1.7       canacar   348:                while (tw >= d) {
1.1       canacar   349:                        pos++;
1.7       canacar   350:                        tw -= d;
1.1       canacar   351:                }
                    352:
                    353:                len = snprintf(buf, sizeof(buf), "%d\\", val);
1.21      deraadt   354:                if (len >= sizeof(buf))
                    355:                        len = strlen(buf);
1.1       canacar   356:                while (cur < pos - len) {
                    357:                        tbprintf(" ");
                    358:                        cur++;
                    359:                }
                    360:                tbprintf("%s", buf);
                    361:                cur += len;
                    362:        }
                    363:
                    364:        print_fld_tb(fld);
                    365: }
                    366:
                    367: void
                    368: print_fld_bar(field_def *fld, int value)
                    369: {
1.19      benno     370:        int i, tw, val;
1.1       canacar   371:
                    372:        if (fld->width < 1)
                    373:                return;
                    374:
                    375:        val = 0;
                    376:        tw = fld->arg / 2;
                    377:
                    378:        tb_start();
1.19      benno     379:
1.1       canacar   380:        for(i = 0; i < fld->width; i++) {
                    381:                tw += fld->arg;
                    382:
                    383:                while (tw >= fld->width) {
                    384:                        val++;
                    385:                        tw -= fld->width;
                    386:                }
                    387:                if (val > value)
                    388:                        break;
                    389:                tbprintf("#");
                    390:        }
                    391:
                    392:        print_fld_tb(fld);
                    393: }
                    394:
                    395: void
                    396: print_fld_tb(field_def *fld)
                    397: {
                    398:        print_fld_str(fld, tmp_buf);
                    399:        tb_end();
                    400: }
                    401:
                    402: void
                    403: print_title(void)
                    404: {
                    405:        field_def **fp;
                    406:
                    407:        if (curr_view != NULL && curr_view->view != NULL) {
                    408:                for (fp = curr_view->view; *fp != NULL; fp++) {
                    409:                        switch((*fp)->align) {
                    410:                        case FLD_ALIGN_LEFT:
                    411:                        case FLD_ALIGN_RIGHT:
                    412:                        case FLD_ALIGN_CENTER:
                    413:                        case FLD_ALIGN_COLUMN:
                    414:                                print_fld_str(*fp, (*fp)->title);
                    415:                                break;
                    416:                        case FLD_ALIGN_BAR:
                    417:                                print_bar_title(*fp);
                    418:                                break;
                    419:                        }
                    420:                }
                    421:        }
                    422:        end_line();
                    423: }
                    424:
                    425: /* view related functions */
                    426: void
                    427: hide_field(field_def *fld)
                    428: {
                    429:        if (fld == NULL)
                    430:                return;
                    431:
                    432:        fld->flags |= FLD_FLAG_HIDDEN;
                    433: }
                    434:
                    435: void
                    436: show_field(field_def *fld)
                    437: {
                    438:        if (fld == NULL)
                    439:                return;
                    440:
                    441:        fld->flags &= ~((unsigned int) FLD_FLAG_HIDDEN);
                    442: }
                    443:
                    444: void
                    445: reset_fields(void)
                    446: {
                    447:        field_def **fp;
                    448:        field_def *fld;
                    449:
                    450:        if (curr_view == NULL)
                    451:                return;
                    452:
                    453:        if (curr_view->view == NULL)
                    454:                return;
                    455:
                    456:        for (fp = curr_view->view; *fp != NULL; fp++) {
                    457:                fld = *fp;
                    458:                fld->start = -1;
                    459:                fld->width = fld->norm_width;
                    460:        }
                    461: }
                    462:
                    463: void
                    464: field_setup(void)
                    465: {
                    466:        field_def **fp;
                    467:        field_def *fld;
                    468:        int st, fwid, change;
                    469:        int width = columns;
                    470:
                    471:        reset_fields();
                    472:
                    473:        dispstart = 0;
                    474:        st = 0;
                    475:
                    476:        for (fp = curr_view->view; *fp != NULL; fp++) {
                    477:                fld = *fp;
                    478:                if (fld->flags & FLD_FLAG_HIDDEN)
                    479:                        continue;
                    480:
                    481:                if (width <= 1)
                    482:                        break;
                    483:
                    484:                if (st != 1)
                    485:                        width--;
                    486:
                    487:                fld->start = 1;
                    488:                fwid = fld->width;
                    489:                st++;
                    490:                if (fwid >= width) {
                    491:                        fld->width = width;
                    492:                        width = 0;
                    493:                } else
                    494:                        width -= fwid;
                    495:        }
                    496:
                    497:        while (width > 0) {
                    498:                change = 0;
                    499:                for (fp = curr_view->view; *fp != NULL; fp++) {
                    500:                        fld = *fp;
                    501:                        if (fld->flags & FLD_FLAG_HIDDEN)
                    502:                                continue;
                    503:                        if ((fld->width < fld->max_width) &&
                    504:                            (fld->increment <= width)) {
                    505:                                int w = fld->width + fld->increment;
                    506:                                if (w > fld->max_width)
                    507:                                        w = fld->max_width;
                    508:                                width += fld->width - w;
                    509:                                fld->width = w;
                    510:                                change = 1;
                    511:                        }
                    512:                        if (width <= 0) break;
                    513:                }
                    514:                if (change == 0) break;
                    515:        }
                    516:
                    517:        st = 0;
                    518:        for (fp = curr_view->view; *fp != NULL; fp++) {
                    519:                fld = *fp;
                    520:                if (fld->flags & FLD_FLAG_HIDDEN)
                    521:                        continue;
                    522:                if (fld->start < 0) break;
                    523:                fld->start = st;
                    524:                st += fld->width + 1;
                    525:        }
                    526: }
                    527:
                    528: void
                    529: set_curr_view(struct view_ent *ve)
                    530: {
                    531:        field_view *v;
                    532:
                    533:        reset_fields();
                    534:
                    535:        if (ve == NULL) {
                    536:                curr_view_ent = NULL;
                    537:                curr_view = NULL;
                    538:                curr_mgr = NULL;
                    539:                return;
                    540:        }
                    541:
                    542:        v = ve->view;
1.26      jasper    543:
1.1       canacar   544:        if ((curr_view != NULL) && (curr_mgr != v->mgr)) {
                    545:                gotsig_alarm = 1;
                    546:                if (v->mgr != NULL && v->mgr->select_fn != NULL)
                    547:                        v->mgr->select_fn();
                    548:        }
                    549:
                    550:        curr_view_ent = ve;
                    551:        curr_view = v;
                    552:        curr_mgr = v->mgr;
                    553:        field_setup();
                    554:        need_update = 1;
                    555: }
                    556:
                    557: void
                    558: add_view(field_view *fv)
                    559: {
                    560:        struct view_ent *ent;
                    561:
                    562:        if (fv == NULL)
                    563:                return;
                    564:
                    565:        if (fv->view == NULL || fv->name == NULL || fv->mgr == NULL)
                    566:                return;
                    567:
                    568:        ent = malloc(sizeof(struct view_ent));
                    569:        if (ent == NULL)
                    570:                return;
                    571:
                    572:        ent->view = fv;
1.17      krw       573:        TAILQ_INSERT_TAIL(&view_head, ent, entries);
1.1       canacar   574:
                    575:        if (curr_view == NULL)
                    576:                set_curr_view(ent);
                    577: }
                    578:
                    579: int
1.5       canacar   580: set_view(const char *opt)
1.1       canacar   581: {
                    582:        struct view_ent *ve, *vm = NULL;
                    583:        field_view *v;
                    584:        int len;
                    585:
                    586:        if (opt == NULL || (len = strlen(opt)) == 0)
                    587:                return 1;
                    588:
1.17      krw       589:        TAILQ_FOREACH(ve, &view_head, entries) {
1.1       canacar   590:                v = ve->view;
                    591:                if (strncasecmp(opt, v->name, len) == 0) {
                    592:                        if (vm)
                    593:                                return 1;
                    594:                        vm = ve;
                    595:                }
                    596:        }
                    597:
                    598:        if (vm) {
                    599:                set_curr_view(vm);
                    600:                return 0;
                    601:        }
                    602:
                    603:        return 1;
                    604: }
                    605:
                    606: void
                    607: foreach_view(void (*callback)(field_view *))
                    608: {
                    609:        struct view_ent *ve;
                    610:
1.17      krw       611:        TAILQ_FOREACH(ve, &view_head, entries) {
1.1       canacar   612:                callback(ve->view);
                    613:        }
                    614: }
                    615:
                    616: int
                    617: set_view_hotkey(int ch)
                    618: {
                    619:        struct view_ent *ve;
                    620:        field_view *v;
                    621:        int key = tolower(ch);
                    622:
1.17      krw       623:        TAILQ_FOREACH(ve, &view_head, entries) {
1.1       canacar   624:                v = ve->view;
                    625:                if (key == v->hotkey) {
                    626:                        set_curr_view(ve);
                    627:                        return 1;
                    628:                }
                    629:        }
                    630:
                    631:        return 0;
                    632: }
                    633:
                    634: void
                    635: next_view(void)
                    636: {
                    637:        struct view_ent *ve;
                    638:
1.17      krw       639:        if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
1.1       canacar   640:                return;
                    641:
1.17      krw       642:        ve = TAILQ_NEXT(curr_view_ent, entries);
                    643:        if (ve == NULL)
                    644:                ve = TAILQ_FIRST(&view_head);
1.1       canacar   645:
                    646:        set_curr_view(ve);
                    647: }
                    648:
                    649: void
                    650: prev_view(void)
                    651: {
                    652:        struct view_ent *ve;
                    653:
1.17      krw       654:        if (TAILQ_EMPTY(&view_head) || curr_view_ent == NULL)
1.1       canacar   655:                return;
                    656:
1.17      krw       657:        ve = TAILQ_PREV(curr_view_ent, view_list, entries);
                    658:        if (ve == NULL)
                    659:                ve = TAILQ_LAST(&view_head, view_list);
1.1       canacar   660:
                    661:        set_curr_view(ve);
                    662: }
                    663:
                    664: /* generic field printing */
                    665:
                    666: void
                    667: print_fld_age(field_def *fld, unsigned int age)
                    668: {
                    669:        int len;
                    670:        unsigned int h, m, s;
                    671:
                    672:        if (fld == NULL)
                    673:                return;
                    674:        len = fld->width;
                    675:
                    676:        if (len < 1)
                    677:                return;
                    678:
                    679:        s = age % 60;
                    680:        m = age / 60;
                    681:        h = m / 60;
                    682:        m %= 60;
                    683:
                    684:        tb_start();
                    685:        if (tbprintf("%02u:%02u:%02u", h, m, s) <= len)
                    686:                goto ok;
1.26      jasper    687:
1.3       canacar   688:        tb_start();
1.1       canacar   689:        if (tbprintf("%u", age) <= len)
                    690:                goto ok;
                    691:
1.3       canacar   692:        tb_start();
1.1       canacar   693:        age /= 60;
                    694:        if (tbprintf("%um", age) <= len)
                    695:                goto ok;
                    696:        if (age == 0)
                    697:                goto err;
1.26      jasper    698:
1.3       canacar   699:        tb_start();
1.1       canacar   700:        age /= 60;
                    701:        if (tbprintf("%uh", age) <= len)
                    702:                goto ok;
                    703:        if (age == 0)
                    704:                goto err;
1.26      jasper    705:
1.3       canacar   706:        tb_start();
1.1       canacar   707:        age /= 24;
                    708:        if (tbprintf("%ud", age) <= len)
                    709:                goto ok;
1.26      jasper    710:
1.9       jasper    711: err:
1.1       canacar   712:        print_fld_str(fld, "*");
                    713:        tb_end();
                    714:        return;
1.26      jasper    715:
1.9       jasper    716: ok:
1.1       canacar   717:        print_fld_tb(fld);
                    718: }
                    719:
                    720: void
1.7       canacar   721: print_fld_sdiv(field_def *fld, u_int64_t size, int d)
1.1       canacar   722: {
                    723:        int len;
1.25      martijn   724:        char *mult = "KMGTPE";
                    725:        int i = -1;
1.1       canacar   726:
                    727:        if (fld == NULL)
                    728:                return;
                    729:
                    730:        len = fld->width;
                    731:        if (len < 1)
                    732:                return;
                    733:
1.25      martijn   734:        if (humanreadable) {
                    735:                while (size >= 10000 && sizeof(mult) >= i + 1) {
                    736:                        i++;
                    737:                        size /= d;
                    738:                }
                    739:                tb_start();
                    740:                if (tbprintft("%llu%.1s", size, i == -1 ? "" : mult + i) <= len)
                    741:                        goto ok;
1.1       canacar   742:                goto err;
1.25      martijn   743:        }
                    744:        do {
                    745:                tb_start();
                    746:                if (tbprintft("%llu%.1s", size, i == -1 ? "" : mult + i) <= len)
                    747:                        goto ok;
                    748:                i++;
                    749:                size /= d;
                    750:        } while (size != 0 && sizeof(mult) >= i);
                    751: err:
1.3       canacar   752:        tb_start();
1.1       canacar   753:        print_fld_str(fld, "*");
                    754:        tb_end();
                    755:        return;
                    756:
                    757: ok:
                    758:        print_fld_tb(fld);
                    759: }
                    760:
                    761: void
                    762: print_fld_size(field_def *fld, u_int64_t size)
                    763: {
                    764:        print_fld_sdiv(fld, size, 1024);
1.4       canacar   765: }
                    766:
                    767: void
1.7       canacar   768: print_fld_ssdiv(field_def *fld, int64_t size, int d)
1.4       canacar   769: {
                    770:        int len;
                    771:
                    772:        if (fld == NULL)
                    773:                return;
                    774:
                    775:        len = fld->width;
                    776:        if (len < 1)
                    777:                return;
                    778:
                    779:        tb_start();
1.14      mpf       780:        if (tbprintft("%lld", size) <= len)
1.4       canacar   781:                goto ok;
                    782:
                    783:        tb_start();
1.7       canacar   784:        size /= d;
1.14      mpf       785:        if (tbprintft("%lldK", size) <= len)
1.4       canacar   786:                goto ok;
                    787:        if (size == 0)
                    788:                goto err;
                    789:
                    790:        tb_start();
1.7       canacar   791:        size /= d;
1.14      mpf       792:        if (tbprintft("%lldM", size) <= len)
1.4       canacar   793:                goto ok;
                    794:        if (size == 0)
                    795:                goto err;
                    796:
                    797:        tb_start();
1.7       canacar   798:        size /= d;
1.14      mpf       799:        if (tbprintft("%lldG", size) <= len)
1.4       canacar   800:                goto ok;
                    801:        if (size == 0)
                    802:                goto err;
                    803:
                    804:        tb_start();
1.7       canacar   805:        size /= d;
1.14      mpf       806:        if (tbprintft("%lldT", size) <= len)
1.4       canacar   807:                goto ok;
                    808:
                    809: err:
                    810:        print_fld_str(fld, "*");
                    811:        tb_end();
                    812:        return;
                    813:
                    814: ok:
                    815:        print_fld_tb(fld);
                    816: }
                    817:
                    818: void
                    819: print_fld_ssize(field_def *fld, int64_t size)
                    820: {
                    821:        print_fld_ssdiv(fld, size, 1024);
1.1       canacar   822: }
                    823:
                    824: void
                    825: print_fld_rate(field_def *fld, double rate)
                    826: {
                    827:        if (rate < 0) {
                    828:                print_fld_str(fld, "*");
                    829:        } else {
                    830:                print_fld_size(fld, rate);
                    831:        }
                    832: }
                    833:
                    834: void
                    835: print_fld_bw(field_def *fld, double bw)
                    836: {
                    837:        if (bw < 0) {
                    838:                print_fld_str(fld, "*");
                    839:        } else {
                    840:                print_fld_sdiv(fld, bw, 1000);
                    841:        }
                    842: }
                    843:
                    844: void
                    845: print_fld_uint(field_def *fld, unsigned int size)
                    846: {
                    847:        int len;
                    848:
                    849:        if (fld == NULL)
                    850:                return;
                    851:
                    852:        len = fld->width;
                    853:        if (len < 1)
                    854:                return;
                    855:
                    856:        tb_start();
1.14      mpf       857:        if (tbprintft("%u", size) > len)
1.6       naddy     858:                print_fld_str(fld, "*");
                    859:        else
                    860:                print_fld_tb(fld);
                    861:        tb_end();
                    862: }
                    863:
                    864: void
                    865: print_fld_float(field_def *fld, double f, int prec)
                    866: {
                    867:        int len;
                    868:
                    869:        if (fld == NULL)
                    870:                return;
                    871:
                    872:        len = fld->width;
                    873:        if (len < 1)
                    874:                return;
                    875:
                    876:        tb_start();
                    877:        if (tbprintf("%*.*f", len, prec, f) > len)
1.1       canacar   878:                print_fld_str(fld, "*");
                    879:        else
                    880:                print_fld_tb(fld);
                    881:        tb_end();
                    882: }
                    883:
                    884:
                    885: /* ordering */
1.22      martijn   886:
                    887: int
                    888: foreach_order(void (*callback)(order_type *))
                    889: {
                    890:        order_type *o;
                    891:
                    892:        if (curr_view == NULL || curr_view->mgr == NULL ||
                    893:            curr_view->mgr->order_list == NULL)
                    894:                return -1;
                    895:        o = curr_view->mgr->order_list;
                    896:        do {
                    897:                callback(o++);
                    898:        } while (o->name != NULL);
                    899:        return 0;
                    900: }
1.1       canacar   901:
                    902: void
1.5       canacar   903: set_order(const char *opt)
1.1       canacar   904: {
                    905:        order_type *o;
                    906:
                    907:        if (curr_view == NULL || curr_view->mgr == NULL)
                    908:                return;
                    909:
                    910:        curr_view->mgr->order_curr = curr_view->mgr->order_list;
                    911:
                    912:        if (opt == NULL)
                    913:                return;
                    914:
                    915:        o = curr_view->mgr->order_list;
                    916:
                    917:        if (o == NULL)
                    918:                return;
                    919:
                    920:        for (;o->name != NULL; o++) {
                    921:                if (strcasecmp(opt, o->match) == 0) {
                    922:                        curr_view->mgr->order_curr = o;
                    923:                        return;
                    924:                }
                    925:        }
                    926: }
                    927:
                    928: int
                    929: set_order_hotkey(int ch)
                    930: {
                    931:        order_type *o;
                    932:        int key = ch;
                    933:
                    934:        if (curr_view == NULL || curr_view->mgr == NULL)
                    935:                return 0;
                    936:
                    937:        o = curr_view->mgr->order_list;
                    938:
                    939:        if (o == NULL)
                    940:                return 0;
                    941:
                    942:        for (;o->name != NULL; o++) {
                    943:                if (key == o->hotkey) {
                    944:                        if (curr_view->mgr->order_curr == o) {
                    945:                                sortdir *= -1;
                    946:                        } else {
                    947:                                curr_view->mgr->order_curr = o;
                    948:                        }
                    949:                        return 1;
                    950:                }
                    951:        }
                    952:
                    953:        return 0;
                    954: }
                    955:
                    956: void
                    957: next_order(void)
                    958: {
                    959:        order_type *o, *oc;
1.2       canacar   960:
                    961:        if (curr_view->mgr->order_list == NULL)
                    962:                return;
1.1       canacar   963:
                    964:        oc = curr_view->mgr->order_curr;
                    965:
                    966:        for (o = curr_view->mgr->order_list; o->name != NULL; o++) {
                    967:                if (oc == o) {
                    968:                        o++;
                    969:                        if (o->name == NULL)
                    970:                                break;
                    971:                        curr_view->mgr->order_curr = o;
                    972:                        return;
                    973:                }
                    974:        }
                    975:
                    976:        curr_view->mgr->order_curr = curr_view->mgr->order_list;
                    977: }
                    978:
                    979:
                    980: /* main program functions */
                    981:
                    982: int
                    983: read_view(void)
                    984: {
                    985:        if (curr_mgr == NULL)
                    986:                return (0);
                    987:
                    988:        if (paused)
                    989:                return (0);
                    990:
                    991:        if (curr_mgr->read_fn != NULL)
                    992:                return (curr_mgr->read_fn());
                    993:
                    994:        return (0);
                    995: }
                    996:
                    997:
                    998: int
                    999: disp_update(void)
                   1000: {
1.7       canacar  1001:        int li;
1.1       canacar  1002:
                   1003:        if (maxprint < 0)
                   1004:                dispstart = 0;
                   1005:        else if (dispstart + maxprint > num_disp)
                   1006:                dispstart = num_disp - maxprint;
1.26      jasper   1007:
1.1       canacar  1008:        if (dispstart < 0)
                   1009:                dispstart = 0;
                   1010:
                   1011:        if (curr_view == NULL)
                   1012:                return 0;
                   1013:
                   1014:        if (curr_mgr != NULL) {
                   1015:                curr_line = 0;
                   1016:
                   1017:                if (curr_mgr->header_fn != NULL) {
1.7       canacar  1018:                        li = curr_mgr->header_fn();
                   1019:                        if (li < 0)
1.1       canacar  1020:                                return (1);
1.7       canacar  1021:                        curr_line = ++li;
                   1022:                        home_line = li + maxprint + 1;
1.1       canacar  1023:                }
                   1024:
                   1025:                print_title();
                   1026:
                   1027:                if (curr_mgr->print_fn != NULL)
                   1028:                        curr_mgr->print_fn();
                   1029:        }
                   1030:
                   1031:        return (0);
                   1032: }
                   1033:
                   1034: void
                   1035: sort_view(void)
                   1036: {
                   1037:        if (curr_mgr != NULL)
                   1038:                if (curr_mgr->sort_fn != NULL)
                   1039:                        curr_mgr->sort_fn();
                   1040: }
                   1041:
                   1042: void
1.7       canacar  1043: sig_close(int sig)
1.1       canacar  1044: {
                   1045:        gotsig_close = 1;
                   1046: }
                   1047:
                   1048: void
1.7       canacar  1049: sig_resize(int sig)
1.1       canacar  1050: {
                   1051:        gotsig_resize = 1;
                   1052: }
                   1053:
                   1054: void
1.7       canacar  1055: sig_alarm(int sig)
1.1       canacar  1056: {
                   1057:        gotsig_alarm = 1;
                   1058: }
                   1059:
                   1060: void
                   1061: setup_term(int dmax)
                   1062: {
                   1063:        max_disp = dmax;
                   1064:        maxprint = dmax;
                   1065:
                   1066:        if (rawmode) {
                   1067:                columns = rawwidth;
                   1068:                lines = DEFAULT_HEIGHT;
                   1069:                clear_linebuf();
                   1070:        } else {
                   1071:                if (dmax < 0)
                   1072:                        dmax = 0;
                   1073:
                   1074:                screen = newterm(NULL, stdout, stdin);
                   1075:                if (screen == NULL) {
                   1076:                        rawmode = 1;
                   1077:                        interactive = 0;
                   1078:                        setup_term(dmax);
                   1079:                        return;
                   1080:                }
                   1081:                columns = COLS;
                   1082:                lines = LINES;
                   1083:
                   1084:                if (maxprint > lines - HEADER_LINES)
                   1085:                        maxprint = lines - HEADER_LINES;
                   1086:
                   1087:                nonl();
                   1088:                keypad(stdscr, TRUE);
                   1089:                intrflush(stdscr, FALSE);
                   1090:
                   1091:                halfdelay(10);
                   1092:                noecho();
                   1093:        }
                   1094:
                   1095:        if (dmax == 0)
                   1096:                maxprint = lines - HEADER_LINES;
                   1097:
                   1098:        field_setup();
                   1099: }
                   1100:
1.8       canacar  1101: void
1.11      nicm     1102: do_resize_term(void)
1.8       canacar  1103: {
                   1104:        struct winsize ws;
                   1105:
                   1106:        if (rawmode)
                   1107:                return;
                   1108:
                   1109:        if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1)
                   1110:                return;
                   1111:
                   1112:        resizeterm(ws.ws_row, ws.ws_col);
                   1113:
                   1114:        columns = COLS;
                   1115:        lines = LINES;
                   1116:
                   1117:        maxprint = max_disp;
                   1118:
                   1119:        if (maxprint == 0 || maxprint > lines - HEADER_LINES)
                   1120:                maxprint = lines - HEADER_LINES;
                   1121:
                   1122:        clear();
                   1123:
                   1124:        field_setup();
                   1125: }
                   1126:
1.1       canacar  1127: struct command *
                   1128: command_set(struct command *cmd, const char *init)
                   1129: {
                   1130:        struct command *prev = curr_cmd;
                   1131:
                   1132:        if (cmd) {
                   1133:                if (init) {
                   1134:                        cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf));
                   1135:                        if (cmd_len >= sizeof(cmdbuf)) {
                   1136:                                cmdbuf[0] = '\0';
                   1137:                                cmd_len = 0;
                   1138:                        }
                   1139:                } else {
                   1140:                        cmd_len = 0;
                   1141:                        cmdbuf[0] = 0;
                   1142:                }
                   1143:        }
1.27      tb       1144:        message_set(NULL);
1.1       canacar  1145:        curr_cmd = cmd;
                   1146:        need_update = 1;
                   1147:        return prev;
                   1148: }
                   1149:
1.28    ! martijn  1150: void
        !          1151: message_toggle(enum message_mode mode)
        !          1152: {
        !          1153:        message_mode = message_mode != mode ? mode : MESSAGE_NONE;
        !          1154:        need_update = 1;
        !          1155:        message_cont = 1;
        !          1156: }
        !          1157:
1.1       canacar  1158: const char *
1.28    ! martijn  1159: message_set(const char *msg)
        !          1160: {
        !          1161:        free(curr_message);
        !          1162:
        !          1163:        if (msg) {
1.1       canacar  1164:                curr_message = strdup(msg);
1.28    ! martijn  1165:                message_cont = 0;
        !          1166:        } else {
1.1       canacar  1167:                curr_message = NULL;
1.28    ! martijn  1168:                message_cont = 1;
        !          1169:        }
1.1       canacar  1170:        return NULL;
                   1171: }
                   1172:
                   1173: void
                   1174: print_cmdline(void)
                   1175: {
                   1176:        if (curr_cmd) {
                   1177:                attron(A_STANDOUT);
                   1178:                mvprintw(home_line, 0, "%s: ", curr_cmd->prompt);
                   1179:                attroff(A_STANDOUT);
                   1180:                printw("%s", cmdbuf);
                   1181:        } else if (curr_message) {
                   1182:                mvprintw(home_line, 0, "> %s", curr_message);
                   1183:        }
                   1184:        clrtoeol();
                   1185: }
                   1186:
                   1187:
                   1188: void
                   1189: cmd_keyboard(int ch)
                   1190: {
                   1191:        if (curr_cmd == NULL)
                   1192:                return;
                   1193:
                   1194:        if (ch > 0 && isprint(ch)) {
                   1195:                if (cmd_len < sizeof(cmdbuf) - 1) {
                   1196:                        cmdbuf[cmd_len++] = ch;
                   1197:                        cmdbuf[cmd_len] = 0;
                   1198:                } else
                   1199:                        beep();
                   1200:        }
1.26      jasper   1201:
1.1       canacar  1202:        switch (ch) {
                   1203:        case KEY_ENTER:
                   1204:        case 0x0a:
                   1205:        case 0x0d:
                   1206:        {
                   1207:                struct command * c = command_set(NULL, NULL);
1.5       canacar  1208:                c->exec(cmdbuf);
1.1       canacar  1209:                break;
                   1210:        }
                   1211:        case KEY_BACKSPACE:
                   1212:        case KEY_DC:
                   1213:        case CTRL_H:
                   1214:                if (cmd_len > 0) {
                   1215:                        cmdbuf[--cmd_len] = 0;
                   1216:                } else
                   1217:                        beep();
                   1218:                break;
                   1219:        case 0x1b:
                   1220:        case CTRL_G:
                   1221:                if (cmd_len > 0) {
                   1222:                        cmdbuf[0] = '\0';
                   1223:                        cmd_len = 0;
                   1224:                } else
                   1225:                        command_set(NULL, NULL);
                   1226:                break;
                   1227:        default:
                   1228:                break;
                   1229:        }
                   1230: }
                   1231:
                   1232: void
                   1233: keyboard(void)
                   1234: {
                   1235:        int ch;
                   1236:
                   1237:        ch = getch();
                   1238:
                   1239:        if (curr_cmd) {
                   1240:                cmd_keyboard(ch);
                   1241:                print_cmdline();
                   1242:                return;
                   1243:        }
                   1244:
                   1245:        if (curr_mgr != NULL)
                   1246:                if (curr_mgr->key_fn != NULL)
                   1247:                        if (curr_mgr->key_fn(ch))
                   1248:                                return;
                   1249:
                   1250:        if (curr_message != NULL) {
                   1251:                if (ch > 0) {
1.27      tb       1252:                        message_set(NULL);
1.1       canacar  1253:                        need_update = 1;
                   1254:                }
                   1255:        }
                   1256:
                   1257:        switch (ch) {
                   1258:        case ' ':
                   1259:                gotsig_alarm = 1;
                   1260:                break;
                   1261:        case 'o':
                   1262:                next_order();
                   1263:                need_sort = 1;
                   1264:                break;
                   1265:        case 'p':
                   1266:                paused = !paused;
                   1267:                gotsig_alarm = 1;
                   1268:                break;
                   1269:        case 'q':
                   1270:                gotsig_close = 1;
                   1271:                break;
                   1272:        case 'r':
                   1273:                sortdir *= -1;
                   1274:                need_sort = 1;
                   1275:                break;
                   1276:        case 'v':
                   1277:                /* FALLTHROUGH */
                   1278:        case KEY_RIGHT:
                   1279:                /* FALLTHROUGH */
                   1280:        case CTRL_F:
                   1281:                next_view();
                   1282:                break;
                   1283:        case KEY_LEFT:
                   1284:                /* FALLTHROUGH */
                   1285:        case CTRL_B:
                   1286:                prev_view();
                   1287:                break;
                   1288:        case KEY_DOWN:
                   1289:                /* FALLTHROUGH */
                   1290:        case CTRL_N:
                   1291:                dispstart++;
                   1292:                need_update = 1;
                   1293:                break;
                   1294:        case KEY_UP:
                   1295:                /* FALLTHROUGH */
                   1296:        case CTRL_P:
                   1297:                dispstart--;
                   1298:                need_update = 1;
                   1299:                break;
                   1300:        case KEY_NPAGE:
                   1301:                /* FALLTHROUGH */
                   1302:        case CTRL_V:
                   1303:                dispstart += maxprint;
                   1304:                need_update = 1;
                   1305:                break;
                   1306:        case KEY_PPAGE:
                   1307:                /* FALLTHROUGH */
                   1308:        case META_V:
                   1309:                dispstart -= maxprint;
                   1310:                need_update = 1;
                   1311:                break;
                   1312:        case KEY_HOME:
                   1313:                /* FALLTHROUGH */
                   1314:        case CTRL_A:
                   1315:                dispstart = 0;
                   1316:                need_update = 1;
                   1317:                break;
                   1318:        case KEY_END:
                   1319:                /* FALLTHROUGH */
                   1320:        case CTRL_E:
                   1321:                dispstart = num_disp;
                   1322:                need_update = 1;
                   1323:                break;
                   1324:        case CTRL_L:
                   1325:                clear();
                   1326:                need_update = 1;
                   1327:                break;
                   1328:        default:
                   1329:                break;
                   1330:        }
                   1331:
                   1332:        if (set_order_hotkey(ch))
                   1333:                need_sort = 1;
                   1334:        else
                   1335:                set_view_hotkey(ch);
                   1336: }
                   1337:
                   1338: void
                   1339: engine_initialize(void)
                   1340: {
                   1341:        signal(SIGTERM, sig_close);
                   1342:        signal(SIGINT, sig_close);
                   1343:        signal(SIGQUIT, sig_close);
                   1344:        signal(SIGWINCH, sig_resize);
                   1345:        signal(SIGALRM, sig_alarm);
                   1346: }
                   1347:
                   1348: void
                   1349: engine_loop(int countmax)
                   1350: {
                   1351:        int count = 0;
                   1352:
                   1353:        for (;;) {
                   1354:                if (gotsig_alarm) {
                   1355:                        read_view();
                   1356:                        need_sort = 1;
                   1357:                        gotsig_alarm = 0;
                   1358:                        ualarm(udelay, 0);
                   1359:                }
                   1360:
                   1361:                if (need_sort) {
                   1362:                        sort_view();
                   1363:                        need_sort = 0;
                   1364:                        need_update = 1;
1.26      jasper   1365:
1.1       canacar  1366:                        /* XXX if sort took too long */
                   1367:                        if (gotsig_alarm) {
                   1368:                                gotsig_alarm = 0;
                   1369:                                ualarm(udelay, 0);
                   1370:                        }
                   1371:                }
                   1372:
                   1373:                if (need_update) {
                   1374:                        erase();
1.15      reyk     1375:                        if (!averageonly ||
                   1376:                            (averageonly && count == countmax - 1))
                   1377:                                disp_update();
1.28    ! martijn  1378:                        if (message_cont) {
        !          1379:                                switch (message_mode) {
        !          1380:                                case MESSAGE_NONE:
        !          1381:                                        message_set(NULL);
        !          1382:                                        break;
        !          1383:                                case MESSAGE_HELP:
        !          1384:                                        show_help();
        !          1385:                                        break;
        !          1386:                                case MESSAGE_VIEW:
        !          1387:                                        show_view();
        !          1388:                                        break;
        !          1389:                                case MESSAGE_ORDER:
        !          1390:                                        show_order();
        !          1391:                                        break;
        !          1392:                                }
        !          1393:                        }
1.1       canacar  1394:                        end_page();
                   1395:                        need_update = 0;
                   1396:                        if (countmax && ++count >= countmax)
                   1397:                                break;
                   1398:                }
                   1399:
                   1400:                if (gotsig_close)
                   1401:                        break;
                   1402:                if (gotsig_resize) {
1.11      nicm     1403:                        do_resize_term();
1.1       canacar  1404:                        gotsig_resize = 0;
                   1405:                        need_update = 1;
                   1406:                }
                   1407:
                   1408:                if (interactive && need_update == 0)
                   1409:                        keyboard();
                   1410:                else if (interactive == 0)
                   1411:                        usleep(udelay);
                   1412:        }
                   1413:
                   1414:        if (rawmode == 0)
                   1415:                endwin();
1.12      lum      1416: }
                   1417:
                   1418: int
                   1419: check_termcap(void)
                   1420: {
                   1421:        char *term_name;
                   1422:        int status;
                   1423:        static struct termios screen_settings;
                   1424:
                   1425:        if (!interactive)
                   1426:                /* pretend we have a dumb terminal */
                   1427:                return(1);
                   1428:
                   1429:        /* get the terminal name */
                   1430:        term_name = getenv("TERM");
                   1431:        if (term_name == NULL)
                   1432:                return(1);
                   1433:
                   1434:        /* now get the termcap entry */
                   1435:        if ((status = tgetent(NULL, term_name)) != 1) {
                   1436:                if (status == -1)
                   1437:                        warnx("can't open termcap file");
                   1438:                else
1.26      jasper   1439:                        warnx("no termcap entry for a `%s' terminal",
1.12      lum      1440:                            term_name);
                   1441:
                   1442:                /* pretend it's dumb and proceed */
                   1443:                return(1);
                   1444:        }
                   1445:
                   1446:        /* "hardcopy" immediately indicates a very stupid terminal */
                   1447:        if (tgetflag("hc"))
                   1448:                return(1);
                   1449:
                   1450:         /* get necessary capabilities */
                   1451:         if (tgetstr("cl", NULL) == NULL || tgetstr("cm", NULL) == NULL)
                   1452:                return(1);
                   1453:
                   1454:        /* if stdout is not a terminal, pretend we are a dumb terminal */
                   1455:        if (tcgetattr(STDOUT_FILENO, &screen_settings) == -1)
                   1456:                return(1);
                   1457:
                   1458:        return(0);
1.1       canacar  1459: }