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