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