/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/editline/editline.c
C | 1368 lines | 1112 code | 158 blank | 98 comment | 272 complexity | 9a92f794d6fc8318bee250795bfb0b05 MD5 | raw file
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * 3 * ***** BEGIN LICENSE BLOCK ***** 4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 5 * 6 * The contents of this file are subject to the Mozilla Public License Version 7 * 1.1 (the "License"); you may not use this file except in compliance with 8 * the License. You may obtain a copy of the License at 9 * http://www.mozilla.org/MPL/ 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 * 16 * The Original Code is Mozilla Communicator client code, released 17 * March 31, 1998. 18 * 19 * The Initial Developer of the Original Code is 20 * Simmule Turner and Rich Salz. 21 * Portions created by the Initial Developer are Copyright (C) 1998 22 * the Initial Developer. All Rights Reserved. 23 * 24 * Contributor(s): 25 * 26 * Alternatively, the contents of this file may be used under the terms of 27 * either the GNU General Public License Version 2 or later (the "GPL"), or 28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 29 * in which case the provisions of the GPL or the LGPL are applicable instead 30 * of those above. If you wish to allow use of your version of this file only 31 * under the terms of either the GPL or the LGPL, and not to allow others to 32 * use your version of this file under the terms of the MPL, indicate your 33 * decision by deleting the provisions above and replace them with the notice 34 * and other provisions required by the GPL or the LGPL. If you do not delete 35 * the provisions above, a recipient may use your version of this file under 36 * the terms of any one of the MPL, the GPL or the LGPL. 37 * 38 * ***** END LICENSE BLOCK ***** */ 39 40/* 41 * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved. 42 * 43 * This software is not subject to any license of the American Telephone 44 * and Telegraph Company or of the Regents of the University of California. 45 * 46 * Permission is granted to anyone to use this software for any purpose on 47 * any computer system, and to alter it and redistribute it freely, subject 48 * to the following restrictions: 49 * 1. The authors are not responsible for the consequences of use of this 50 * software, no matter how awful, even if they arise from flaws in it. 51 * 2. The origin of this software must not be misrepresented, either by 52 * explicit claim or by omission. Since few users ever read sources, 53 * credits must appear in the documentation. 54 * 3. Altered versions must be plainly marked as such, and must not be 55 * misrepresented as being the original software. Since few users 56 * ever read sources, credits must appear in the documentation. 57 * 4. This notice may not be removed or altered. 58 */ 59 60 61/* 62** Main editing routines for editline library. 63*/ 64#include "editline.h" 65#include <signal.h> 66#include <ctype.h> 67#include <unistd.h> 68 69/* 70** Manifest constants. 71*/ 72#define SCREEN_WIDTH 80 73#define SCREEN_ROWS 24 74#define NO_ARG (-1) 75#define DEL 127 76#define CTL(x) ((x) & 0x1F) 77#define ISCTL(x) ((x) && (x) < ' ') 78#define UNCTL(x) ((x) + 64) 79#define META(x) ((x) | 0x80) 80#define ISMETA(x) ((x) & 0x80) 81#define UNMETA(x) ((x) & 0x7F) 82#if !defined(HIST_SIZE) 83#define HIST_SIZE 20 84#endif /* !defined(HIST_SIZE) */ 85 86/* 87** Command status codes. 88*/ 89typedef enum _STATUS { 90 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal 91} STATUS; 92 93/* 94** The type of case-changing to perform. 95*/ 96typedef enum _CASE { 97 TOupper, TOlower 98} CASE; 99 100/* 101** Key to command mapping. 102*/ 103typedef struct _KEYMAP { 104 CHAR Key; 105 STATUS (*Function)(); 106} KEYMAP; 107 108/* 109** Command history structure. 110*/ 111typedef struct _HISTORY { 112 int Size; 113 int Pos; 114 CHAR *Lines[HIST_SIZE]; 115} HISTORY; 116 117/* 118** Globals. 119*/ 120int rl_eof; 121int rl_erase; 122int rl_intr; 123int rl_kill; 124int rl_quit; 125 126STATIC CHAR NIL[] = ""; 127STATIC CONST CHAR *Input = NIL; 128STATIC CHAR *Line; 129STATIC CONST char *Prompt; 130STATIC CHAR *Yanked; 131STATIC char *Screen; 132STATIC char NEWLINE[]= CRLF; 133STATIC HISTORY H; 134STATIC int Repeat; 135STATIC int End; 136STATIC int Mark; 137STATIC int OldPoint; 138STATIC int Point; 139STATIC int PushBack; 140STATIC int Pushed; 141STATIC int Signal; 142FORWARD KEYMAP Map[32]; 143FORWARD KEYMAP MetaMap[16]; 144STATIC SIZE_T Length; 145STATIC SIZE_T ScreenCount; 146STATIC SIZE_T ScreenSize; 147STATIC char *backspace; 148STATIC int TTYwidth; 149STATIC int TTYrows; 150 151/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */ 152int rl_meta_chars = 0; 153 154/* 155** Declarations. 156*/ 157STATIC CHAR *editinput(); 158#if defined(USE_TERMCAP) 159#include <stdlib.h> 160#include <curses.h> 161#include <term.h> 162#endif /* defined(USE_TERMCAP) */ 163 164/* 165** TTY input/output functions. 166*/ 167 168STATIC void 169TTYflush() 170{ 171 if (ScreenCount) { 172 (void)write(1, Screen, ScreenCount); 173 ScreenCount = 0; 174 } 175} 176 177STATIC void 178TTYput(c) 179 CHAR c; 180{ 181 Screen[ScreenCount] = c; 182 if (++ScreenCount >= ScreenSize - 1) { 183 ScreenSize += SCREEN_INC; 184 RENEW(Screen, char, ScreenSize); 185 } 186} 187 188STATIC void 189TTYputs(p) 190 CHAR *p; 191{ 192 while (*p) 193 TTYput(*p++); 194} 195 196STATIC void 197TTYshow(c) 198 CHAR c; 199{ 200 if (c == DEL) { 201 TTYput('^'); 202 TTYput('?'); 203 } 204 else if (ISCTL(c)) { 205 TTYput('^'); 206 TTYput(UNCTL(c)); 207 } 208 else if (rl_meta_chars && ISMETA(c)) { 209 TTYput('M'); 210 TTYput('-'); 211 TTYput(UNMETA(c)); 212 } 213 else 214 TTYput(c); 215} 216 217STATIC void 218TTYstring(p) 219 CHAR *p; 220{ 221 while (*p) 222 TTYshow(*p++); 223} 224 225STATIC unsigned int 226TTYget() 227{ 228 CHAR c; 229 230 TTYflush(); 231 if (Pushed) { 232 Pushed = 0; 233 return PushBack; 234 } 235 if (*Input) 236 return *Input++; 237 return read(0, &c, (SIZE_T)1) == 1 ? c : EOF; 238} 239 240#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b')) 241 242STATIC void 243TTYbackn(n) 244 int n; 245{ 246 while (--n >= 0) 247 TTYback(); 248} 249 250STATIC void 251TTYinfo() 252{ 253 static int init; 254#if defined(USE_TERMCAP) 255 char *term; 256 char buff[2048]; 257 char *bp, *p; 258#endif /* defined(USE_TERMCAP) */ 259#if defined(TIOCGWINSZ) 260 struct winsize W; 261#endif /* defined(TIOCGWINSZ) */ 262 263 if (init) { 264#if defined(TIOCGWINSZ) 265 /* Perhaps we got resized. */ 266 if (ioctl(0, TIOCGWINSZ, &W) >= 0 267 && W.ws_col > 0 && W.ws_row > 0) { 268 TTYwidth = (int)W.ws_col; 269 TTYrows = (int)W.ws_row; 270 } 271#endif /* defined(TIOCGWINSZ) */ 272 return; 273 } 274 init++; 275 276 TTYwidth = TTYrows = 0; 277#if defined(USE_TERMCAP) 278 bp = &buff[0]; 279 if ((term = getenv("TERM")) == NULL) 280 term = "dumb"; 281 if (tgetent(buff, term) < 0) { 282 TTYwidth = SCREEN_WIDTH; 283 TTYrows = SCREEN_ROWS; 284 return; 285 } 286 p = tgetstr("le", &bp); 287 backspace = p ? strdup(p) : NULL; 288 TTYwidth = tgetnum("co"); 289 TTYrows = tgetnum("li"); 290#endif /* defined(USE_TERMCAP) */ 291 292#if defined(TIOCGWINSZ) 293 if (ioctl(0, TIOCGWINSZ, &W) >= 0) { 294 TTYwidth = (int)W.ws_col; 295 TTYrows = (int)W.ws_row; 296 } 297#endif /* defined(TIOCGWINSZ) */ 298 299 if (TTYwidth <= 0 || TTYrows <= 0) { 300 TTYwidth = SCREEN_WIDTH; 301 TTYrows = SCREEN_ROWS; 302 } 303} 304 305 306STATIC void 307reposition() 308{ 309 int i; 310 CHAR *p; 311 312 TTYput('\r'); 313 TTYputs((CONST CHAR *)Prompt); 314 for (i = Point, p = Line; --i >= 0; p++) 315 TTYshow(*p); 316} 317 318STATIC void 319left(Change) 320 STATUS Change; 321{ 322 TTYback(); 323 if (Point) { 324 if (ISCTL(Line[Point - 1])) 325 TTYback(); 326 else if (rl_meta_chars && ISMETA(Line[Point - 1])) { 327 TTYback(); 328 TTYback(); 329 } 330 } 331 if (Change == CSmove) 332 Point--; 333} 334 335STATIC void 336right(Change) 337 STATUS Change; 338{ 339 TTYshow(Line[Point]); 340 if (Change == CSmove) 341 Point++; 342} 343 344STATIC STATUS 345ring_bell() 346{ 347 TTYput('\07'); 348 TTYflush(); 349 return CSstay; 350} 351 352STATIC STATUS 353do_macro(c) 354 unsigned int c; 355{ 356 CHAR name[4]; 357 358 name[0] = '_'; 359 name[1] = c; 360 name[2] = '_'; 361 name[3] = '\0'; 362 363 if ((Input = (CHAR *)getenv((char *)name)) == NULL) { 364 Input = NIL; 365 return ring_bell(); 366 } 367 return CSstay; 368} 369 370STATIC STATUS 371do_forward(move) 372 STATUS move; 373{ 374 int i; 375 CHAR *p; 376 377 i = 0; 378 do { 379 p = &Line[Point]; 380 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++) 381 if (move == CSmove) 382 right(CSstay); 383 384 for (; Point < End && isalnum(*p); Point++, p++) 385 if (move == CSmove) 386 right(CSstay); 387 388 if (Point == End) 389 break; 390 } while (++i < Repeat); 391 392 return CSstay; 393} 394 395STATIC STATUS 396do_case(type) 397 CASE type; 398{ 399 int i; 400 int end; 401 int count; 402 CHAR *p; 403 404 (void)do_forward(CSstay); 405 if (OldPoint != Point) { 406 if ((count = Point - OldPoint) < 0) 407 count = -count; 408 Point = OldPoint; 409 if ((end = Point + count) > End) 410 end = End; 411 for (i = Point, p = &Line[i]; i < end; i++, p++) { 412 if (type == TOupper) { 413 if (islower(*p)) 414 *p = toupper(*p); 415 } 416 else if (isupper(*p)) 417 *p = tolower(*p); 418 right(CSmove); 419 } 420 } 421 return CSstay; 422} 423 424STATIC STATUS 425case_down_word() 426{ 427 return do_case(TOlower); 428} 429 430STATIC STATUS 431case_up_word() 432{ 433 return do_case(TOupper); 434} 435 436STATIC void 437ceol() 438{ 439 int extras; 440 int i; 441 CHAR *p; 442 443 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) { 444 TTYput(' '); 445 if (ISCTL(*p)) { 446 TTYput(' '); 447 extras++; 448 } 449 else if (rl_meta_chars && ISMETA(*p)) { 450 TTYput(' '); 451 TTYput(' '); 452 extras += 2; 453 } 454 } 455 456 for (i += extras; i > Point; i--) 457 TTYback(); 458} 459 460STATIC void 461clear_line() 462{ 463 Point = -strlen(Prompt); 464 TTYput('\r'); 465 ceol(); 466 Point = 0; 467 End = 0; 468 Line[0] = '\0'; 469} 470 471STATIC STATUS 472insert_string(p) 473 CHAR *p; 474{ 475 SIZE_T len; 476 int i; 477 CHAR *new; 478 CHAR *q; 479 480 len = strlen((char *)p); 481 if (End + len >= Length) { 482 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL) 483 return CSstay; 484 if (Length) { 485 COPYFROMTO(new, Line, Length); 486 DISPOSE(Line); 487 } 488 Line = new; 489 Length += len + MEM_INC; 490 } 491 492 for (q = &Line[Point], i = End - Point; --i >= 0; ) 493 q[len + i] = q[i]; 494 COPYFROMTO(&Line[Point], p, len); 495 End += len; 496 Line[End] = '\0'; 497 TTYstring(&Line[Point]); 498 Point += len; 499 500 return Point == End ? CSstay : CSmove; 501} 502 503STATIC STATUS 504redisplay() 505{ 506 TTYputs((CONST CHAR *)NEWLINE); 507 TTYputs((CONST CHAR *)Prompt); 508 TTYstring(Line); 509 return CSmove; 510} 511 512STATIC STATUS 513toggle_meta_mode() 514{ 515 rl_meta_chars = ! rl_meta_chars; 516 return redisplay(); 517} 518 519 520STATIC CHAR * 521next_hist() 522{ 523 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos]; 524} 525 526STATIC CHAR * 527prev_hist() 528{ 529 return H.Pos == 0 ? NULL : H.Lines[--H.Pos]; 530} 531 532STATIC STATUS 533do_insert_hist(p) 534 CHAR *p; 535{ 536 if (p == NULL) 537 return ring_bell(); 538 Point = 0; 539 reposition(); 540 ceol(); 541 End = 0; 542 return insert_string(p); 543} 544 545STATIC STATUS 546do_hist(move) 547 CHAR *(*move)(); 548{ 549 CHAR *p; 550 int i; 551 552 i = 0; 553 do { 554 if ((p = (*move)()) == NULL) 555 return ring_bell(); 556 } while (++i < Repeat); 557 return do_insert_hist(p); 558} 559 560STATIC STATUS 561h_next() 562{ 563 return do_hist(next_hist); 564} 565 566STATIC STATUS 567h_prev() 568{ 569 return do_hist(prev_hist); 570} 571 572STATIC STATUS 573h_first() 574{ 575 return do_insert_hist(H.Lines[H.Pos = 0]); 576} 577 578STATIC STATUS 579h_last() 580{ 581 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]); 582} 583 584/* 585** Return zero if pat appears as a substring in text. 586*/ 587STATIC int 588substrcmp(text, pat, len) 589 char *text; 590 char *pat; 591 int len; 592{ 593 char c; 594 595 if ((c = *pat) == '\0') 596 return *text == '\0'; 597 for ( ; *text; text++) 598 if (*text == c && strncmp(text, pat, len) == 0) 599 return 0; 600 return 1; 601} 602 603STATIC CHAR * 604search_hist(search, move) 605 CHAR *search; 606 CHAR *(*move)(); 607{ 608 static CHAR *old_search; 609 int len; 610 int pos; 611 int (*match)(); 612 char *pat; 613 614 /* Save or get remembered search pattern. */ 615 if (search && *search) { 616 if (old_search) 617 DISPOSE(old_search); 618 old_search = (CHAR *)strdup((char *)search); 619 } 620 else { 621 if (old_search == NULL || *old_search == '\0') 622 return NULL; 623 search = old_search; 624 } 625 626 /* Set up pattern-finder. */ 627 if (*search == '^') { 628 match = strncmp; 629 pat = (char *)(search + 1); 630 } 631 else { 632 match = substrcmp; 633 pat = (char *)search; 634 } 635 len = strlen(pat); 636 637 for (pos = H.Pos; (*move)() != NULL; ) 638 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0) 639 return H.Lines[H.Pos]; 640 H.Pos = pos; 641 return NULL; 642} 643 644STATIC STATUS 645h_search() 646{ 647 static int Searching; 648 CONST char *old_prompt; 649 CHAR *(*move)(); 650 CHAR *p; 651 652 if (Searching) 653 return ring_bell(); 654 Searching = 1; 655 656 clear_line(); 657 old_prompt = Prompt; 658 Prompt = "Search: "; 659 TTYputs((CONST CHAR *)Prompt); 660 move = Repeat == NO_ARG ? prev_hist : next_hist; 661 p = editinput(); 662 Prompt = old_prompt; 663 Searching = 0; 664 TTYputs((CONST CHAR *)Prompt); 665 if (p == NULL && Signal > 0) { 666 Signal = 0; 667 clear_line(); 668 return redisplay(); 669 } 670 p = search_hist(p, move); 671 clear_line(); 672 if (p == NULL) { 673 (void)ring_bell(); 674 return redisplay(); 675 } 676 return do_insert_hist(p); 677} 678 679STATIC STATUS 680fd_char() 681{ 682 int i; 683 684 i = 0; 685 do { 686 if (Point >= End) 687 break; 688 right(CSmove); 689 } while (++i < Repeat); 690 return CSstay; 691} 692 693STATIC void 694save_yank(begin, i) 695 int begin; 696 int i; 697{ 698 if (Yanked) { 699 DISPOSE(Yanked); 700 Yanked = NULL; 701 } 702 703 if (i < 1) 704 return; 705 706 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) { 707 COPYFROMTO(Yanked, &Line[begin], i); 708 Yanked[i] = '\0'; 709 } 710} 711 712STATIC STATUS 713delete_string(count) 714 int count; 715{ 716 int i; 717 CHAR *p; 718 719 if (count <= 0 || End == Point) 720 return ring_bell(); 721 722 if (count == 1 && Point == End - 1) { 723 /* Optimize common case of delete at end of line. */ 724 End--; 725 p = &Line[Point]; 726 i = 1; 727 TTYput(' '); 728 if (ISCTL(*p)) { 729 i = 2; 730 TTYput(' '); 731 } 732 else if (rl_meta_chars && ISMETA(*p)) { 733 i = 3; 734 TTYput(' '); 735 TTYput(' '); 736 } 737 TTYbackn(i); 738 *p = '\0'; 739 return CSmove; 740 } 741 if (Point + count > End && (count = End - Point) <= 0) 742 return CSstay; 743 744 if (count > 1) 745 save_yank(Point, count); 746 747 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++) 748 p[0] = p[count]; 749 ceol(); 750 End -= count; 751 TTYstring(&Line[Point]); 752 return CSmove; 753} 754 755STATIC STATUS 756bk_char() 757{ 758 int i; 759 760 i = 0; 761 do { 762 if (Point == 0) 763 break; 764 left(CSmove); 765 } while (++i < Repeat); 766 767 return CSstay; 768} 769 770STATIC STATUS 771bk_del_char() 772{ 773 int i; 774 775 i = 0; 776 do { 777 if (Point == 0) 778 break; 779 left(CSmove); 780 } while (++i < Repeat); 781 782 return delete_string(i); 783} 784 785STATIC STATUS 786kill_line() 787{ 788 int i; 789 790 if (Repeat != NO_ARG) { 791 if (Repeat < Point) { 792 i = Point; 793 Point = Repeat; 794 reposition(); 795 (void)delete_string(i - Point); 796 } 797 else if (Repeat > Point) { 798 right(CSmove); 799 (void)delete_string(Repeat - Point - 1); 800 } 801 return CSmove; 802 } 803 804 save_yank(Point, End - Point); 805 Line[Point] = '\0'; 806 ceol(); 807 End = Point; 808 return CSstay; 809} 810 811STATIC STATUS 812insert_char(c) 813 int c; 814{ 815 STATUS s; 816 CHAR buff[2]; 817 CHAR *p; 818 CHAR *q; 819 int i; 820 821 if (Repeat == NO_ARG || Repeat < 2) { 822 buff[0] = c; 823 buff[1] = '\0'; 824 return insert_string(buff); 825 } 826 827 if ((p = NEW(CHAR, Repeat + 1)) == NULL) 828 return CSstay; 829 for (i = Repeat, q = p; --i >= 0; ) 830 *q++ = c; 831 *q = '\0'; 832 Repeat = 0; 833 s = insert_string(p); 834 DISPOSE(p); 835 return s; 836} 837 838STATIC STATUS 839meta() 840{ 841 unsigned int c; 842 KEYMAP *kp; 843 844 if ((c = TTYget()) == EOF) 845 return CSeof; 846#if defined(ANSI_ARROWS) 847 /* Also include VT-100 arrows. */ 848 if (c == '[' || c == 'O') 849 switch (c = TTYget()) { 850 default: return ring_bell(); 851 case EOF: return CSeof; 852 case 'A': return h_prev(); 853 case 'B': return h_next(); 854 case 'C': return fd_char(); 855 case 'D': return bk_char(); 856 } 857#endif /* defined(ANSI_ARROWS) */ 858 859 if (isdigit(c)) { 860 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); ) 861 Repeat = Repeat * 10 + c - '0'; 862 Pushed = 1; 863 PushBack = c; 864 return CSstay; 865 } 866 867 if (isupper(c)) 868 return do_macro(c); 869 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++) 870 if (kp->Key == c) 871 return (*kp->Function)(); 872 873 return ring_bell(); 874} 875 876STATIC STATUS 877emacs(c) 878 unsigned int c; 879{ 880 STATUS s; 881 KEYMAP *kp; 882 883 if (rl_meta_chars && ISMETA(c)) { 884 Pushed = 1; 885 PushBack = UNMETA(c); 886 return meta(); 887 } 888 for (kp = Map; kp->Function; kp++) 889 if (kp->Key == c) 890 break; 891 s = kp->Function ? (*kp->Function)() : insert_char((int)c); 892 if (!Pushed) 893 /* No pushback means no repeat count; hacky, but true. */ 894 Repeat = NO_ARG; 895 return s; 896} 897 898STATIC STATUS 899TTYspecial(c) 900 unsigned int c; 901{ 902 if (ISMETA(c)) 903 return CSdispatch; 904 905 if (c == rl_erase || c == DEL) 906 return bk_del_char(); 907 if (c == rl_kill) { 908 if (Point != 0) { 909 Point = 0; 910 reposition(); 911 } 912 Repeat = NO_ARG; 913 return kill_line(); 914 } 915 if (c == rl_eof && Point == 0 && End == 0) 916 return CSeof; 917 if (c == rl_intr) { 918 Signal = SIGINT; 919 return CSsignal; 920 } 921 if (c == rl_quit) { 922 Signal = SIGQUIT; 923 return CSeof; 924 } 925 926 return CSdispatch; 927} 928 929STATIC CHAR * 930editinput() 931{ 932 unsigned int c; 933 934 Repeat = NO_ARG; 935 OldPoint = Point = Mark = End = 0; 936 Line[0] = '\0'; 937 938 Signal = -1; 939 while ((c = TTYget()) != EOF) 940 switch (TTYspecial(c)) { 941 case CSdone: 942 return Line; 943 case CSeof: 944 return NULL; 945 case CSsignal: 946 return (CHAR *)""; 947 case CSmove: 948 reposition(); 949 break; 950 case CSdispatch: 951 switch (emacs(c)) { 952 case CSdone: 953 return Line; 954 case CSeof: 955 return NULL; 956 case CSsignal: 957 return (CHAR *)""; 958 case CSmove: 959 reposition(); 960 break; 961 case CSdispatch: 962 case CSstay: 963 break; 964 } 965 break; 966 case CSstay: 967 break; 968 } 969 return NULL; 970} 971 972STATIC void 973hist_add(p) 974 CHAR *p; 975{ 976 int i; 977 978 if ((p = (CHAR *)strdup((char *)p)) == NULL) 979 return; 980 if (H.Size < HIST_SIZE) 981 H.Lines[H.Size++] = p; 982 else { 983 DISPOSE(H.Lines[0]); 984 for (i = 0; i < HIST_SIZE - 1; i++) 985 H.Lines[i] = H.Lines[i + 1]; 986 H.Lines[i] = p; 987 } 988 H.Pos = H.Size - 1; 989} 990 991/* 992** For compatibility with FSF readline. 993*/ 994/* ARGSUSED0 */ 995void 996rl_reset_terminal(p) 997 char *p; 998{ 999} 1000 1001void 1002rl_initialize() 1003{ 1004} 1005 1006char * 1007readline(prompt) 1008 CONST char *prompt; 1009{ 1010 CHAR *line; 1011 int s; 1012 1013 if (Line == NULL) { 1014 Length = MEM_INC; 1015 if ((Line = NEW(CHAR, Length)) == NULL) 1016 return NULL; 1017 } 1018 1019 TTYinfo(); 1020 rl_ttyset(0); 1021 hist_add(NIL); 1022 ScreenSize = SCREEN_INC; 1023 Screen = NEW(char, ScreenSize); 1024 Prompt = prompt ? prompt : (char *)NIL; 1025 TTYputs((CONST CHAR *)Prompt); 1026 if ((line = editinput()) != NULL) { 1027 line = (CHAR *)strdup((char *)line); 1028 TTYputs((CHAR *)NEWLINE); 1029 TTYflush(); 1030 } 1031 rl_ttyset(1); 1032 DISPOSE(Screen); 1033 DISPOSE(H.Lines[--H.Size]); 1034 if (Signal > 0) { 1035 s = Signal; 1036 Signal = 0; 1037 (void)kill(getpid(), s); 1038 } 1039 return (char *)line; 1040} 1041 1042void 1043add_history(p) 1044 char *p; 1045{ 1046 if (p == NULL || *p == '\0') 1047 return; 1048 1049#if defined(UNIQUE_HISTORY) 1050 if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0) 1051 return; 1052#endif /* defined(UNIQUE_HISTORY) */ 1053 hist_add((CHAR *)p); 1054} 1055 1056 1057STATIC STATUS 1058beg_line() 1059{ 1060 if (Point) { 1061 Point = 0; 1062 return CSmove; 1063 } 1064 return CSstay; 1065} 1066 1067STATIC STATUS 1068del_char() 1069{ 1070 return delete_string(Repeat == NO_ARG ? 1 : Repeat); 1071} 1072 1073STATIC STATUS 1074end_line() 1075{ 1076 if (Point != End) { 1077 Point = End; 1078 return CSmove; 1079 } 1080 return CSstay; 1081} 1082 1083STATIC STATUS 1084accept_line() 1085{ 1086 Line[End] = '\0'; 1087 return CSdone; 1088} 1089 1090STATIC STATUS 1091transpose() 1092{ 1093 CHAR c; 1094 1095 if (Point) { 1096 if (Point == End) 1097 left(CSmove); 1098 c = Line[Point - 1]; 1099 left(CSstay); 1100 Line[Point - 1] = Line[Point]; 1101 TTYshow(Line[Point - 1]); 1102 Line[Point++] = c; 1103 TTYshow(c); 1104 } 1105 return CSstay; 1106} 1107 1108STATIC STATUS 1109quote() 1110{ 1111 unsigned int c; 1112 1113 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c); 1114} 1115 1116STATIC STATUS 1117wipe() 1118{ 1119 int i; 1120 1121 if (Mark > End) 1122 return ring_bell(); 1123 1124 if (Point > Mark) { 1125 i = Point; 1126 Point = Mark; 1127 Mark = i; 1128 reposition(); 1129 } 1130 1131 return delete_string(Mark - Point); 1132} 1133 1134STATIC STATUS 1135mk_set() 1136{ 1137 Mark = Point; 1138 return CSstay; 1139} 1140 1141STATIC STATUS 1142exchange() 1143{ 1144 unsigned int c; 1145 1146 if ((c = TTYget()) != CTL('X')) 1147 return c == EOF ? CSeof : ring_bell(); 1148 1149 if ((c = Mark) <= End) { 1150 Mark = Point; 1151 Point = c; 1152 return CSmove; 1153 } 1154 return CSstay; 1155} 1156 1157STATIC STATUS 1158yank() 1159{ 1160 if (Yanked && *Yanked) 1161 return insert_string(Yanked); 1162 return CSstay; 1163} 1164 1165STATIC STATUS 1166copy_region() 1167{ 1168 if (Mark > End) 1169 return ring_bell(); 1170 1171 if (Point > Mark) 1172 save_yank(Mark, Point - Mark); 1173 else 1174 save_yank(Point, Mark - Point); 1175 1176 return CSstay; 1177} 1178 1179STATIC STATUS 1180move_to_char() 1181{ 1182 unsigned int c; 1183 int i; 1184 CHAR *p; 1185 1186 if ((c = TTYget()) == EOF) 1187 return CSeof; 1188 for (i = Point + 1, p = &Line[i]; i < End; i++, p++) 1189 if (*p == c) { 1190 Point = i; 1191 return CSmove; 1192 } 1193 return CSstay; 1194} 1195 1196STATIC STATUS 1197fd_word() 1198{ 1199 return do_forward(CSmove); 1200} 1201 1202STATIC STATUS 1203fd_kill_word() 1204{ 1205 int i; 1206 1207 (void)do_forward(CSstay); 1208 if (OldPoint != Point) { 1209 i = Point - OldPoint; 1210 Point = OldPoint; 1211 return delete_string(i); 1212 } 1213 return CSstay; 1214} 1215 1216STATIC STATUS 1217bk_word() 1218{ 1219 int i; 1220 CHAR *p; 1221 1222 i = 0; 1223 do { 1224 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--) 1225 left(CSmove); 1226 1227 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--) 1228 left(CSmove); 1229 1230 if (Point == 0) 1231 break; 1232 } while (++i < Repeat); 1233 1234 return CSstay; 1235} 1236 1237STATIC STATUS 1238bk_kill_word() 1239{ 1240 (void)bk_word(); 1241 if (OldPoint != Point) 1242 return delete_string(OldPoint - Point); 1243 return CSstay; 1244} 1245 1246STATIC int 1247argify(line, avp) 1248 CHAR *line; 1249 CHAR ***avp; 1250{ 1251 CHAR *c; 1252 CHAR **p; 1253 CHAR **new; 1254 int ac; 1255 int i; 1256 1257 i = MEM_INC; 1258 if ((*avp = p = NEW(CHAR*, i))== NULL) 1259 return 0; 1260 1261 for (c = line; isspace(*c); c++) 1262 continue; 1263 if (*c == '\n' || *c == '\0') 1264 return 0; 1265 1266 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { 1267 if (isspace(*c)) { 1268 *c++ = '\0'; 1269 if (*c && *c != '\n') { 1270 if (ac + 1 == i) { 1271 new = NEW(CHAR*, i + MEM_INC); 1272 if (new == NULL) { 1273 p[ac] = NULL; 1274 return ac; 1275 } 1276 COPYFROMTO(new, p, i * sizeof (char **)); 1277 i += MEM_INC; 1278 DISPOSE(p); 1279 *avp = p = new; 1280 } 1281 p[ac++] = c; 1282 } 1283 } 1284 else 1285 c++; 1286 } 1287 *c = '\0'; 1288 p[ac] = NULL; 1289 return ac; 1290} 1291 1292STATIC STATUS 1293last_argument() 1294{ 1295 CHAR **av; 1296 CHAR *p; 1297 STATUS s; 1298 int ac; 1299 1300 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL) 1301 return ring_bell(); 1302 1303 if ((p = (CHAR *)strdup((char *)p)) == NULL) 1304 return CSstay; 1305 ac = argify(p, &av); 1306 1307 if (Repeat != NO_ARG) 1308 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell(); 1309 else 1310 s = ac ? insert_string(av[ac - 1]) : CSstay; 1311 1312 if (ac) 1313 DISPOSE(av); 1314 DISPOSE(p); 1315 return s; 1316} 1317 1318STATIC KEYMAP Map[32] = { 1319 { CTL('@'), ring_bell }, 1320 { CTL('A'), beg_line }, 1321 { CTL('B'), bk_char }, 1322 { CTL('D'), del_char }, 1323 { CTL('E'), end_line }, 1324 { CTL('F'), fd_char }, 1325 { CTL('G'), ring_bell }, 1326 { CTL('H'), bk_del_char }, 1327 { CTL('J'), accept_line }, 1328 { CTL('K'), kill_line }, 1329 { CTL('L'), redisplay }, 1330 { CTL('M'), accept_line }, 1331 { CTL('N'), h_next }, 1332 { CTL('O'), ring_bell }, 1333 { CTL('P'), h_prev }, 1334 { CTL('Q'), ring_bell }, 1335 { CTL('R'), h_search }, 1336 { CTL('S'), ring_bell }, 1337 { CTL('T'), transpose }, 1338 { CTL('U'), ring_bell }, 1339 { CTL('V'), quote }, 1340 { CTL('W'), wipe }, 1341 { CTL('X'), exchange }, 1342 { CTL('Y'), yank }, 1343 { CTL('Z'), ring_bell }, 1344 { CTL('['), meta }, 1345 { CTL(']'), move_to_char }, 1346 { CTL('^'), ring_bell }, 1347 { CTL('_'), ring_bell }, 1348 { 0, NULL } 1349}; 1350 1351STATIC KEYMAP MetaMap[16]= { 1352 { CTL('H'), bk_kill_word }, 1353 { DEL, bk_kill_word }, 1354 { ' ', mk_set }, 1355 { '.', last_argument }, 1356 { '<', h_first }, 1357 { '>', h_last }, 1358 { 'b', bk_word }, 1359 { 'd', fd_kill_word }, 1360 { 'f', fd_word }, 1361 { 'l', case_down_word }, 1362 { 'm', toggle_meta_mode }, 1363 { 'u', case_up_word }, 1364 { 'y', yank }, 1365 { 'w', copy_region }, 1366 { 0, NULL } 1367}; 1368