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