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