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