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