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