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