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