editline.c (37116B)
1 /* $Revision: 1.21 $ 2 ** 3 ** Main editing routines for editline library. 4 ** 5 ** There are two editline implementations: synchronous and asynchronsou. 6 ** Synchronous is a blocking read call readline(CONST char *prompt). 7 ** This call returns after a whole line has been read, returning that 8 ** line to the user. The returned line could have been pulled from history 9 ** or directly from stdin. 10 ** 11 ** Asynchronous is a character process non-blocking call, which make 12 ** a callout to an end-of-line handler. The entry points for these calls 13 ** are: 14 ** rl_callback_handler_install(CONST char *prompt, rl_vcpfunc_t eol_handler, 15 ** rl_callback_read_char(void) 16 ** rl_callback_handler_remove(void) 17 ** 18 ** Algorithm 19 ** 20 ** The major steps taken for synchronous API are: 21 ** READ LINE 22 ** TTYInfo 23 ** rl_ttyset(0) 24 ** hist_add(nil) 25 ** TTYputs(Prompt) 26 ** read line 27 ** TTYputs(NEWLINE) 28 ** rl_ttyset(1) 29 ** DISPOSE(H.Lines[-H.Size]); 30 ** return line 31 ** add to history 32 ** All operations are done during the readline call. 33 ** 34 ** The Major steps for asynchronous are broken into three stages. 35 ** 36 ** START <- rl_callback_handler_install 37 ** TTYInfo 38 ** rl_ttyset(0) 39 ** hist_add(nil) 40 ** 41 ** READ CHAR <- rl_callback_read_char 42 ** TTYInfo 43 ** hist_add(nil) 44 ** read character 45 ** DISPOSE(H.Lines[-H.Size]); 46 ** if end-of-line then call eol_callback with line 47 ** hist_add(nil) 48 ** TTYputs(Prompt) 49 ** 50 ** CLEAN <- rl_callback_handler_remove 51 ** rl_ttyset(1) 52 ** 53 ** START is done initially once. CLEAN is done at termination. READ 54 */ 55 56 #ifdef INCLUDE_EDITLINE 57 58 #include "sal/appl/editline/editline.h" 59 #include "editline.h" 60 #if defined(INCLUDE_AUTOCOMPLETE) 61 #include <sal/appl/editline/autocomplete.h> 62 #endif 63 64 #include <appl/diag/shell.h> 65 66 #if defined(USE_POSIX_SIGNALS) 67 #include <signal.h> 68 #include <errno.h> 69 #else 70 /* Dummy defines to avoid too many ifdefs */ 71 #define SIGINT 2 72 #define SIGQUIT 3 73 #define SIGTSTP 20 74 #endif 75 76 /* 77 ** Manifest constants. 78 */ 79 #define SCREEN_WIDTH 80 80 #define SCREEN_ROWS 24 81 #define NO_ARG (-1) 82 #define DEL 127 83 #define TAB '\t' 84 #define CTL(x) ((x) & 0x1F) 85 #define ISCTL(x) ((x) && (x) < ' ') 86 #define UNCTL(x) ((x) + 64) 87 #define META(x) ((x) | 0x80) 88 #define ISMETA(x) ((x) & 0x80) 89 #define UNMETA(x) ((x) & 0x7F) 90 #define MAPSIZE 32 91 #define METAMAPSIZE 20 92 #if !defined(HIST_SIZE) 93 #define HIST_SIZE 20 94 #endif /* !defined(HIST_SIZE) */ 95 96 97 typedef CONST CHAR *STRING; 98 99 /* 100 ** Command status codes. 101 */ 102 typedef enum _STATE { 103 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal 104 } STATE; 105 106 /* 107 ** The type of case-changing to perform. 108 */ 109 typedef enum _CASE { 110 TOupper, TOlower 111 } CASE; 112 113 /* 114 ** Key to command mapping. 115 */ 116 typedef struct _KEYMAP { 117 CHAR Key; 118 char Active; 119 STATE (*Function)(); 120 } KEYMAP; 121 122 /* 123 ** Command history structure. 124 */ 125 typedef struct _HISTORY { 126 int Size; 127 int Pos; 128 CHAR *Lines[HIST_SIZE]; 129 } HISTORY; 130 131 /* 132 ** Globals. 133 */ 134 int rl_eof; 135 int rl_erase; 136 int rl_intr; 137 int rl_kill; 138 int rl_quit; 139 #if defined(DO_SIGTSTP) 140 int rl_susp; 141 #endif /* defined(DO_SIGTSTP) */ 142 char *(*rl_complete)() = rl_complete_file; 143 int (*rl_list_possib)() = rl_list_possib_file; 144 145 STATIC CHAR NIL[] = ""; 146 STATIC STRING Input = NIL; 147 STATIC CHAR *Line; 148 STATIC CONST char *Prompt; 149 STATIC CHAR *Yanked; 150 STATIC char *Screen; 151 STATIC char NEWLINE[]= CRLF; 152 STATIC HISTORY H; 153 STATIC int Repeat; 154 STATIC int End; 155 STATIC int Mark; 156 STATIC int CursorPos; /* Relative to beginning of prompt */ 157 STATIC int OldPoint; 158 STATIC int Point; 159 STATIC int PushBack; 160 STATIC int Pushed; 161 STATIC int Signal; 162 FORWARD KEYMAP Map[MAPSIZE]; 163 FORWARD KEYMAP MetaMap[METAMAPSIZE]; 164 STATIC SIZE_T Length; 165 STATIC SIZE_T ScreenCount; 166 STATIC SIZE_T ScreenSize; 167 STATIC char *backspace; 168 STATIC int TTYwidth; 169 STATIC int TTYrows; 170 171 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ 172 int rl_meta_chars = 1; 173 174 STATIC rl_vcpfunc_t gCALLBACK_EOL_HANDLER = NULL; 175 STATIC void *gCALLBACK_EOL_HANDLER_CTX = NULL; 176 STATIC rf_vcpfunc_t gCALLBACK_EOF_HANDLER = NULL; 177 STATIC void *gCALLBACK_EOF_HANDLER_CTX = NULL; 178 179 /* 180 ** Declarations. 181 */ 182 STATIC CHAR *editinput(); 183 #if defined(USE_TERMCAP) 184 extern char *getenv(); 185 extern char *tgetstr(); 186 extern int tgetent(); 187 extern int tgetnum(); 188 #endif /* defined(USE_TERMCAP) */ 189 190 /* 191 ** TTY input/output functions. 192 */ 193 194 STATIC void 195 TTYflush() 196 { 197 if (ScreenCount) { 198 (void)sal_console_write(Screen, ScreenCount); 199 ScreenCount = 0; 200 } 201 } 202 203 STATIC void 204 TTYput(CONST CHAR c) 205 { 206 Screen[ScreenCount] = c; 207 switch (c) { 208 case '\b': 209 CursorPos--; 210 break; 211 case '\r': 212 /* Actually, never use CR any more; use TTYbol() instead */ 213 CursorPos = 0; 214 break; 215 default: 216 if (c >= ' ') 217 CursorPos++; 218 } 219 if (++ScreenCount >= ScreenSize - 1) { 220 char *p; 221 ScreenSize += SCREEN_INC; 222 p = NEW(char, ScreenSize); 223 memcpy(p, Screen, (ScreenSize - SCREEN_INC)); 224 DISPOSE(Screen); 225 Screen = p; 226 } 227 } 228 229 STATIC void 230 TTYputs(STRING p) 231 { 232 while (*p) 233 TTYput(*p++); 234 } 235 236 STATIC void 237 TTYshow(CHAR c) 238 { 239 if (c == DEL) { 240 TTYput('^'); 241 TTYput('?'); 242 } else if (c == TAB) { 243 /* XXX */ 244 } else if (ISCTL(c)) { 245 TTYput('^'); 246 TTYput(UNCTL(c)); 247 } else if (rl_meta_chars && ISMETA(c)) { 248 TTYput('M'); 249 TTYput('-'); 250 TTYput(UNMETA(c)); 251 } else { 252 TTYput(c); 253 } 254 } 255 256 STATIC void 257 TTYstring(CHAR *p) 258 { 259 while (*p) 260 TTYshow(*p++); 261 } 262 263 STATIC unsigned int 264 TTYget() 265 { 266 CHAR c; 267 int n; 268 269 TTYflush(); 270 if (Pushed) { 271 Pushed = 0; 272 return PushBack; 273 } 274 275 if (*Input) { 276 return *Input++; 277 } 278 279 n = sal_console_read(&c, 1) == 1 ? c : EOF; 280 281 return n; 282 } 283 284 #define TTYback() (backspace ? TTYputs((STRING)backspace) : TTYput('\b')) 285 286 STATIC void 287 TTYbackn(int n) 288 { 289 while (--n >= 0) 290 TTYback(); 291 } 292 293 STATIC void 294 TTYbol() 295 { 296 while (CursorPos > 0) 297 TTYback(); 298 } 299 300 STATIC void 301 TTYinfo() 302 { 303 static int init; 304 sal_console_info_t info; 305 #if defined(USE_TERMCAP) 306 char *term; 307 char buff[2048]; 308 char *bp; 309 char *p; 310 #endif /* defined(USE_TERMCAP) */ 311 312 if (init) { 313 /* Perhaps we got resized. */ 314 if (sal_console_info_get(&info) >= 0 315 && info.cols > 0 && info.rows > 0) { 316 TTYwidth = info.cols; 317 TTYrows = info.rows; 318 } 319 return; 320 } 321 init++; 322 323 TTYwidth = TTYrows = 0; 324 #if defined(USE_TERMCAP) 325 bp = &buff[0]; 326 if ((term = getenv("TERM")) == NULL) 327 term = "dumb"; 328 if (tgetent(buff, term) < 0) { 329 TTYwidth = SCREEN_WIDTH; 330 TTYrows = SCREEN_ROWS; 331 return; 332 } 333 p = tgetstr("le", &bp); 334 backspace = p ? sal_strdup(p) : NULL; 335 TTYwidth = tgetnum("co"); 336 TTYrows = tgetnum("li"); 337 #endif /* defined(USE_TERMCAP) */ 338 339 if (sal_console_info_get(&info) >= 0) { 340 TTYwidth = info.cols; 341 TTYrows = info.rows; 342 } 343 344 if (TTYwidth <= 0 || TTYrows <= 0) { 345 TTYwidth = SCREEN_WIDTH; 346 TTYrows = SCREEN_ROWS; 347 } 348 } 349 350 351 /* 352 ** Print an array of words in columns. 353 */ 354 STATIC void 355 columns(int ac, CHAR **av) 356 { 357 CHAR *p; 358 int i; 359 int j; 360 int k; 361 int len; 362 int skip; 363 int longest; 364 int cols; 365 366 /* Find longest name, determine column count from that. */ 367 for (longest = 0, i = 0; i < ac; i++) 368 if ((j = strlen((char *)av[i])) > longest) 369 longest = j; 370 cols = TTYwidth / (longest + 3); 371 372 TTYputs((STRING)NEWLINE); 373 for (skip = ac / cols + 1, i = 0; i < skip; i++) { 374 for (j = i; j < ac; j += skip) { 375 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++) 376 TTYput(*p); 377 if (j + skip < ac) 378 while (++len < longest + 3) 379 TTYput(' '); 380 } 381 TTYputs((STRING)NEWLINE); 382 } 383 } 384 385 STATIC void 386 reposition() 387 { 388 int i; 389 CHAR *p; 390 391 TTYbol(); 392 TTYputs((STRING)Prompt); 393 for (i = Point, p = Line; --i >= 0; p++) { 394 TTYshow(*p); 395 } 396 } 397 398 STATIC void 399 left(STATE Change) 400 { 401 CHAR c; 402 403 TTYback(); 404 if (Point) { 405 c = Line[Point - 1]; 406 if (c == TAB) { 407 /* XXX */ 408 } 409 else if (ISCTL(c)) 410 TTYback(); 411 else if (rl_meta_chars && ISMETA(c)) { 412 TTYback(); 413 TTYback(); 414 } 415 } 416 if (Change == CSmove) 417 Point--; 418 } 419 420 STATIC void 421 right(STATE Change) 422 { 423 TTYshow(Line[Point]); 424 if (Change == CSmove) 425 Point++; 426 } 427 428 STATIC STATE 429 ring_bell() 430 { 431 TTYput('\07'); 432 TTYflush(); 433 return CSstay; 434 } 435 436 STATIC STATE 437 do_macro(unsigned int c) 438 { 439 #if defined(USE_TERMCAP) 440 CHAR name[4]; 441 442 name[0] = '_'; 443 name[1] = c; 444 name[2] = '_'; 445 name[3] = '\0'; 446 447 if ((Input = (CHAR *)getenv((char *)name)) == NULL) { 448 Input = NIL; 449 return ring_bell(); 450 } 451 #endif 452 return CSstay; 453 } 454 455 STATIC STATE 456 do_forward(STATE move) 457 { 458 int i; 459 CHAR *p; 460 461 i = 0; 462 do { 463 p = &Line[Point]; 464 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) 465 if (move == CSmove) 466 right(CSstay); 467 468 for (; Point < End && isalnum(*p); Point++, p++) 469 if (move == CSmove) 470 right(CSstay); 471 472 if (Point == End) 473 break; 474 } while (++i < Repeat); 475 476 return CSstay; 477 } 478 479 STATIC STATE 480 do_case(CASE type) 481 { 482 int i; 483 int end; 484 int count; 485 CHAR *p; 486 487 (void)do_forward(CSstay); 488 if (OldPoint != Point) { 489 if ((count = Point - OldPoint) < 0) 490 count = -count; 491 Point = OldPoint; 492 if ((end = Point + count) > End) 493 end = End; 494 for (i = Point, p = &Line[i]; i < end; i++, p++) { 495 if (type == TOupper) { 496 if (islower(*p)) 497 *p = toupper(*p); 498 } 499 else if (isupper(*p)) 500 *p = tolower(*p); 501 right(CSmove); 502 } 503 } 504 return CSstay; 505 } 506 507 STATIC STATE 508 case_down_word() 509 { 510 return do_case(TOlower); 511 } 512 513 STATIC STATE 514 case_up_word() 515 { 516 return do_case(TOupper); 517 } 518 519 STATIC void 520 ceol() 521 { 522 int extras; 523 int i; 524 CHAR *p; 525 526 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { 527 TTYput(' '); 528 if (*p == TAB) { 529 /* XXX */ 530 } 531 else if (ISCTL(*p)) { 532 TTYput(' '); 533 extras++; 534 } 535 else if (rl_meta_chars && ISMETA(*p)) { 536 TTYput(' '); 537 TTYput(' '); 538 extras += 2; 539 } 540 } 541 542 for (i += extras; i > Point; i--) 543 TTYback(); 544 } 545 546 #if defined(SEARCH_HISTORY) 547 STATIC void 548 clear_line() 549 { 550 Point = -strlen(Prompt); 551 TTYbol(); 552 ceol(); 553 Point = 0; 554 End = 0; 555 Line[0] = '\0'; 556 } 557 #endif 558 559 STATIC STATE 560 insert_string(CHAR *p) 561 { 562 SIZE_T len; 563 int i; 564 CHAR *new; 565 CHAR *q; 566 567 len = strlen((char *)p); 568 if (End + len >= Length) { 569 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) 570 return CSstay; 571 if (Length) { 572 COPYFROMTO(new, Line, Length); 573 DISPOSE(Line); 574 } 575 Line = new; 576 Length += len + MEM_INC; 577 } 578 579 for (q = &Line[Point], i = End - Point; --i >= 0; ) 580 q[len + i] = q[i]; 581 COPYFROMTO(&Line[Point], p, len); 582 End += len; 583 Line[End] = '\0'; 584 TTYstring(&Line[Point]); 585 Point += len; 586 587 return Point == End ? CSstay : CSmove; 588 } 589 590 STATIC STATE 591 redisplay() 592 { 593 TTYputs((STRING)NEWLINE); 594 TTYputs((STRING)Prompt); 595 TTYstring(Line); 596 return CSmove; 597 } 598 599 STATIC STATE 600 redisplay_no_nl() 601 { 602 TTYbol(); 603 TTYputs((STRING)Prompt); 604 TTYstring(Line); 605 return CSmove; 606 } 607 608 STATIC STATE 609 toggle_meta_mode() 610 { 611 rl_meta_chars = !rl_meta_chars; 612 return redisplay(); 613 } 614 615 616 STATIC CHAR * 617 next_hist() 618 { 619 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos]; 620 } 621 622 STATIC CHAR * 623 prev_hist() 624 { 625 return H.Pos == 0 ? NULL : H.Lines[--H.Pos]; 626 } 627 628 STATIC STATE 629 do_insert_hist(CHAR *p) 630 { 631 if (p == NULL) 632 return ring_bell(); 633 Point = 0; 634 reposition(); 635 ceol(); 636 End = 0; 637 return insert_string(p); 638 } 639 640 STATIC STATE 641 do_hist(CHAR *(*move)() ) 642 { 643 CHAR *p; 644 int i; 645 646 i = 0; 647 do { 648 if ((p = (*move)()) == NULL) 649 return ring_bell(); 650 } while (++i < Repeat); 651 return do_insert_hist(p); 652 } 653 654 STATIC STATE 655 h_next() 656 { 657 return do_hist(next_hist); 658 } 659 660 STATIC STATE 661 h_prev() 662 { 663 return do_hist(prev_hist); 664 } 665 666 STATIC STATE 667 h_first() 668 { 669 return do_insert_hist(H.Lines[H.Pos = 0]); 670 } 671 672 STATIC STATE 673 h_last() 674 { 675 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]); 676 } 677 678 #if defined(SEARCH_HISTORY) 679 /* 680 ** Return zero if pat appears as a substring in text. 681 */ 682 STATIC int 683 _substrcmp(char *text, char *pat, int len) 684 { 685 CHAR c; 686 687 if ((c = *pat) == '\0') 688 return *text == '\0'; 689 for ( ; *text; text++) 690 if (*text == c && strncmp(text, pat, len) == 0) 691 return 0; 692 return 1; 693 } 694 #endif 695 696 STATIC STATE 697 do_prefix_search(CHAR *(*move)() ) 698 { 699 int old_point; 700 701 old_point = Point; 702 703 for ( ; (*move)() != NULL; ) 704 if (strncmp((char *)H.Lines[H.Pos], (char *)Line, Point) == 0) { 705 (void) do_insert_hist(H.Lines[H.Pos]); 706 Point = old_point; 707 return CSmove; 708 } 709 710 return ring_bell(); 711 } 712 713 STATIC STATE 714 h_search_prev() 715 { 716 return do_prefix_search(prev_hist); 717 } 718 719 STATIC STATE 720 h_search_next() 721 { 722 return do_prefix_search(next_hist); 723 } 724 725 #if defined(SEARCH_HISTORY) 726 STATIC CHAR * 727 search_hist(CHAR *search, CHAR *(*move)() ) 728 { 729 static CHAR *old_search; 730 int len; 731 int pos; 732 int (*match)(); 733 char *pat; 734 735 /* Save or get remembered search pattern. */ 736 if (search && *search) { 737 if (old_search) 738 DISPOSE(old_search); 739 old_search = (CHAR *)sal_strdup((char *)search); 740 } 741 else { 742 if (old_search == NULL || *old_search == '\0') 743 return NULL; 744 search = old_search; 745 } 746 747 /* Set up pattern-finder. */ 748 if (*search == '^') { 749 match = strncmp; 750 pat = (char *)(search + 1); 751 } 752 else { 753 match = _substrcmp; 754 pat = (char *)search; 755 } 756 len = strlen(pat); 757 758 for (pos = H.Pos; (*move)() != NULL; ) 759 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) 760 return H.Lines[H.Pos]; 761 H.Pos = pos; 762 return NULL; 763 } 764 #endif 765 766 #if defined(SEARCH_HISTORY) 767 STATIC STATE 768 h_search() 769 { 770 static int Searching; 771 CONST char *old_prompt; 772 CHAR *(*move)(); 773 CHAR *p; 774 775 if (Searching) 776 return ring_bell(); 777 Searching = 1; 778 779 clear_line(); 780 old_prompt = Prompt; 781 Prompt = "Search: "; 782 TTYputs((STRING)Prompt); 783 move = Repeat == NO_ARG ? prev_hist : next_hist; 784 CursorPos = strlen(Prompt); 785 p = editinput(); 786 Searching = 0; 787 if (p == NULL && Signal > 0) { 788 Signal = 0; 789 clear_line(); 790 Prompt = old_prompt; 791 return redisplay_no_nl(); 792 } 793 p = search_hist(p, move); 794 clear_line(); 795 Prompt = old_prompt; 796 if (p == NULL) { 797 (void)ring_bell(); 798 return redisplay_no_nl(); 799 } 800 return do_insert_hist(p); 801 } 802 #endif 803 804 STATIC STATE 805 fd_char() 806 { 807 int i; 808 809 i = 0; 810 do { 811 if (Point >= End) 812 break; 813 right(CSmove); 814 } while (++i < Repeat); 815 return CSstay; 816 } 817 818 STATIC void 819 save_yank(int begin,int i) 820 { 821 if (Yanked) { 822 DISPOSE(Yanked); 823 Yanked = NULL; 824 } 825 826 if (i < 1) 827 return; 828 829 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) { 830 COPYFROMTO(Yanked, &Line[begin], i); 831 Yanked[i] = '\0'; 832 } 833 } 834 835 STATIC STATE 836 delete_string(int count) 837 { 838 int i; 839 CHAR *p; 840 841 if (count <= 0 || End == Point) 842 return ring_bell(); 843 844 if (count == 1 && Point == End - 1) { 845 /* Optimize common case of delete at end of line. */ 846 End--; 847 p = &Line[Point]; 848 i = 1; 849 TTYput(' '); 850 if (*p == TAB) { 851 /* XXX */ 852 } 853 else if (ISCTL(*p)) { 854 i = 2; 855 TTYput(' '); 856 } 857 else if (rl_meta_chars && ISMETA(*p)) { 858 i = 3; 859 TTYput(' '); 860 TTYput(' '); 861 } 862 TTYbackn(i); 863 *p = '\0'; 864 return CSmove; 865 } 866 if (Point + count > End && (count = End - Point) <= 0) 867 return CSstay; 868 869 if (count > 1) 870 save_yank(Point, count); 871 872 ceol(); 873 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++) 874 p[0] = p[count]; 875 End -= count; 876 TTYstring(&Line[Point]); 877 return CSmove; 878 } 879 880 STATIC STATE 881 bk_char() 882 { 883 int i; 884 885 i = 0; 886 do { 887 if (Point == 0) 888 break; 889 left(CSmove); 890 } while (++i < Repeat); 891 892 return CSstay; 893 } 894 895 STATIC STATE 896 bk_del_char() 897 { 898 int i; 899 900 i = 0; 901 do { 902 if (Point == 0) 903 break; 904 left(CSmove); 905 } while (++i < Repeat); 906 907 return delete_string(i); 908 } 909 910 STATIC STATE 911 kill_line() 912 { 913 int i; 914 915 if (Repeat != NO_ARG) { 916 if (Repeat < Point) { 917 i = Point; 918 Point = Repeat; 919 reposition(); 920 (void)delete_string(i - Point); 921 } 922 else if (Repeat > Point) { 923 right(CSmove); 924 (void)delete_string(Repeat - Point - 1); 925 } 926 return CSmove; 927 } 928 929 save_yank(Point, End - Point); 930 ceol(); 931 Line[Point] = '\0'; 932 End = Point; 933 return CSstay; 934 } 935 936 STATIC STATE 937 insert_char(int c) 938 { 939 STATE s; 940 CHAR buff[2]; 941 CHAR *p; 942 CHAR *q; 943 int i; 944 945 if (Repeat == NO_ARG || Repeat < 2) { 946 buff[0] = c; 947 buff[1] = '\0'; 948 return insert_string(buff); 949 } 950 951 if ((p = NEW(CHAR, Repeat + 1)) == NULL) 952 return CSstay; 953 for (i = Repeat, q = p; --i >= 0; ) 954 *q++ = c; 955 *q = '\0'; 956 Repeat = 0; 957 s = insert_string(p); 958 DISPOSE(p); 959 return s; 960 } 961 962 static STATE 963 meta() 964 { 965 int c; 966 KEYMAP *kp; 967 968 if ((c = TTYget()) == EOF) 969 return CSeof; 970 #if defined(ANSI_ARROWS) 971 /* Also include VT-100 arrows. */ 972 if (c == '[' || c == 'O') 973 switch ((int)(c = TTYget())) { 974 default: return ring_bell(); 975 case EOF: return CSeof; 976 case 'A': return h_prev(); 977 case 'B': return h_next(); 978 case 'C': return fd_char(); 979 case 'D': return bk_char(); 980 } 981 #endif /* defined(ANSI_ARROWS) */ 982 983 if (isdigit(c)) { 984 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); ) 985 Repeat = Repeat * 10 + c - '0'; 986 Pushed = 1; 987 PushBack = c; 988 return CSstay; 989 } 990 991 if (isupper(c)) 992 return do_macro((unsigned int)c); 993 for (OldPoint = Point, kp = MetaMap; kp < &MetaMap[METAMAPSIZE]; kp++) 994 if (kp->Key == c && kp->Active) 995 return (*kp->Function)(); 996 997 return ring_bell(); 998 } 999 1000 STATIC STATE 1001 emacs(unsigned int c) 1002 { 1003 STATE s; 1004 KEYMAP *kp; 1005 1006 #if 0 1007 /* This test makes it impossible to enter eight-bit characters when 1008 * meta-char mode is enabled. */ 1009 if (rl_meta_chars && ISMETA(c)) { 1010 Pushed = 1; 1011 PushBack = UNMETA(c); 1012 return meta(); 1013 } 1014 #endif /* 0 */ 1015 for (kp = Map; kp < &Map[MAPSIZE]; kp++) 1016 if (kp->Key == c && kp->Active) 1017 break; 1018 s = kp < &Map[MAPSIZE] ? (*kp->Function)() : insert_char((int)c); 1019 if (!Pushed) 1020 1021 Repeat = NO_ARG; 1022 return s; 1023 } 1024 1025 STATIC STATE 1026 TTYspecial(int c) 1027 { 1028 if (rl_meta_chars && ISMETA(c)) { 1029 return CSdispatch; 1030 } 1031 1032 if (c == rl_erase || c == DEL) { 1033 return bk_del_char(); 1034 } 1035 if (c == rl_kill) { 1036 if (Point != 0) { 1037 Point = 0; 1038 reposition(); 1039 } 1040 Repeat = NO_ARG; 1041 return kill_line(); 1042 } 1043 if (c == rl_eof && Point == 0 && End == 0) { 1044 return CSeof; 1045 } 1046 1047 if (c == rl_intr) { 1048 Signal = SIGINT; 1049 return CSsignal; 1050 } 1051 if (c == rl_quit) { 1052 Signal = SIGQUIT; 1053 return CSsignal; 1054 } 1055 #if defined(DO_SIGTSTP) 1056 if (c == rl_susp) { 1057 Signal = SIGTSTP; 1058 return CSsignal; 1059 } 1060 #endif /* defined(DO_SIGTSTP) */ 1061 1062 return CSdispatch; 1063 } 1064 1065 STATIC CHAR * 1066 editinput() 1067 { 1068 int c; 1069 #if defined(INCLUDE_AUTOCOMPLETE) 1070 extern int diag_user_var_unit; 1071 #endif 1072 1073 Repeat = NO_ARG; 1074 OldPoint = Point = Mark = End = 0; 1075 Line[0] = '\0'; 1076 /* This is a formality to keep consistent with the asynchronous char 1077 process. 1078 Need to track if the previous character was EOL so that asynchronous 1079 support knows when to apply the three lines above. 1080 */ 1081 1082 Signal = -1; 1083 while ((c = TTYget()) != EOF) { 1084 #if defined(INCLUDE_AUTOCOMPLETE) 1085 if (c == TAB) { 1086 Input = (STRING)autocomplete_print(diag_user_var_unit, (char*)Line, (char*)Prompt); 1087 TTYflush(); 1088 continue; 1089 } 1090 #endif 1091 switch (TTYspecial(c)) { 1092 case CSdone: 1093 return Line; 1094 case CSeof: 1095 return NULL; 1096 case CSsignal: 1097 return (CHAR *)""; 1098 case CSmove: 1099 reposition(); 1100 break; 1101 case CSdispatch: 1102 switch (emacs(c)) { 1103 case CSdone: 1104 return Line; 1105 case CSeof: 1106 return NULL; 1107 case CSsignal: 1108 return (CHAR *)""; 1109 case CSmove: 1110 reposition(); 1111 break; 1112 case CSdispatch: 1113 case CSstay: 1114 break; 1115 } 1116 break; 1117 case CSstay: 1118 break; 1119 } 1120 } 1121 return NULL; 1122 } 1123 1124 STATIC void 1125 hist_add(CHAR *p) 1126 { 1127 int i; 1128 1129 if ((p = (CHAR *)sal_strdup((char *)p)) == NULL) { 1130 return; 1131 } 1132 if (H.Size < HIST_SIZE) 1133 H.Lines[H.Size++] = p; 1134 else { 1135 DISPOSE(H.Lines[0]); 1136 for (i = 0; i < HIST_SIZE - 1; i++) 1137 H.Lines[i] = H.Lines[i + 1]; 1138 H.Lines[i] = p; 1139 } 1140 H.Pos = H.Size - 1; 1141 } 1142 1143 STATIC char * 1144 read_redirected() 1145 { 1146 int size; 1147 char *p; 1148 char *line; 1149 char *end; 1150 1151 size = MEM_INC; 1152 line = NEW(char, size); 1153 end = line + size; 1154 1155 for (p = line; ; p++) { 1156 if (p == end) { 1157 p = NEW(char, size + MEM_INC); 1158 memcpy(p, line, size); 1159 DISPOSE(line); 1160 line = p; 1161 p = line + size; 1162 size += MEM_INC; 1163 end = line + size; 1164 } 1165 if (sal_console_read(p, 1) <= 0) { 1166 /* Ignore "incomplete" lines at EOF, just like we do for a tty. */ 1167 DISPOSE(line); 1168 return NULL; 1169 } 1170 1171 if (*p == '\n') 1172 break; 1173 } 1174 *p = '\0'; 1175 return line; 1176 } 1177 1178 /* 1179 ** For compatibility with FSF readline. 1180 */ 1181 /* ARGSUSED0 */ 1182 void 1183 rl_reset_terminal(char *p) 1184 { 1185 } 1186 1187 int 1188 rl_insert(int count,int c) 1189 { 1190 if (count > 0) { 1191 Repeat = count; 1192 (void)insert_char(c); 1193 (void)redisplay_no_nl(); 1194 } 1195 return 0; 1196 } 1197 1198 int (*rl_event_hook)(); 1199 1200 int 1201 rl_key_action(int c, char flag) 1202 { 1203 KEYMAP *kp; 1204 int size; 1205 1206 if (ISMETA(c)) { 1207 kp = MetaMap; 1208 size = METAMAPSIZE; 1209 } 1210 else { 1211 kp = Map; 1212 size = MAPSIZE; 1213 } 1214 for ( ; --size >= 0; kp++) 1215 if (kp->Key == c) { 1216 kp->Active = c ? 1 : 0; 1217 return 1; 1218 } 1219 return -1; 1220 } 1221 1222 int 1223 readchar(CONST char *prompt) 1224 { 1225 char c; 1226 #ifdef UNIX 1227 int gdb = 0; 1228 1229 if (getenv("GDB") != NULL && getenv("DCON") == NULL) { 1230 gdb = 1; 1231 } 1232 #endif 1233 1234 if (Screen == NULL) { 1235 ScreenSize = SCREEN_INC; 1236 Screen = NEW(char, ScreenSize); 1237 } 1238 1239 if (sal_console_info_get(NULL) < 0) { 1240 TTYflush(); 1241 return EOF; 1242 } 1243 1244 #ifdef UNIX 1245 if (gdb) { 1246 char *t; 1247 char p; 1248 printf("%s", prompt); 1249 fflush(stdout); 1250 t = read_redirected(); 1251 if(t == NULL) { 1252 return EOF; 1253 } else { 1254 p = *(t+0); 1255 sal_free(t); 1256 return p; 1257 } 1258 } 1259 #endif 1260 1261 TTYinfo(); 1262 rl_ttyset(0); 1263 Prompt = prompt ? prompt : (char *)NIL; 1264 TTYputs((STRING)Prompt); 1265 c = TTYget(); 1266 if (c == rl_intr) 1267 Signal = SIGINT; 1268 else if (c == rl_quit) 1269 Signal = SIGQUIT; 1270 #if defined(DO_SIGTSTP) 1271 else if (c == rl_susp) 1272 Signal = SIGTSTP; 1273 #endif /* defined(DO_SIGTSTP) */ 1274 rl_ttyset(1); 1275 1276 #if defined(USE_POSIX_SIGNALS) 1277 if (Signal > 0) { 1278 int s = Signal; 1279 Signal = 0; 1280 (void)kill(getpid(), s); 1281 } 1282 #endif 1283 return c; 1284 } 1285 1286 char * 1287 readline(CONST char *prompt) 1288 { 1289 CHAR *line; 1290 #ifdef UNIX 1291 int gdb = 0; 1292 1293 if (getenv("GDB") != NULL && getenv("DCON") == NULL) { 1294 gdb = 1; 1295 } 1296 #endif 1297 1298 if (Screen == NULL) { 1299 ScreenSize = SCREEN_INC; 1300 Screen = NEW(char, ScreenSize); 1301 } 1302 1303 /* 1304 * If input is not a TTY, just do a read. 1305 * Also just do a read if TTY data is pending. 1306 */ 1307 if (sal_console_info_get(NULL) < 0) { 1308 TTYflush(); 1309 return read_redirected(); 1310 } 1311 1312 #ifdef UNIX 1313 if (gdb) { 1314 printf("%s", prompt); 1315 fflush(stdout); 1316 return read_redirected(); 1317 } 1318 #endif 1319 1320 if (Line == NULL) { 1321 Length = MEM_INC; 1322 if ((Line = NEW(CHAR, Length)) == NULL) { 1323 return NULL; 1324 } 1325 } 1326 1327 TTYinfo(); 1328 rl_ttyset(0); 1329 hist_add(NIL); 1330 Prompt = prompt ? prompt : (char *)NIL; 1331 TTYputs((STRING)Prompt); 1332 CursorPos = strlen(Prompt); 1333 if ((line = editinput()) != NULL) { 1334 line = (CHAR *)sal_strdup((char *)line); 1335 TTYputs((STRING)NEWLINE); 1336 TTYflush(); 1337 } 1338 rl_ttyset(1); 1339 1340 DISPOSE(H.Lines[--H.Size]); 1341 #if defined(USE_POSIX_SIGNALS) 1342 if (Signal > 0) { 1343 int s = Signal; 1344 errno = EINTR; 1345 Signal = 0; 1346 (void)kill(getpid(), s); 1347 if (line) { 1348 DISPOSE(line); 1349 line = NULL; 1350 } 1351 } else { 1352 errno = 0; 1353 } 1354 #endif 1355 return (char *)line; 1356 } 1357 1358 void 1359 add_history(char *p) 1360 { 1361 if (p == NULL || *p == '\0') { 1362 return; 1363 } 1364 1365 #if defined(UNIQUE_HISTORY) 1366 if (H.Size && strcmp(p, (char *)H.Lines[H.Size - 1]) == 0) { 1367 return; 1368 } 1369 #endif /* defined(UNIQUE_HISTORY) */ 1370 hist_add((CHAR *)p); 1371 } 1372 1373 void 1374 list_history(int count) 1375 { 1376 int h; 1377 if ((h = H.Size - count) < 0) 1378 h = 0; 1379 while (h < H.Size) { 1380 TTYputs((STRING)" "); 1381 TTYputs((STRING)H.Lines[h++]); 1382 TTYputs((STRING)NEWLINE); 1383 TTYflush(); 1384 } 1385 } 1386 1387 1388 1389 STATIC STATE 1390 beg_line() 1391 { 1392 if (Point) { 1393 Point = 0; 1394 return CSmove; 1395 } 1396 return CSstay; 1397 } 1398 1399 STATIC STATE 1400 del_char() 1401 { 1402 return delete_string(Repeat == NO_ARG ? 1 : Repeat); 1403 } 1404 1405 STATIC STATE 1406 end_line() 1407 { 1408 if (Point != End) { 1409 Point = End; 1410 return CSmove; 1411 } 1412 return CSstay; 1413 } 1414 1415 /* 1416 ** Return allocated copy of word under cursor, moving cursor after the 1417 ** word. 1418 */ 1419 STATIC CHAR * 1420 find_word() 1421 { 1422 static char SEPS[] = "\"#;&|^$=`'{}()<>\n\t "; 1423 CHAR *p; 1424 CHAR *new; 1425 SIZE_T len; 1426 1427 /* Move forward to end of word. */ 1428 p = &Line[Point]; 1429 for ( ; Point < End && strchr(SEPS, (char)*p) == NULL; Point++, p++) 1430 right(CSstay); 1431 1432 /* Back up to beginning of word. */ 1433 for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--) 1434 continue; 1435 len = Point - (p - Line) + 1; 1436 if ((new = NEW(CHAR, len)) == NULL) 1437 return NULL; 1438 COPYFROMTO(new, p, len); 1439 new[len - 1] = '\0'; 1440 return new; 1441 } 1442 1443 STATIC STATE 1444 c_complete() 1445 { 1446 CHAR *p; 1447 CHAR *word; 1448 int unique; 1449 1450 word = find_word(); 1451 p = (CHAR *)(*rl_complete)((char *)word, &unique); 1452 if (word) 1453 DISPOSE(word); 1454 if (p) { 1455 if (*p) 1456 (void)insert_string(p); 1457 if (!unique) 1458 (void)ring_bell(); 1459 DISPOSE(p); 1460 return redisplay_no_nl(); 1461 } 1462 return ring_bell(); 1463 } 1464 1465 void rl_input_state(rl_input_state_t *state) 1466 { 1467 state->line = Line; 1468 state->point = Point; 1469 } 1470 1471 STATIC STATE 1472 c_possible() 1473 { 1474 CHAR **av, ***pav = &av; 1475 CHAR *word; 1476 int ac; 1477 1478 word = find_word(); 1479 ac = (*rl_list_possib)((char *)word, (char ***)pav); 1480 if (word) 1481 DISPOSE(word); 1482 if (ac) { 1483 columns(ac, av); 1484 while (--ac >= 0) 1485 DISPOSE(av[ac]); 1486 DISPOSE(av); 1487 return redisplay_no_nl(); 1488 } 1489 return ring_bell(); 1490 } 1491 1492 STATIC STATE 1493 accept_line() 1494 { 1495 Line[End] = '\0'; 1496 return CSdone; 1497 } 1498 1499 STATIC STATE 1500 transpose() 1501 { 1502 CHAR c; 1503 1504 if (Point) { 1505 if (Point == End) 1506 left(CSmove); 1507 c = Line[Point - 1]; 1508 left(CSstay); 1509 Line[Point - 1] = Line[Point]; 1510 TTYshow(Line[Point - 1]); 1511 Line[Point++] = c; 1512 TTYshow(c); 1513 } 1514 return CSstay; 1515 } 1516 1517 STATIC STATE 1518 quote() 1519 { 1520 int c; 1521 1522 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c); 1523 } 1524 1525 STATIC STATE 1526 wipe() 1527 { 1528 int i; 1529 1530 if (Mark > End) 1531 return ring_bell(); 1532 1533 if (Point > Mark) { 1534 i = Point; 1535 Point = Mark; 1536 Mark = i; 1537 reposition(); 1538 } 1539 1540 return delete_string(Mark - Point); 1541 } 1542 1543 STATIC STATE 1544 mk_set() 1545 { 1546 Mark = Point; 1547 return CSstay; 1548 } 1549 1550 STATIC STATE 1551 exchange() 1552 { 1553 int c; 1554 1555 if ((c = TTYget()) != CTL('X')) 1556 return c == EOF ? CSeof : ring_bell(); 1557 1558 if ((c = Mark) <= End) { 1559 Mark = Point; 1560 Point = c; 1561 return CSmove; 1562 } 1563 return CSstay; 1564 } 1565 1566 STATIC STATE 1567 yank() 1568 { 1569 if (Yanked && *Yanked) 1570 return insert_string(Yanked); 1571 return CSstay; 1572 } 1573 1574 STATIC STATE 1575 copy_region() 1576 { 1577 if (Mark > End) 1578 return ring_bell(); 1579 1580 if (Point > Mark) 1581 save_yank(Mark, Point - Mark); 1582 else 1583 save_yank(Point, Mark - Point); 1584 1585 return CSstay; 1586 } 1587 1588 STATIC STATE 1589 move_to_char() 1590 { 1591 int c; 1592 int i; 1593 CHAR *p; 1594 1595 if ((c = TTYget()) == EOF) 1596 return CSeof; 1597 for (i = Point + 1, p = &Line[i]; i < End; i++, p++) 1598 if (*p == c) { 1599 Point = i; 1600 return CSmove; 1601 } 1602 return CSstay; 1603 } 1604 1605 STATIC STATE 1606 fd_word() 1607 { 1608 return do_forward(CSmove); 1609 } 1610 1611 STATIC STATE 1612 fd_kill_word() 1613 { 1614 int i; 1615 1616 (void)do_forward(CSstay); 1617 if (OldPoint != Point) { 1618 i = Point - OldPoint; 1619 Point = OldPoint; 1620 return delete_string(i); 1621 } 1622 return CSstay; 1623 } 1624 1625 STATIC STATE 1626 bk_word() 1627 { 1628 int i; 1629 CHAR *p; 1630 1631 i = 0; 1632 do { 1633 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--) 1634 left(CSmove); 1635 1636 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--) 1637 left(CSmove); 1638 1639 if (Point == 0) 1640 break; 1641 } while (++i < Repeat); 1642 1643 return CSstay; 1644 } 1645 1646 STATIC STATE 1647 bk_kill_word() 1648 { 1649 (void)bk_word(); 1650 if (OldPoint != Point) 1651 return delete_string(OldPoint - Point); 1652 return CSstay; 1653 } 1654 1655 STATIC int 1656 argify(CHAR *line, CHAR ***avp) 1657 { 1658 CHAR *c; 1659 CHAR **p; 1660 CHAR **new; 1661 int ac; 1662 int i; 1663 1664 i = MEM_INC; 1665 if ((*avp = p = NEW(CHAR*, i))== NULL) 1666 return 0; 1667 1668 for (c = line; isspace(*c); c++) 1669 continue; 1670 if (*c == '\n' || *c == '\0') 1671 return 0; 1672 1673 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { 1674 if (isspace(*c)) { 1675 *c++ = '\0'; 1676 if (*c && *c != '\n') { 1677 if (ac + 1 == i) { 1678 new = NEW(CHAR*, i + MEM_INC); 1679 if (new == NULL) { 1680 p[ac] = NULL; 1681 return ac; 1682 } 1683 COPYFROMTO(new, p, i * sizeof(CHAR*)); 1684 i += MEM_INC; 1685 DISPOSE(p); 1686 *avp = p = new; 1687 } 1688 p[ac++] = c; 1689 } 1690 } 1691 else 1692 c++; 1693 } 1694 *c = '\0'; 1695 p[ac] = NULL; 1696 return ac; 1697 } 1698 1699 STATIC STATE 1700 last_argument() 1701 { 1702 CHAR **av; 1703 CHAR *p; 1704 STATE s; 1705 int ac; 1706 1707 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL) 1708 return ring_bell(); 1709 1710 if ((p = (CHAR *)sal_strdup((char *)p)) == NULL) 1711 return CSstay; 1712 ac = argify(p, &av); 1713 1714 if (Repeat != NO_ARG) 1715 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); 1716 else 1717 s = ac ? insert_string(av[ac - 1]) : CSstay; 1718 1719 if (av) 1720 DISPOSE(av); 1721 DISPOSE(p); 1722 return s; 1723 } 1724 1725 STATIC KEYMAP Map[MAPSIZE] = { 1726 { CTL('@'), 1, mk_set }, 1727 { CTL('A'), 1, beg_line }, 1728 { CTL('B'), 1, bk_char }, 1729 { CTL('D'), 1, del_char }, 1730 { CTL('E'), 1, end_line }, 1731 { CTL('F'), 1, fd_char }, 1732 { CTL('G'), 1, ring_bell }, 1733 { CTL('H'), 1, bk_del_char }, 1734 { CTL('I'), 1, c_complete }, 1735 { CTL('J'), 1, accept_line }, 1736 { CTL('K'), 1, kill_line }, 1737 { CTL('L'), 1, redisplay }, 1738 { CTL('M'), 1, accept_line }, 1739 { CTL('N'), 1, h_next }, 1740 { CTL('O'), 1, ring_bell }, 1741 { CTL('P'), 1, h_prev }, 1742 { CTL('Q'), 1, ring_bell }, 1743 #if defined(SEARCH_HISTORY) 1744 { CTL('R'), 1, h_search }, 1745 #endif 1746 { CTL('S'), 1, ring_bell }, 1747 { CTL('T'), 1, transpose }, 1748 { CTL('U'), 1, ring_bell }, 1749 { CTL('V'), 1, quote }, 1750 { CTL('W'), 1, wipe }, 1751 { CTL('X'), 1, exchange }, 1752 { CTL('Y'), 1, yank }, 1753 { CTL('Z'), 1, ring_bell }, 1754 { CTL('['), 1, meta }, 1755 { CTL(']'), 1, move_to_char }, 1756 { CTL('^'), 1, ring_bell }, 1757 { CTL('_'), 1, ring_bell }, 1758 }; 1759 1760 STATIC KEYMAP MetaMap[METAMAPSIZE]= { 1761 { CTL('H'), 1, bk_kill_word }, 1762 { CTL('['), 1, c_possible }, 1763 { DEL, 1, bk_kill_word }, 1764 { ' ', 1, mk_set }, 1765 { '.', 1, last_argument }, 1766 { '<', 1, h_first }, 1767 { '>', 1, h_last }, 1768 { '?', 1, c_possible }, 1769 { 'b', 1, bk_word }, 1770 { 'd', 1, fd_kill_word }, 1771 { 'f', 1, fd_word }, 1772 { 'l', 1, case_down_word }, 1773 { 'm', 1, toggle_meta_mode}, 1774 { 'n', 1, h_search_next }, 1775 { 'p', 1, h_search_prev }, 1776 { 'u', 1, case_up_word }, 1777 { 'y', 1, yank }, 1778 { 'w', 1, copy_region }, 1779 }; 1780 1781 /* Asynchronous event support */ 1782 void 1783 _rl_editline_input_start(void) 1784 { 1785 1786 Repeat = NO_ARG; 1787 OldPoint = Point = Mark = End = 0; 1788 Line[0] = '\0'; 1789 1790 Signal = -1; 1791 } 1792 1793 /* 1794 * Description: 1795 * process individual characters and determines if history should be 1796 * be presented to the user. 1797 */ 1798 int 1799 _rl_editline_input_process(int c, CHAR **linep) 1800 { 1801 int eol = FALSE; 1802 1803 switch (TTYspecial(c)) { 1804 case CSdone: 1805 *linep = Line; 1806 eol = TRUE; 1807 break; 1808 case CSeof: 1809 if (gCALLBACK_EOF_HANDLER) { 1810 gCALLBACK_EOF_HANDLER(gCALLBACK_EOF_HANDLER_CTX); 1811 } 1812 break; 1813 case CSsignal: 1814 *linep = (CHAR *)""; 1815 eol = TRUE; 1816 break; 1817 case CSmove: 1818 reposition(); 1819 break; 1820 case CSdispatch: 1821 switch (emacs(c)) { 1822 case CSdone: 1823 *linep = Line; 1824 eol = TRUE; 1825 break; 1826 case CSeof: 1827 if (gCALLBACK_EOF_HANDLER) { 1828 gCALLBACK_EOF_HANDLER(gCALLBACK_EOF_HANDLER_CTX); 1829 } 1830 *linep = NULL; 1831 eol = TRUE; 1832 break; 1833 case CSsignal: 1834 *linep = (CHAR *)""; 1835 eol = TRUE; 1836 break; 1837 case CSmove: 1838 reposition(); 1839 break; 1840 case CSdispatch: 1841 case CSstay: 1842 break; 1843 } 1844 break; 1845 case CSstay: 1846 break; 1847 } 1848 1849 return eol; 1850 } 1851 1852 /* 1853 Set new prompt. 1854 */ 1855 void rl_prompt_set(CONST char *prompt) 1856 { 1857 int changed = 0; 1858 if (!Prompt || !prompt) { 1859 changed = 1; 1860 } else if (Prompt && prompt && sal_strcmp(Prompt, prompt)) { 1861 changed = 1; 1862 } 1863 1864 Prompt = prompt ? prompt : (char *)NIL; 1865 if (changed || (CursorPos == 0)) { 1866 /* CursorPos == 0 means that nothing has been displayed as a prompt.*/ 1867 if (CursorPos != 0) { 1868 /* We're changing prompts in the middle of a line. 1869 put a new line to continue. */ 1870 TTYputs((STRING)NEWLINE); 1871 } 1872 TTYputs((STRING)Prompt); 1873 TTYflush(); 1874 CursorPos = strlen((char *)Prompt); 1875 } 1876 } 1877 1878 /* 1879 * Initialize asynchronous editline support. 1880 * 1881 * Must call _rl_done when finished. 1882 */ 1883 int 1884 _rl_initialize(CONST char *prompt) 1885 { 1886 if (Screen == NULL) { 1887 ScreenSize = SCREEN_INC; 1888 if(!(Screen = NEW(char, ScreenSize))) { 1889 return 0; 1890 } 1891 } 1892 1893 if (Line == NULL) { 1894 Length = MEM_INC; 1895 if ((Line = NEW(CHAR, Length)) == NULL) { 1896 return 0; 1897 } 1898 } 1899 1900 TTYinfo(); 1901 rl_ttyset(0); 1902 hist_add(NIL); 1903 rl_prompt_set(prompt); 1904 1905 return 1; 1906 } 1907 1908 void 1909 _rl_done(void) 1910 { 1911 rl_ttyset(1); 1912 1913 #if defined(USE_POSIX_SIGNALS) 1914 if (Signal > 0) { 1915 int s = Signal; 1916 errno = EINTR; 1917 Signal = 0; 1918 (void)kill(getpid(), s); 1919 } else { 1920 errno = 0; 1921 } 1922 #endif 1923 } 1924 1925 /** 1926 Read a single character and post end-of-line handler. 1927 1928 Notes: 1929 see rl_callback_handler_install to register the end-of-line handler. 1930 */ 1931 void rl_callback_read_char(CONST char *prompt) 1932 { 1933 /* Start with yes previous character processed was eol so that 1934 initialization will work. */ 1935 static int PrevEol = TRUE; 1936 1937 /* read a char from input */ 1938 CHAR *line = NULL; 1939 int c = 0; 1940 1941 /* 1942 When we transition from synchronous to asynchronous H.Size == H.Pos 1943 that is how we tell we are at a new line. We may need to change 1944 the prompt and cleanout output. 1945 1946 The PrevEol state is strictly internal because PrevEol is only 1947 set to TRUE when eol handler is called a new line has been read. 1948 */ 1949 if ((H.Size == H.Pos) || (PrevEol == TRUE)) { 1950 _rl_initialize(prompt); 1951 _rl_editline_input_start(); 1952 PrevEol = FALSE; /* Start of a process a new line. */ 1953 } 1954 c = TTYget(); 1955 1956 /* if the line is complete, execute eol handler */ 1957 if (_rl_editline_input_process(c, &line)) { 1958 PrevEol = TRUE; 1959 /* Once a new line has been found pos to eol handler. 1960 We can call the handler anywhere before hist_add but after 1961 NEWLINE is good for printf debugging from eol handler. */ 1962 TTYputs((STRING)NEWLINE); 1963 TTYflush(); 1964 DISPOSE(H.Lines[--H.Size]); 1965 gCALLBACK_EOL_HANDLER((char *)line, gCALLBACK_EOL_HANDLER_CTX); 1966 /* We need to push the prompt after we're done with the end of line. 1967 Because the end of line handler might process TCL script causing 1968 output which needs to occur before the prompt. 1969 1970 Note that EOL_HANDLER might call into another shell changing the 1971 prompt. When returnning the following needs to occur verses just 1972 flushing Prompt. 1973 */ 1974 rl_prompt_set(prompt); 1975 } 1976 1977 /* flush is needed because at this point input was processed and 1978 pushed out. This could have been just the input character or 1979 the history information processed i.e. up down arrows. */ 1980 TTYflush(); 1981 1982 #if defined(USE_POSIX_SIGNALS) 1983 if (Signal > 0) { 1984 int s = Signal; 1985 errno = EINTR; 1986 Signal = 0; 1987 (void)kill(getpid(), s); 1988 if (line) { 1989 DISPOSE(line); 1990 line = NULL; 1991 } 1992 } else { 1993 errno = 0; 1994 } 1995 #endif 1996 } 1997 1998 /** 1999 Install an end-of-line handler. 2000 2001 The end-of-line handler is only called when a complete line is parsed. 2002 Users must call rl_callback_handler_remove when done. 2003 */ 2004 void rl_callback_handler_install(CONST char *prompt, 2005 rl_vcpfunc_t eol_handler, void *eolCtx, 2006 rf_vcpfunc_t eof_handler, void *eofCtx) 2007 { 2008 if (_rl_initialize(prompt)) { 2009 /* save handler */ 2010 gCALLBACK_EOL_HANDLER = eol_handler; 2011 gCALLBACK_EOL_HANDLER_CTX = eolCtx; 2012 2013 gCALLBACK_EOF_HANDLER = eof_handler; 2014 gCALLBACK_EOF_HANDLER_CTX = eofCtx; 2015 2016 /* set terminal and init library */ 2017 _rl_editline_input_start(); 2018 } 2019 } 2020 2021 /** 2022 Called when asynchronous editline is done. 2023 */ 2024 void rl_callback_handler_remove(void **eolCtx, void **eofCtx) 2025 { 2026 if (eolCtx) { 2027 (*eolCtx) = gCALLBACK_EOL_HANDLER_CTX; 2028 } 2029 if (eofCtx) { 2030 (*eofCtx) = gCALLBACK_EOF_HANDLER_CTX; 2031 } 2032 _rl_done(); 2033 /* remove handler */ 2034 gCALLBACK_EOL_HANDLER = NULL; 2035 gCALLBACK_EOL_HANDLER_CTX = NULL; 2036 2037 gCALLBACK_EOF_HANDLER = NULL; 2038 gCALLBACK_EOF_HANDLER_CTX = NULL; 2039 } 2040 2041 #else /* INCLUDE_EDITLINE */ 2042 int _editline_editline_not_empty; 2043 #endif /* INCLUDE_EDITLINE */