Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / src / editline / editline.c
blob48db9c2ac28dbfee9e84c8b79558e42088eee6fa
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 * Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved.
9 * This software is not subject to any license of the American Telephone
10 * and Telegraph Company or of the Regents of the University of California.
12 * Permission is granted to anyone to use this software for any purpose on
13 * any computer system, and to alter it and redistribute it freely, subject
14 * to the following restrictions:
15 * 1. The authors are not responsible for the consequences of use of this
16 * software, no matter how awful, even if they arise from flaws in it.
17 * 2. The origin of this software must not be misrepresented, either by
18 * explicit claim or by omission. Since few users ever read sources,
19 * credits must appear in the documentation.
20 * 3. Altered versions must be plainly marked as such, and must not be
21 * misrepresented as being the original software. Since few users
22 * ever read sources, credits must appear in the documentation.
23 * 4. This notice may not be removed or altered.
28 ** Main editing routines for editline library.
30 #include "editline.h"
31 #include <signal.h>
32 #include <ctype.h>
33 #include <unistd.h>
36 ** Manifest constants.
38 #define SCREEN_WIDTH 80
39 #define SCREEN_ROWS 24
40 #define NO_ARG (-1)
41 #define DEL 127
42 #define CTL(x) ((x) & 0x1F)
43 #define ISCTL(x) ((x) && (x) < ' ')
44 #define UNCTL(x) ((x) + 64)
45 #define META(x) ((x) | 0x80)
46 #define ISMETA(x) ((x) & 0x80)
47 #define UNMETA(x) ((x) & 0x7F)
48 #if !defined(HIST_SIZE)
49 #define HIST_SIZE 20
50 #endif /* !defined(HIST_SIZE) */
53 ** Command status codes.
55 typedef enum _STATUS {
56 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
57 } STATUS;
60 ** The type of case-changing to perform.
62 typedef enum _CASE {
63 TOupper, TOlower
64 } CASE;
67 ** Key to command mapping.
69 typedef struct _KEYMAP {
70 CHAR Key;
71 STATUS (*Function)();
72 } KEYMAP;
75 ** Command history structure.
77 typedef struct _HISTORY {
78 int Size;
79 int Pos;
80 CHAR *Lines[HIST_SIZE];
81 } HISTORY;
84 ** Globals.
86 unsigned rl_eof;
87 unsigned rl_erase;
88 unsigned rl_intr;
89 unsigned rl_kill;
90 unsigned rl_quit;
92 STATIC CHAR NIL[] = "";
93 STATIC CONST CHAR *Input = NIL;
94 STATIC CHAR *Line;
95 STATIC CONST char *Prompt;
96 STATIC CHAR *Yanked;
97 STATIC char *Screen;
98 STATIC CONST char NEWLINE[]= CRLF;
99 STATIC HISTORY H;
100 STATIC int Repeat;
101 STATIC int End;
102 STATIC int Mark;
103 STATIC int OldPoint;
104 STATIC int Point;
105 STATIC int PushBack;
106 STATIC int Pushed;
107 STATIC int Signal;
108 FORWARD CONST KEYMAP Map[32];
109 FORWARD CONST KEYMAP MetaMap[16];
110 STATIC SIZE_T Length;
111 STATIC SIZE_T ScreenCount;
112 STATIC SIZE_T ScreenSize;
113 STATIC char *backspace;
114 STATIC int TTYwidth;
115 STATIC int TTYrows;
117 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
118 int rl_meta_chars = 0;
121 ** Declarations.
123 STATIC CHAR *editinput();
124 #if defined(USE_TERMCAP)
125 #include <stdlib.h>
126 #include <curses.h>
127 #include <term.h>
128 #endif /* defined(USE_TERMCAP) */
131 ** TTY input/output functions.
134 STATIC void
135 TTYflush()
137 if (ScreenCount) {
138 /* Dummy assignment avoids GCC warning on
139 * "attribute warn_unused_result" */
140 ssize_t dummy = write(1, Screen, ScreenCount);
141 (void)dummy;
142 ScreenCount = 0;
146 STATIC void
147 TTYput(CHAR c)
149 Screen[ScreenCount] = c;
150 if (++ScreenCount >= ScreenSize - 1) {
151 ScreenSize += SCREEN_INC;
152 RENEW(Screen, char, ScreenSize);
156 STATIC void
157 TTYputs(CONST CHAR *p)
159 while (*p)
160 TTYput(*p++);
163 STATIC void
164 TTYshow(CHAR c)
166 if (c == DEL) {
167 TTYput('^');
168 TTYput('?');
170 else if (ISCTL(c)) {
171 TTYput('^');
172 TTYput(UNCTL(c));
174 else if (rl_meta_chars && ISMETA(c)) {
175 TTYput('M');
176 TTYput('-');
177 TTYput(UNMETA(c));
179 else
180 TTYput(c);
183 STATIC void
184 TTYstring(CHAR *p)
186 while (*p)
187 TTYshow(*p++);
190 STATIC unsigned int
191 TTYget()
193 CHAR c;
195 TTYflush();
196 if (Pushed) {
197 Pushed = 0;
198 return PushBack;
200 if (*Input)
201 return *Input++;
202 return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
205 #define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
207 STATIC void
208 TTYbackn(int n)
210 while (--n >= 0)
211 TTYback();
214 STATIC void
215 TTYinfo()
217 static int init;
218 #if defined(USE_TERMCAP)
219 char *term;
220 char buff[2048];
221 char *bp, *p;
222 #endif /* defined(USE_TERMCAP) */
223 #if defined(TIOCGWINSZ)
224 struct winsize W;
225 #endif /* defined(TIOCGWINSZ) */
227 if (init) {
228 #if defined(TIOCGWINSZ)
229 /* Perhaps we got resized. */
230 if (ioctl(0, TIOCGWINSZ, &W) >= 0
231 && W.ws_col > 0 && W.ws_row > 0) {
232 TTYwidth = (int)W.ws_col;
233 TTYrows = (int)W.ws_row;
235 #endif /* defined(TIOCGWINSZ) */
236 return;
238 init++;
240 TTYwidth = TTYrows = 0;
241 #if defined(USE_TERMCAP)
242 bp = &buff[0];
243 if ((term = getenv("TERM")) == NULL)
244 term = "dumb";
245 if (tgetent(buff, term) < 0) {
246 TTYwidth = SCREEN_WIDTH;
247 TTYrows = SCREEN_ROWS;
248 return;
250 p = tgetstr("le", &bp);
251 backspace = p ? strdup(p) : NULL;
252 TTYwidth = tgetnum("co");
253 TTYrows = tgetnum("li");
254 #endif /* defined(USE_TERMCAP) */
256 #if defined(TIOCGWINSZ)
257 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
258 TTYwidth = (int)W.ws_col;
259 TTYrows = (int)W.ws_row;
261 #endif /* defined(TIOCGWINSZ) */
263 if (TTYwidth <= 0 || TTYrows <= 0) {
264 TTYwidth = SCREEN_WIDTH;
265 TTYrows = SCREEN_ROWS;
270 STATIC void
271 reposition()
273 int i;
274 CHAR *p;
276 TTYput('\r');
277 TTYputs((CONST CHAR *)Prompt);
278 for (i = Point, p = Line; --i >= 0; p++)
279 TTYshow(*p);
282 STATIC void
283 left(STATUS Change)
285 TTYback();
286 if (Point) {
287 if (ISCTL(Line[Point - 1]))
288 TTYback();
289 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
290 TTYback();
291 TTYback();
294 if (Change == CSmove)
295 Point--;
298 STATIC void
299 right(STATUS Change)
301 TTYshow(Line[Point]);
302 if (Change == CSmove)
303 Point++;
306 STATIC STATUS
307 ring_bell()
309 TTYput('\07');
310 TTYflush();
311 return CSstay;
314 STATIC STATUS
315 do_macro(unsigned int c)
317 CHAR name[4];
319 name[0] = '_';
320 name[1] = c;
321 name[2] = '_';
322 name[3] = '\0';
324 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
325 Input = NIL;
326 return ring_bell();
328 return CSstay;
331 STATIC STATUS
332 do_forward(STATUS move)
334 int i;
335 CHAR *p;
337 i = 0;
338 do {
339 p = &Line[Point];
340 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
341 if (move == CSmove)
342 right(CSstay);
344 for (; Point < End && isalnum(*p); Point++, p++)
345 if (move == CSmove)
346 right(CSstay);
348 if (Point == End)
349 break;
350 } while (++i < Repeat);
352 return CSstay;
355 STATIC STATUS
356 do_case(CASE type)
358 int i;
359 int end;
360 int count;
361 CHAR *p;
363 (void)do_forward(CSstay);
364 if (OldPoint != Point) {
365 if ((count = Point - OldPoint) < 0)
366 count = -count;
367 Point = OldPoint;
368 if ((end = Point + count) > End)
369 end = End;
370 for (i = Point, p = &Line[i]; i < end; i++, p++) {
371 if (type == TOupper) {
372 if (islower(*p))
373 *p = toupper(*p);
375 else if (isupper(*p))
376 *p = tolower(*p);
377 right(CSmove);
380 return CSstay;
383 STATIC STATUS
384 case_down_word()
386 return do_case(TOlower);
389 STATIC STATUS
390 case_up_word()
392 return do_case(TOupper);
395 STATIC void
396 ceol()
398 int extras;
399 int i;
400 CHAR *p;
402 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
403 TTYput(' ');
404 if (ISCTL(*p)) {
405 TTYput(' ');
406 extras++;
408 else if (rl_meta_chars && ISMETA(*p)) {
409 TTYput(' ');
410 TTYput(' ');
411 extras += 2;
415 for (i += extras; i > Point; i--)
416 TTYback();
419 STATIC void
420 clear_line()
422 Point = -strlen(Prompt);
423 TTYput('\r');
424 ceol();
425 Point = 0;
426 End = 0;
427 Line[0] = '\0';
430 STATIC STATUS
431 insert_string(CHAR *p)
433 SIZE_T len;
434 int i;
435 CHAR *new;
436 CHAR *q;
438 len = strlen((char *)p);
439 if (End + len >= Length) {
440 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
441 return CSstay;
442 if (Length) {
443 COPYFROMTO(new, Line, Length);
444 DISPOSE(Line);
446 Line = new;
447 Length += len + MEM_INC;
450 for (q = &Line[Point], i = End - Point; --i >= 0; )
451 q[len + i] = q[i];
452 COPYFROMTO(&Line[Point], p, len);
453 End += len;
454 Line[End] = '\0';
455 TTYstring(&Line[Point]);
456 Point += len;
458 return Point == End ? CSstay : CSmove;
461 STATIC STATUS
462 redisplay()
464 TTYputs((CONST CHAR *)NEWLINE);
465 TTYputs((CONST CHAR *)Prompt);
466 TTYstring(Line);
467 return CSmove;
470 STATIC STATUS
471 toggle_meta_mode()
473 rl_meta_chars = ! rl_meta_chars;
474 return redisplay();
478 STATIC CHAR *
479 next_hist()
481 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
484 STATIC CHAR *
485 prev_hist()
487 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
490 STATIC STATUS
491 do_insert_hist(CHAR *p)
493 if (p == NULL)
494 return ring_bell();
495 Point = 0;
496 reposition();
497 ceol();
498 End = 0;
499 return insert_string(p);
502 STATIC STATUS
503 do_hist(CHAR *(*move)())
505 CHAR *p;
506 int i;
508 i = 0;
509 do {
510 if ((p = (*move)()) == NULL)
511 return ring_bell();
512 } while (++i < Repeat);
513 return do_insert_hist(p);
516 STATIC STATUS
517 h_next()
519 return do_hist(next_hist);
522 STATIC STATUS
523 h_prev()
525 return do_hist(prev_hist);
528 STATIC STATUS
529 h_first()
531 return do_insert_hist(H.Lines[H.Pos = 0]);
534 STATIC STATUS
535 h_last()
537 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
541 ** Return zero if pat appears as a substring in text.
543 STATIC int
544 substrcmp(char *text, char *pat, size_t len)
546 char c;
548 if ((c = *pat) == '\0')
549 return *text == '\0';
550 for ( ; *text; text++)
551 if (*text == c && strncmp(text, pat, len) == 0)
552 return 0;
553 return 1;
556 STATIC CHAR *
557 search_hist(CHAR *search, CHAR *(*move)())
559 static CHAR *old_search;
560 int len;
561 int pos;
562 int (*match)(char *, char *, size_t);
563 char *pat;
565 /* Save or get remembered search pattern. */
566 if (search && *search) {
567 if (old_search)
568 DISPOSE(old_search);
569 old_search = (CHAR *)strdup((char *)search);
571 else {
572 if (old_search == NULL || *old_search == '\0')
573 return NULL;
574 search = old_search;
577 /* Set up pattern-finder. */
578 if (*search == '^') {
579 match = (int(*)(char *, char *, size_t))strncmp;
580 pat = (char *)(search + 1);
582 else {
583 match = substrcmp;
584 pat = (char *)search;
586 len = strlen(pat);
588 for (pos = H.Pos; (*move)() != NULL; )
589 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
590 return H.Lines[H.Pos];
591 H.Pos = pos;
592 return NULL;
595 STATIC STATUS
596 h_search()
598 static int Searching;
599 CONST char *old_prompt;
600 CHAR *(*move)();
601 CHAR *p;
603 if (Searching)
604 return ring_bell();
605 Searching = 1;
607 clear_line();
608 old_prompt = Prompt;
609 Prompt = "Search: ";
610 TTYputs((CONST CHAR *)Prompt);
611 move = Repeat == NO_ARG ? prev_hist : next_hist;
612 p = editinput();
613 Prompt = old_prompt;
614 Searching = 0;
615 TTYputs((CONST CHAR *)Prompt);
616 if (p == NULL && Signal > 0) {
617 Signal = 0;
618 clear_line();
619 return redisplay();
621 p = search_hist(p, move);
622 clear_line();
623 if (p == NULL) {
624 (void)ring_bell();
625 return redisplay();
627 return do_insert_hist(p);
630 STATIC STATUS
631 fd_char()
633 int i;
635 i = 0;
636 do {
637 if (Point >= End)
638 break;
639 right(CSmove);
640 } while (++i < Repeat);
641 return CSstay;
644 STATIC void
645 save_yank(int begin, int i)
647 if (Yanked) {
648 DISPOSE(Yanked);
649 Yanked = NULL;
652 if (i < 1)
653 return;
655 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
656 COPYFROMTO(Yanked, &Line[begin], i);
657 Yanked[i] = '\0';
661 STATIC STATUS
662 delete_string(int count)
664 int i;
665 CHAR *p;
667 if (count <= 0 || End == Point)
668 return ring_bell();
670 if (count == 1 && Point == End - 1) {
671 /* Optimize common case of delete at end of line. */
672 End--;
673 p = &Line[Point];
674 i = 1;
675 TTYput(' ');
676 if (ISCTL(*p)) {
677 i = 2;
678 TTYput(' ');
680 else if (rl_meta_chars && ISMETA(*p)) {
681 i = 3;
682 TTYput(' ');
683 TTYput(' ');
685 TTYbackn(i);
686 *p = '\0';
687 return CSmove;
689 if (Point + count > End && (count = End - Point) <= 0)
690 return CSstay;
692 if (count > 1)
693 save_yank(Point, count);
695 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
696 p[0] = p[count];
697 ceol();
698 End -= count;
699 TTYstring(&Line[Point]);
700 return CSmove;
703 STATIC STATUS
704 bk_char()
706 int i;
708 i = 0;
709 do {
710 if (Point == 0)
711 break;
712 left(CSmove);
713 } while (++i < Repeat);
715 return CSstay;
718 STATIC STATUS
719 bk_del_char()
721 int i;
723 i = 0;
724 do {
725 if (Point == 0)
726 break;
727 left(CSmove);
728 } while (++i < Repeat);
730 return delete_string(i);
733 STATIC STATUS
734 kill_line()
736 int i;
738 if (Repeat != NO_ARG) {
739 if (Repeat < Point) {
740 i = Point;
741 Point = Repeat;
742 reposition();
743 (void)delete_string(i - Point);
745 else if (Repeat > Point) {
746 right(CSmove);
747 (void)delete_string(Repeat - Point - 1);
749 return CSmove;
752 save_yank(Point, End - Point);
753 Line[Point] = '\0';
754 ceol();
755 End = Point;
756 return CSstay;
759 STATIC STATUS
760 insert_char(int c)
762 STATUS s;
763 CHAR buff[2];
764 CHAR *p;
765 CHAR *q;
766 int i;
768 if (Repeat == NO_ARG || Repeat < 2) {
769 buff[0] = c;
770 buff[1] = '\0';
771 return insert_string(buff);
774 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
775 return CSstay;
776 for (i = Repeat, q = p; --i >= 0; )
777 *q++ = c;
778 *q = '\0';
779 Repeat = 0;
780 s = insert_string(p);
781 DISPOSE(p);
782 return s;
785 STATIC STATUS
786 meta()
788 unsigned int c;
789 CONST KEYMAP *kp;
791 if ((int)(c = TTYget()) == EOF)
792 return CSeof;
793 #if defined(ANSI_ARROWS)
794 /* Also include VT-100 arrows. */
795 if (c == '[' || c == 'O')
796 switch (c = TTYget()) {
797 default: return ring_bell();
798 case EOF: return CSeof;
799 case 'A': return h_prev();
800 case 'B': return h_next();
801 case 'C': return fd_char();
802 case 'D': return bk_char();
804 #endif /* defined(ANSI_ARROWS) */
806 if (isdigit(c)) {
807 for (Repeat = c - '0'; (int)(c = TTYget()) != EOF && isdigit(c); )
808 Repeat = Repeat * 10 + c - '0';
809 Pushed = 1;
810 PushBack = c;
811 return CSstay;
814 if (isupper(c))
815 return do_macro(c);
816 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
817 if (kp->Key == c)
818 return (*kp->Function)();
820 return ring_bell();
823 STATIC STATUS
824 emacs(unsigned int c)
826 STATUS s;
827 const KEYMAP *kp;
829 if (rl_meta_chars && ISMETA(c)) {
830 Pushed = 1;
831 PushBack = UNMETA(c);
832 return meta();
834 for (kp = Map; kp->Function; kp++)
835 if (kp->Key == c)
836 break;
837 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
838 if (!Pushed)
839 /* No pushback means no repeat count; hacky, but true. */
840 Repeat = NO_ARG;
841 return s;
844 STATIC STATUS
845 TTYspecial(unsigned int c)
847 if (ISMETA(c))
848 return CSdispatch;
850 if (c == rl_erase || (int)c == DEL)
851 return bk_del_char();
852 if (c == rl_kill) {
853 if (Point != 0) {
854 Point = 0;
855 reposition();
857 Repeat = NO_ARG;
858 return kill_line();
860 if (c == rl_eof && Point == 0 && End == 0)
861 return CSeof;
862 if (c == rl_intr) {
863 Signal = SIGINT;
864 return CSsignal;
866 if (c == rl_quit) {
867 Signal = SIGQUIT;
868 return CSeof;
871 return CSdispatch;
874 STATIC CHAR *
875 editinput()
877 unsigned int c;
879 Repeat = NO_ARG;
880 OldPoint = Point = Mark = End = 0;
881 Line[0] = '\0';
883 Signal = -1;
884 while ((int)(c = TTYget()) != EOF)
885 switch (TTYspecial(c)) {
886 case CSdone:
887 return Line;
888 case CSeof:
889 return NULL;
890 case CSsignal:
891 return (CHAR *)"";
892 case CSmove:
893 reposition();
894 break;
895 case CSdispatch:
896 switch (emacs(c)) {
897 case CSdone:
898 return Line;
899 case CSeof:
900 return NULL;
901 case CSsignal:
902 return (CHAR *)"";
903 case CSmove:
904 reposition();
905 break;
906 case CSdispatch:
907 case CSstay:
908 break;
910 break;
911 case CSstay:
912 break;
914 if (strlen((char *)Line))
915 return Line;
916 free(Line);
917 return NULL;
920 STATIC void
921 hist_add(CHAR *p)
923 int i;
925 if ((p = (CHAR *)strdup((char *)p)) == NULL)
926 return;
927 if (H.Size < HIST_SIZE)
928 H.Lines[H.Size++] = p;
929 else {
930 DISPOSE(H.Lines[0]);
931 for (i = 0; i < HIST_SIZE - 1; i++)
932 H.Lines[i] = H.Lines[i + 1];
933 H.Lines[i] = p;
935 H.Pos = H.Size - 1;
939 ** For compatibility with FSF readline.
941 /* ARGSUSED0 */
942 void
943 rl_reset_terminal(char *p)
945 (void)p;
948 void
949 rl_initialize()
953 char *
954 readline(CONST char *prompt)
956 CHAR *line;
957 int s;
959 if (Line == NULL) {
960 Length = MEM_INC;
961 if ((Line = NEW(CHAR, Length)) == NULL)
962 return NULL;
965 TTYinfo();
966 rl_ttyset(0);
967 hist_add(NIL);
968 ScreenSize = SCREEN_INC;
969 Screen = NEW(char, ScreenSize);
970 Prompt = prompt ? prompt : (char *)NIL;
971 TTYputs((CONST CHAR *)Prompt);
972 if ((line = editinput()) != NULL) {
973 line = (CHAR *)strdup((char *)line);
974 TTYputs((CONST CHAR *)NEWLINE);
975 TTYflush();
977 rl_ttyset(1);
978 DISPOSE(Screen);
979 DISPOSE(H.Lines[--H.Size]);
980 if (Signal > 0) {
981 s = Signal;
982 Signal = 0;
983 (void)kill(getpid(), s);
985 return (char *)line;
988 void
989 add_history(char *p)
991 if (p == NULL || *p == '\0')
992 return;
994 #if defined(UNIQUE_HISTORY)
995 if (H.Size && strcmp(p, (char *)H.Lines[H.Size - 1]) == 0)
996 return;
997 #endif /* defined(UNIQUE_HISTORY) */
998 hist_add((CHAR *)p);
1002 STATIC STATUS
1003 beg_line()
1005 if (Point) {
1006 Point = 0;
1007 return CSmove;
1009 return CSstay;
1012 STATIC STATUS
1013 del_char()
1015 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1018 STATIC STATUS
1019 end_line()
1021 if (Point != End) {
1022 Point = End;
1023 return CSmove;
1025 return CSstay;
1028 STATIC STATUS
1029 accept_line()
1031 Line[End] = '\0';
1032 return CSdone;
1035 STATIC STATUS
1036 transpose()
1038 CHAR c;
1040 if (Point) {
1041 if (Point == End)
1042 left(CSmove);
1043 c = Line[Point - 1];
1044 left(CSstay);
1045 Line[Point - 1] = Line[Point];
1046 TTYshow(Line[Point - 1]);
1047 Line[Point++] = c;
1048 TTYshow(c);
1050 return CSstay;
1053 STATIC STATUS
1054 quote()
1056 unsigned int c;
1058 return (int)(c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1061 STATIC STATUS
1062 wipe()
1064 int i;
1066 if (Mark > End)
1067 return ring_bell();
1069 if (Point > Mark) {
1070 i = Point;
1071 Point = Mark;
1072 Mark = i;
1073 reposition();
1076 return delete_string(Mark - Point);
1079 STATIC STATUS
1080 mk_set()
1082 Mark = Point;
1083 return CSstay;
1086 STATIC STATUS
1087 exchange()
1089 unsigned int c;
1091 if ((c = TTYget()) != CTL('X'))
1092 return (int)c == EOF ? CSeof : ring_bell();
1094 if ((int)(c = Mark) <= End) {
1095 Mark = Point;
1096 Point = c;
1097 return CSmove;
1099 return CSstay;
1102 STATIC STATUS
1103 yank()
1105 if (Yanked && *Yanked)
1106 return insert_string(Yanked);
1107 return CSstay;
1110 STATIC STATUS
1111 copy_region()
1113 if (Mark > End)
1114 return ring_bell();
1116 if (Point > Mark)
1117 save_yank(Mark, Point - Mark);
1118 else
1119 save_yank(Point, Mark - Point);
1121 return CSstay;
1124 STATIC STATUS
1125 move_to_char()
1127 unsigned int c;
1128 int i;
1129 CHAR *p;
1131 if ((int)(c = TTYget()) == EOF)
1132 return CSeof;
1133 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1134 if (*p == c) {
1135 Point = i;
1136 return CSmove;
1138 return CSstay;
1141 STATIC STATUS
1142 fd_word()
1144 return do_forward(CSmove);
1147 STATIC STATUS
1148 fd_kill_word()
1150 int i;
1152 (void)do_forward(CSstay);
1153 if (OldPoint != Point) {
1154 i = Point - OldPoint;
1155 Point = OldPoint;
1156 return delete_string(i);
1158 return CSstay;
1161 STATIC STATUS
1162 bk_word()
1164 int i;
1165 CHAR *p;
1167 i = 0;
1168 do {
1169 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1170 left(CSmove);
1172 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1173 left(CSmove);
1175 if (Point == 0)
1176 break;
1177 } while (++i < Repeat);
1179 return CSstay;
1182 STATIC STATUS
1183 bk_kill_word()
1185 (void)bk_word();
1186 if (OldPoint != Point)
1187 return delete_string(OldPoint - Point);
1188 return CSstay;
1191 STATIC int
1192 argify(CHAR *line, CHAR ***avp)
1194 CHAR *c;
1195 CHAR **p;
1196 CHAR **new;
1197 int ac;
1198 int i;
1200 i = MEM_INC;
1201 if ((*avp = p = NEW(CHAR*, i))== NULL)
1202 return 0;
1204 for (c = line; isspace(*c); c++)
1205 continue;
1206 if (*c == '\n' || *c == '\0')
1207 return 0;
1209 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1210 if (isspace(*c)) {
1211 *c++ = '\0';
1212 if (*c && *c != '\n') {
1213 if (ac + 1 == i) {
1214 new = NEW(CHAR*, i + MEM_INC);
1215 if (new == NULL) {
1216 p[ac] = NULL;
1217 return ac;
1219 COPYFROMTO(new, p, i * sizeof (char **));
1220 i += MEM_INC;
1221 DISPOSE(p);
1222 *avp = p = new;
1224 p[ac++] = c;
1227 else
1228 c++;
1230 *c = '\0';
1231 p[ac] = NULL;
1232 return ac;
1235 STATIC STATUS
1236 last_argument()
1238 CHAR **av;
1239 CHAR *p;
1240 STATUS s;
1241 int ac;
1243 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1244 return ring_bell();
1246 if ((p = (CHAR *)strdup((char *)p)) == NULL)
1247 return CSstay;
1248 ac = argify(p, &av);
1250 if (Repeat != NO_ARG)
1251 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1252 else
1253 s = ac ? insert_string(av[ac - 1]) : CSstay;
1255 if (ac)
1256 DISPOSE(av);
1257 DISPOSE(p);
1258 return s;
1261 STATIC CONST KEYMAP Map[32] = {
1262 { CTL('@'), ring_bell },
1263 { CTL('A'), beg_line },
1264 { CTL('B'), bk_char },
1265 { CTL('D'), del_char },
1266 { CTL('E'), end_line },
1267 { CTL('F'), fd_char },
1268 { CTL('G'), ring_bell },
1269 { CTL('H'), bk_del_char },
1270 { CTL('J'), accept_line },
1271 { CTL('K'), kill_line },
1272 { CTL('L'), redisplay },
1273 { CTL('M'), accept_line },
1274 { CTL('N'), h_next },
1275 { CTL('O'), ring_bell },
1276 { CTL('P'), h_prev },
1277 { CTL('Q'), ring_bell },
1278 { CTL('R'), h_search },
1279 { CTL('S'), ring_bell },
1280 { CTL('T'), transpose },
1281 { CTL('U'), ring_bell },
1282 { CTL('V'), quote },
1283 { CTL('W'), wipe },
1284 { CTL('X'), exchange },
1285 { CTL('Y'), yank },
1286 { CTL('Z'), ring_bell },
1287 { CTL('['), meta },
1288 { CTL(']'), move_to_char },
1289 { CTL('^'), ring_bell },
1290 { CTL('_'), ring_bell },
1291 { 0, NULL }
1294 STATIC CONST KEYMAP MetaMap[16]= {
1295 { CTL('H'), bk_kill_word },
1296 { DEL, bk_kill_word },
1297 { ' ', mk_set },
1298 { '.', last_argument },
1299 { '<', h_first },
1300 { '>', h_last },
1301 { 'b', bk_word },
1302 { 'd', fd_kill_word },
1303 { 'f', fd_word },
1304 { 'l', case_down_word },
1305 { 'm', toggle_meta_mode },
1306 { 'u', case_up_word },
1307 { 'y', yank },
1308 { 'w', copy_region },
1309 { 0, NULL }