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