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