Annotation of src/usr.bin/systat/engine.c, Revision 1.5
1.5 ! canacar 1: /* $Id: engine.c,v 1.4 2008/07/22 03:00:23 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>
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: {
206: int len, move;
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) {
230: move = (fld->width - len) / 2;
231: } else {
232: move = (fld->width / 2) - (cpos - str);
233: if (move < 0)
234: move = 0;
235: else if (move > (fld->width - len))
236: move = fld->width - len;
237: }
238: move_horiz(fld->start + move);
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];
252: int len, div, i, tr, tw, val, pos, cur;
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:
272: div = divs[i];
273:
274: val = 0;
275: pos = 0;
276: tr = fld->arg % div;
277: tw = fld->width % div;
278:
279: tb_start();
280: cur = 0;
281: for(i = 0; i < div; i++) {
282: tw += fld->width;
283: tr += fld->arg;
284:
285: while (tr >= div) {
286: val++;
287: tr -= div;
288: }
289: while (tw >= div) {
290: pos++;
291: tw -= div;
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
661: print_fld_sdiv(field_def *fld, u_int64_t size, int div)
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.1 canacar 677: size /= div;
678: if (tbprintf("%lluK", size) <= len)
679: goto ok;
680: if (size == 0)
681: goto err;
682:
1.3 canacar 683: tb_start();
1.1 canacar 684: size /= div;
685: if (tbprintf("%lluM", size) <= len)
686: goto ok;
687: if (size == 0)
688: goto err;
689:
1.3 canacar 690: tb_start();
1.1 canacar 691: size /= div;
692: if (tbprintf("%lluG", size) <= len)
693: goto ok;
1.4 canacar 694: if (size == 0)
695: goto err;
696:
697: tb_start();
698: size /= div;
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
718: print_fld_ssdiv(field_def *fld, int64_t size, int div)
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();
734: size /= div;
735: if (tbprintf("%lldK", size) <= len)
736: goto ok;
737: if (size == 0)
738: goto err;
739:
740: tb_start();
741: size /= div;
742: if (tbprintf("%lldM", size) <= len)
743: goto ok;
744: if (size == 0)
745: goto err;
746:
747: tb_start();
748: size /= div;
749: if (tbprintf("%lldG", size) <= len)
750: goto ok;
751: if (size == 0)
752: goto err;
753:
754: tb_start();
755: size /= div;
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)
808: print_fld_str(fld, "*");
809: else
810: print_fld_tb(fld);
811: tb_end();
812: }
813:
814:
815: /* ordering */
816:
817: void
1.5 ! canacar 818: set_order(const char *opt)
1.1 canacar 819: {
820: order_type *o;
821:
822: if (curr_view == NULL || curr_view->mgr == NULL)
823: return;
824:
825: curr_view->mgr->order_curr = curr_view->mgr->order_list;
826:
827: if (opt == NULL)
828: return;
829:
830: o = curr_view->mgr->order_list;
831:
832: if (o == NULL)
833: return;
834:
835: for (;o->name != NULL; o++) {
836: if (strcasecmp(opt, o->match) == 0) {
837: curr_view->mgr->order_curr = o;
838: return;
839: }
840: }
841: }
842:
843: int
844: set_order_hotkey(int ch)
845: {
846: order_type *o;
847: int key = ch;
848:
849: if (curr_view == NULL || curr_view->mgr == NULL)
850: return 0;
851:
852: o = curr_view->mgr->order_list;
853:
854: if (o == NULL)
855: return 0;
856:
857: for (;o->name != NULL; o++) {
858: if (key == o->hotkey) {
859: if (curr_view->mgr->order_curr == o) {
860: sortdir *= -1;
861: } else {
862: curr_view->mgr->order_curr = o;
863: }
864: return 1;
865: }
866: }
867:
868: return 0;
869: }
870:
871: void
872: next_order(void)
873: {
874: order_type *o, *oc;
1.2 canacar 875:
876: if (curr_view->mgr->order_list == NULL)
877: return;
1.1 canacar 878:
879: oc = curr_view->mgr->order_curr;
880:
881: for (o = curr_view->mgr->order_list; o->name != NULL; o++) {
882: if (oc == o) {
883: o++;
884: if (o->name == NULL)
885: break;
886: curr_view->mgr->order_curr = o;
887: return;
888: }
889: }
890:
891: curr_view->mgr->order_curr = curr_view->mgr->order_list;
892: }
893:
894:
895: /* main program functions */
896:
897: int
898: read_view(void)
899: {
900: if (curr_mgr == NULL)
901: return (0);
902:
903: if (paused)
904: return (0);
905:
906: if (curr_mgr->read_fn != NULL)
907: return (curr_mgr->read_fn());
908:
909: return (0);
910: }
911:
912:
913: int
914: disp_update(void)
915: {
916: int lines;
917:
918: if (maxprint < 0)
919: dispstart = 0;
920: else if (dispstart + maxprint > num_disp)
921: dispstart = num_disp - maxprint;
922:
923: if (dispstart < 0)
924: dispstart = 0;
925:
926: if (curr_view == NULL)
927: return 0;
928:
929: if (curr_mgr != NULL) {
930: curr_line = 0;
931:
932: if (curr_mgr->header_fn != NULL) {
933: lines = curr_mgr->header_fn();
934: if (lines < 0)
935: return (1);
936: // home_line = lines++;
937: curr_line = ++lines;
938: home_line = lines + maxprint + 1;
939: }
940:
941: print_title();
942:
943: if (curr_mgr->print_fn != NULL)
944: curr_mgr->print_fn();
945: }
946:
947: return (0);
948: }
949:
950: void
951: sort_view(void)
952: {
953: if (curr_mgr != NULL)
954: if (curr_mgr->sort_fn != NULL)
955: curr_mgr->sort_fn();
956: }
957:
958: void
959: sig_close(int signal)
960: {
961: gotsig_close = 1;
962: }
963:
964: void
965: sig_resize(int signal)
966: {
967: gotsig_resize = 1;
968: }
969:
970: void
971: sig_alarm(int signal)
972: {
973: gotsig_alarm = 1;
974: }
975:
976: void
977: setup_term(int dmax)
978: {
979: max_disp = dmax;
980: maxprint = dmax;
981:
982: if (rawmode) {
983: columns = rawwidth;
984: lines = DEFAULT_HEIGHT;
985: clear_linebuf();
986: } else {
987: if (dmax < 0)
988: dmax = 0;
989:
990: screen = newterm(NULL, stdout, stdin);
991: if (screen == NULL) {
992: rawmode = 1;
993: interactive = 0;
994: setup_term(dmax);
995: return;
996: }
997: columns = COLS;
998: lines = LINES;
999:
1000: if (maxprint > lines - HEADER_LINES)
1001: maxprint = lines - HEADER_LINES;
1002:
1003: nonl();
1004: keypad(stdscr, TRUE);
1005: intrflush(stdscr, FALSE);
1006:
1007: halfdelay(10);
1008: noecho();
1009: }
1010:
1011: if (dmax == 0)
1012: maxprint = lines - HEADER_LINES;
1013:
1014: field_setup();
1015: }
1016:
1017: struct command *
1018: command_set(struct command *cmd, const char *init)
1019: {
1020: struct command *prev = curr_cmd;
1021:
1022: if (cmd) {
1023: if (init) {
1024: cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf));
1025: if (cmd_len >= sizeof(cmdbuf)) {
1026: cmdbuf[0] = '\0';
1027: cmd_len = 0;
1028: }
1029: } else {
1030: cmd_len = 0;
1031: cmdbuf[0] = 0;
1032: }
1033: }
1034: curr_message = NULL;
1035: curr_cmd = cmd;
1036: need_update = 1;
1037: return prev;
1038: }
1039:
1040: const char *
1041: message_set(const char *msg) {
1042: char *prev = curr_message;
1043: if (msg)
1044: curr_message = strdup(msg);
1045: else
1046: curr_message = NULL;
1047: free(prev);
1048: return NULL;
1049: }
1050:
1051: void
1052: print_cmdline(void)
1053: {
1054: if (curr_cmd) {
1055: attron(A_STANDOUT);
1056: mvprintw(home_line, 0, "%s: ", curr_cmd->prompt);
1057: attroff(A_STANDOUT);
1058: printw("%s", cmdbuf);
1059: } else if (curr_message) {
1060: mvprintw(home_line, 0, "> %s", curr_message);
1061: }
1062: clrtoeol();
1063: }
1064:
1065:
1066: void
1067: cmd_keyboard(int ch)
1068: {
1069: if (curr_cmd == NULL)
1070: return;
1071:
1072: if (ch > 0 && isprint(ch)) {
1073: if (cmd_len < sizeof(cmdbuf) - 1) {
1074: cmdbuf[cmd_len++] = ch;
1075: cmdbuf[cmd_len] = 0;
1076: } else
1077: beep();
1078: }
1079:
1080: switch (ch) {
1081: case KEY_ENTER:
1082: case 0x0a:
1083: case 0x0d:
1084: {
1085: struct command * c = command_set(NULL, NULL);
1.5 ! canacar 1086: c->exec(cmdbuf);
1.1 canacar 1087: break;
1088: }
1089: case KEY_BACKSPACE:
1090: case KEY_DC:
1091: case CTRL_H:
1092: if (cmd_len > 0) {
1093: cmdbuf[--cmd_len] = 0;
1094: } else
1095: beep();
1096: break;
1097: case 0x1b:
1098: case CTRL_G:
1099: if (cmd_len > 0) {
1100: cmdbuf[0] = '\0';
1101: cmd_len = 0;
1102: } else
1103: command_set(NULL, NULL);
1104: break;
1105: default:
1106: break;
1107: }
1108: }
1109:
1110: void
1111: keyboard(void)
1112: {
1113: int ch;
1114:
1115: ch = getch();
1116:
1117: if (curr_cmd) {
1118: cmd_keyboard(ch);
1119: print_cmdline();
1120: return;
1121: }
1122:
1123: if (curr_mgr != NULL)
1124: if (curr_mgr->key_fn != NULL)
1125: if (curr_mgr->key_fn(ch))
1126: return;
1127:
1128: if (curr_message != NULL) {
1129: if (ch > 0) {
1130: curr_message = NULL;
1131: need_update = 1;
1132: }
1133: }
1134:
1135: switch (ch) {
1136: case ' ':
1137: gotsig_alarm = 1;
1138: break;
1139: case 'o':
1140: next_order();
1141: need_sort = 1;
1142: break;
1143: case 'p':
1144: paused = !paused;
1145: gotsig_alarm = 1;
1146: break;
1147: case 'q':
1148: gotsig_close = 1;
1149: break;
1150: case 'r':
1151: sortdir *= -1;
1152: need_sort = 1;
1153: break;
1154: case 'v':
1155: /* FALLTHROUGH */
1156: case KEY_RIGHT:
1157: /* FALLTHROUGH */
1158: case CTRL_F:
1159: next_view();
1160: break;
1161: case KEY_LEFT:
1162: /* FALLTHROUGH */
1163: case CTRL_B:
1164: prev_view();
1165: break;
1166: case KEY_DOWN:
1167: /* FALLTHROUGH */
1168: case CTRL_N:
1169: dispstart++;
1170: need_update = 1;
1171: break;
1172: case KEY_UP:
1173: /* FALLTHROUGH */
1174: case CTRL_P:
1175: dispstart--;
1176: need_update = 1;
1177: break;
1178: case KEY_NPAGE:
1179: /* FALLTHROUGH */
1180: case CTRL_V:
1181: dispstart += maxprint;
1182: need_update = 1;
1183: break;
1184: case KEY_PPAGE:
1185: /* FALLTHROUGH */
1186: case META_V:
1187: dispstart -= maxprint;
1188: need_update = 1;
1189: break;
1190: case KEY_HOME:
1191: /* FALLTHROUGH */
1192: case CTRL_A:
1193: dispstart = 0;
1194: need_update = 1;
1195: break;
1196: case KEY_END:
1197: /* FALLTHROUGH */
1198: case CTRL_E:
1199: dispstart = num_disp;
1200: need_update = 1;
1201: break;
1202: case CTRL_L:
1203: clear();
1204: need_update = 1;
1205: break;
1206: default:
1207: break;
1208: }
1209:
1210: if (set_order_hotkey(ch))
1211: need_sort = 1;
1212: else
1213: set_view_hotkey(ch);
1214: }
1215:
1216: void
1217: engine_initialize(void)
1218: {
1219: signal(SIGTERM, sig_close);
1220: signal(SIGINT, sig_close);
1221: signal(SIGQUIT, sig_close);
1222: signal(SIGWINCH, sig_resize);
1223: signal(SIGALRM, sig_alarm);
1224: }
1225:
1226: void
1227: engine_loop(int countmax)
1228: {
1229: int count = 0;
1230:
1231: for (;;) {
1232: if (gotsig_alarm) {
1233: read_view();
1234: need_sort = 1;
1235: gotsig_alarm = 0;
1236: ualarm(udelay, 0);
1237: }
1238:
1239: if (need_sort) {
1240: sort_view();
1241: need_sort = 0;
1242: need_update = 1;
1243:
1244: /* XXX if sort took too long */
1245: if (gotsig_alarm) {
1246: gotsig_alarm = 0;
1247: ualarm(udelay, 0);
1248: }
1249: }
1250:
1251: if (need_update) {
1252: erase();
1253: disp_update();
1254: end_page();
1255: need_update = 0;
1256: if (countmax && ++count >= countmax)
1257: break;
1258: }
1259:
1260: if (gotsig_close)
1261: break;
1262: if (gotsig_resize) {
1263: if (rawmode == 0)
1264: endwin();
1265: setup_term(max_disp);
1266: gotsig_resize = 0;
1267: need_update = 1;
1268: }
1269:
1270: if (interactive && need_update == 0)
1271: keyboard();
1272: else if (interactive == 0)
1273: usleep(udelay);
1274: }
1275:
1276: if (rawmode == 0)
1277: endwin();
1278: }