1 /* $Id: engine.c,v 1.7 2008/12/07 02:56:06 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, offset; 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 offset = (fld->width - len) / 2; 231 } else { 232 offset = (fld->width / 2) - (cpos - str); 233 if (offset < 0) 234 offset = 0; 235 else if (offset > (fld->width - len)) 236 offset = fld->width - len; 237 } 238 move_horiz(fld->start + offset); 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, i, d, 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 d = divs[i]; 273 274 val = 0; 275 pos = 0; 276 tr = fld->arg % d; 277 tw = fld->width % d; 278 279 tb_start(); 280 cur = 0; 281 for(i = 0; i < d; i++) { 282 tw += fld->width; 283 tr += fld->arg; 284 285 while (tr >= d) { 286 val++; 287 tr -= d; 288 } 289 while (tw >= d) { 290 pos++; 291 tw -= d; 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(const 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 d) 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 /= d; 678 if (tbprintf("%lluK", size) <= len) 679 goto ok; 680 if (size == 0) 681 goto err; 682 683 tb_start(); 684 size /= d; 685 if (tbprintf("%lluM", size) <= len) 686 goto ok; 687 if (size == 0) 688 goto err; 689 690 tb_start(); 691 size /= d; 692 if (tbprintf("%lluG", size) <= len) 693 goto ok; 694 if (size == 0) 695 goto err; 696 697 tb_start(); 698 size /= d; 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 d) 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 /= d; 735 if (tbprintf("%lldK", size) <= len) 736 goto ok; 737 if (size == 0) 738 goto err; 739 740 tb_start(); 741 size /= d; 742 if (tbprintf("%lldM", size) <= len) 743 goto ok; 744 if (size == 0) 745 goto err; 746 747 tb_start(); 748 size /= d; 749 if (tbprintf("%lldG", size) <= len) 750 goto ok; 751 if (size == 0) 752 goto err; 753 754 tb_start(); 755 size /= d; 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 void 815 print_fld_float(field_def *fld, double f, int prec) 816 { 817 int len; 818 819 if (fld == NULL) 820 return; 821 822 len = fld->width; 823 if (len < 1) 824 return; 825 826 tb_start(); 827 if (tbprintf("%*.*f", len, prec, f) > len) 828 print_fld_str(fld, "*"); 829 else 830 print_fld_tb(fld); 831 tb_end(); 832 } 833 834 835 /* ordering */ 836 837 void 838 set_order(const char *opt) 839 { 840 order_type *o; 841 842 if (curr_view == NULL || curr_view->mgr == NULL) 843 return; 844 845 curr_view->mgr->order_curr = curr_view->mgr->order_list; 846 847 if (opt == NULL) 848 return; 849 850 o = curr_view->mgr->order_list; 851 852 if (o == NULL) 853 return; 854 855 for (;o->name != NULL; o++) { 856 if (strcasecmp(opt, o->match) == 0) { 857 curr_view->mgr->order_curr = o; 858 return; 859 } 860 } 861 } 862 863 int 864 set_order_hotkey(int ch) 865 { 866 order_type *o; 867 int key = ch; 868 869 if (curr_view == NULL || curr_view->mgr == NULL) 870 return 0; 871 872 o = curr_view->mgr->order_list; 873 874 if (o == NULL) 875 return 0; 876 877 for (;o->name != NULL; o++) { 878 if (key == o->hotkey) { 879 if (curr_view->mgr->order_curr == o) { 880 sortdir *= -1; 881 } else { 882 curr_view->mgr->order_curr = o; 883 } 884 return 1; 885 } 886 } 887 888 return 0; 889 } 890 891 void 892 next_order(void) 893 { 894 order_type *o, *oc; 895 896 if (curr_view->mgr->order_list == NULL) 897 return; 898 899 oc = curr_view->mgr->order_curr; 900 901 for (o = curr_view->mgr->order_list; o->name != NULL; o++) { 902 if (oc == o) { 903 o++; 904 if (o->name == NULL) 905 break; 906 curr_view->mgr->order_curr = o; 907 return; 908 } 909 } 910 911 curr_view->mgr->order_curr = curr_view->mgr->order_list; 912 } 913 914 915 /* main program functions */ 916 917 int 918 read_view(void) 919 { 920 if (curr_mgr == NULL) 921 return (0); 922 923 if (paused) 924 return (0); 925 926 if (curr_mgr->read_fn != NULL) 927 return (curr_mgr->read_fn()); 928 929 return (0); 930 } 931 932 933 int 934 disp_update(void) 935 { 936 int li; 937 938 if (maxprint < 0) 939 dispstart = 0; 940 else if (dispstart + maxprint > num_disp) 941 dispstart = num_disp - maxprint; 942 943 if (dispstart < 0) 944 dispstart = 0; 945 946 if (curr_view == NULL) 947 return 0; 948 949 if (curr_mgr != NULL) { 950 curr_line = 0; 951 952 if (curr_mgr->header_fn != NULL) { 953 li = curr_mgr->header_fn(); 954 if (li < 0) 955 return (1); 956 curr_line = ++li; 957 home_line = li + maxprint + 1; 958 } 959 960 print_title(); 961 962 if (curr_mgr->print_fn != NULL) 963 curr_mgr->print_fn(); 964 } 965 966 return (0); 967 } 968 969 void 970 sort_view(void) 971 { 972 if (curr_mgr != NULL) 973 if (curr_mgr->sort_fn != NULL) 974 curr_mgr->sort_fn(); 975 } 976 977 void 978 sig_close(int sig) 979 { 980 gotsig_close = 1; 981 } 982 983 void 984 sig_resize(int sig) 985 { 986 gotsig_resize = 1; 987 } 988 989 void 990 sig_alarm(int sig) 991 { 992 gotsig_alarm = 1; 993 } 994 995 void 996 setup_term(int dmax) 997 { 998 max_disp = dmax; 999 maxprint = dmax; 1000 1001 if (rawmode) { 1002 columns = rawwidth; 1003 lines = DEFAULT_HEIGHT; 1004 clear_linebuf(); 1005 } else { 1006 if (dmax < 0) 1007 dmax = 0; 1008 1009 screen = newterm(NULL, stdout, stdin); 1010 if (screen == NULL) { 1011 rawmode = 1; 1012 interactive = 0; 1013 setup_term(dmax); 1014 return; 1015 } 1016 columns = COLS; 1017 lines = LINES; 1018 1019 if (maxprint > lines - HEADER_LINES) 1020 maxprint = lines - HEADER_LINES; 1021 1022 nonl(); 1023 keypad(stdscr, TRUE); 1024 intrflush(stdscr, FALSE); 1025 1026 halfdelay(10); 1027 noecho(); 1028 } 1029 1030 if (dmax == 0) 1031 maxprint = lines - HEADER_LINES; 1032 1033 field_setup(); 1034 } 1035 1036 struct command * 1037 command_set(struct command *cmd, const char *init) 1038 { 1039 struct command *prev = curr_cmd; 1040 1041 if (cmd) { 1042 if (init) { 1043 cmd_len = strlcpy(cmdbuf, init, sizeof(cmdbuf)); 1044 if (cmd_len >= sizeof(cmdbuf)) { 1045 cmdbuf[0] = '\0'; 1046 cmd_len = 0; 1047 } 1048 } else { 1049 cmd_len = 0; 1050 cmdbuf[0] = 0; 1051 } 1052 } 1053 curr_message = NULL; 1054 curr_cmd = cmd; 1055 need_update = 1; 1056 return prev; 1057 } 1058 1059 const char * 1060 message_set(const char *msg) { 1061 char *prev = curr_message; 1062 if (msg) 1063 curr_message = strdup(msg); 1064 else 1065 curr_message = NULL; 1066 free(prev); 1067 return NULL; 1068 } 1069 1070 void 1071 print_cmdline(void) 1072 { 1073 if (curr_cmd) { 1074 attron(A_STANDOUT); 1075 mvprintw(home_line, 0, "%s: ", curr_cmd->prompt); 1076 attroff(A_STANDOUT); 1077 printw("%s", cmdbuf); 1078 } else if (curr_message) { 1079 mvprintw(home_line, 0, "> %s", curr_message); 1080 } 1081 clrtoeol(); 1082 } 1083 1084 1085 void 1086 cmd_keyboard(int ch) 1087 { 1088 if (curr_cmd == NULL) 1089 return; 1090 1091 if (ch > 0 && isprint(ch)) { 1092 if (cmd_len < sizeof(cmdbuf) - 1) { 1093 cmdbuf[cmd_len++] = ch; 1094 cmdbuf[cmd_len] = 0; 1095 } else 1096 beep(); 1097 } 1098 1099 switch (ch) { 1100 case KEY_ENTER: 1101 case 0x0a: 1102 case 0x0d: 1103 { 1104 struct command * c = command_set(NULL, NULL); 1105 c->exec(cmdbuf); 1106 break; 1107 } 1108 case KEY_BACKSPACE: 1109 case KEY_DC: 1110 case CTRL_H: 1111 if (cmd_len > 0) { 1112 cmdbuf[--cmd_len] = 0; 1113 } else 1114 beep(); 1115 break; 1116 case 0x1b: 1117 case CTRL_G: 1118 if (cmd_len > 0) { 1119 cmdbuf[0] = '\0'; 1120 cmd_len = 0; 1121 } else 1122 command_set(NULL, NULL); 1123 break; 1124 default: 1125 break; 1126 } 1127 } 1128 1129 void 1130 keyboard(void) 1131 { 1132 int ch; 1133 1134 ch = getch(); 1135 1136 if (curr_cmd) { 1137 cmd_keyboard(ch); 1138 print_cmdline(); 1139 return; 1140 } 1141 1142 if (curr_mgr != NULL) 1143 if (curr_mgr->key_fn != NULL) 1144 if (curr_mgr->key_fn(ch)) 1145 return; 1146 1147 if (curr_message != NULL) { 1148 if (ch > 0) { 1149 curr_message = NULL; 1150 need_update = 1; 1151 } 1152 } 1153 1154 switch (ch) { 1155 case ' ': 1156 gotsig_alarm = 1; 1157 break; 1158 case 'o': 1159 next_order(); 1160 need_sort = 1; 1161 break; 1162 case 'p': 1163 paused = !paused; 1164 gotsig_alarm = 1; 1165 break; 1166 case 'q': 1167 gotsig_close = 1; 1168 break; 1169 case 'r': 1170 sortdir *= -1; 1171 need_sort = 1; 1172 break; 1173 case 'v': 1174 /* FALLTHROUGH */ 1175 case KEY_RIGHT: 1176 /* FALLTHROUGH */ 1177 case CTRL_F: 1178 next_view(); 1179 break; 1180 case KEY_LEFT: 1181 /* FALLTHROUGH */ 1182 case CTRL_B: 1183 prev_view(); 1184 break; 1185 case KEY_DOWN: 1186 /* FALLTHROUGH */ 1187 case CTRL_N: 1188 dispstart++; 1189 need_update = 1; 1190 break; 1191 case KEY_UP: 1192 /* FALLTHROUGH */ 1193 case CTRL_P: 1194 dispstart--; 1195 need_update = 1; 1196 break; 1197 case KEY_NPAGE: 1198 /* FALLTHROUGH */ 1199 case CTRL_V: 1200 dispstart += maxprint; 1201 need_update = 1; 1202 break; 1203 case KEY_PPAGE: 1204 /* FALLTHROUGH */ 1205 case META_V: 1206 dispstart -= maxprint; 1207 need_update = 1; 1208 break; 1209 case KEY_HOME: 1210 /* FALLTHROUGH */ 1211 case CTRL_A: 1212 dispstart = 0; 1213 need_update = 1; 1214 break; 1215 case KEY_END: 1216 /* FALLTHROUGH */ 1217 case CTRL_E: 1218 dispstart = num_disp; 1219 need_update = 1; 1220 break; 1221 case CTRL_L: 1222 clear(); 1223 need_update = 1; 1224 break; 1225 default: 1226 break; 1227 } 1228 1229 if (set_order_hotkey(ch)) 1230 need_sort = 1; 1231 else 1232 set_view_hotkey(ch); 1233 } 1234 1235 void 1236 engine_initialize(void) 1237 { 1238 signal(SIGTERM, sig_close); 1239 signal(SIGINT, sig_close); 1240 signal(SIGQUIT, sig_close); 1241 signal(SIGWINCH, sig_resize); 1242 signal(SIGALRM, sig_alarm); 1243 } 1244 1245 void 1246 engine_loop(int countmax) 1247 { 1248 int count = 0; 1249 1250 for (;;) { 1251 if (gotsig_alarm) { 1252 read_view(); 1253 need_sort = 1; 1254 gotsig_alarm = 0; 1255 ualarm(udelay, 0); 1256 } 1257 1258 if (need_sort) { 1259 sort_view(); 1260 need_sort = 0; 1261 need_update = 1; 1262 1263 /* XXX if sort took too long */ 1264 if (gotsig_alarm) { 1265 gotsig_alarm = 0; 1266 ualarm(udelay, 0); 1267 } 1268 } 1269 1270 if (need_update) { 1271 erase(); 1272 disp_update(); 1273 end_page(); 1274 need_update = 0; 1275 if (countmax && ++count >= countmax) 1276 break; 1277 } 1278 1279 if (gotsig_close) 1280 break; 1281 if (gotsig_resize) { 1282 if (rawmode == 0) 1283 endwin(); 1284 setup_term(max_disp); 1285 gotsig_resize = 0; 1286 need_update = 1; 1287 } 1288 1289 if (interactive && need_update == 0) 1290 keyboard(); 1291 else if (interactive == 0) 1292 usleep(udelay); 1293 } 1294 1295 if (rawmode == 0) 1296 endwin(); 1297 } 1298