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