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

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