at_wini: remove unnecessary quirks debug message
[minix.git] / lib / libedit / editline.c
blob8e7e56ee70bcdc86b35bb50fe994a03483b6c23d
1 /* $Revision$
2 **
3 ** Main editing routines for editline library.
4 */
5 #include "editline.h"
6 #include <signal.h>
7 #include <errno.h>
8 #include <ctype.h>
11 ** Manifest constants.
13 #define SCREEN_WIDTH 80
14 #define SCREEN_ROWS 24
15 #define NO_ARG (-1)
16 #define DEL 127
17 #define CTL(x) ((x) & 0x1F)
18 #define ISCTL(x) ((x) && (x) < ' ')
19 #define UNCTL(x) ((x) + 64)
20 #define META(x) ((x) | 0x80)
21 #define ISMETA(x) ((x) & 0x80)
22 #define UNMETA(x) ((x) & 0x7F)
23 #if !defined(HIST_SIZE)
24 #define HIST_SIZE 20
25 #endif /* !defined(HIST_SIZE) */
28 ** Command status codes.
30 typedef enum _STATUS {
31 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
32 } STATUS;
35 ** The type of case-changing to perform.
37 typedef enum _CASE {
38 TOupper, TOlower
39 } CASE;
42 ** Key to command mapping.
44 typedef struct _KEYMAP {
45 CHAR Key;
46 STATUS (*Function)();
47 } KEYMAP;
50 ** Command history structure.
52 typedef struct _HISTORY {
53 int Size;
54 int Pos;
55 CHAR *Lines[HIST_SIZE];
56 } HISTORY;
59 ** Globals.
61 int rl_eof;
62 int rl_erase;
63 int rl_intr;
64 int rl_kill;
65 int rl_quit;
67 STATIC CHAR NIL[] = "";
68 STATIC CONST CHAR *Input = NIL;
69 STATIC CHAR *Line;
70 STATIC CONST char *Prompt;
71 STATIC CHAR *Yanked;
72 STATIC char *Screen;
73 STATIC char NEWLINE[]= CRLF;
74 STATIC HISTORY H;
75 STATIC int Repeat;
76 STATIC int End;
77 STATIC int Mark;
78 STATIC int OldPoint;
79 STATIC int Point;
80 STATIC int PushBack;
81 STATIC int Pushed;
82 STATIC int Signal;
83 FORWARD KEYMAP Map[33];
84 FORWARD KEYMAP MetaMap[17];
85 STATIC SIZE_T Length;
86 STATIC SIZE_T ScreenCount;
87 STATIC SIZE_T ScreenSize;
88 STATIC char *backspace;
89 STATIC int TTYwidth;
90 STATIC int TTYrows;
92 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
93 int rl_meta_chars = 0;
96 ** Declarations.
98 STATIC CHAR *editinput();
99 extern int read();
100 extern int write();
101 #if defined(USE_TERMCAP)
102 extern char *tgetstr();
103 extern int tgetent();
104 #endif /* defined(USE_TERMCAP) */
107 ** TTY input/output functions.
110 STATIC void
111 TTYflush()
113 if (ScreenCount) {
114 (void)write(1, Screen, ScreenCount);
115 ScreenCount = 0;
119 STATIC void
120 TTYput(c)
121 CHAR c;
123 Screen[ScreenCount] = c;
124 if (++ScreenCount >= ScreenSize - 1) {
125 ScreenSize += SCREEN_INC;
126 RENEW(Screen, char, ScreenSize);
130 STATIC void
131 TTYputs(p)
132 CHAR *p;
134 while (*p)
135 TTYput(*p++);
138 STATIC void
139 TTYshow(c)
140 CHAR c;
142 if (c == DEL) {
143 TTYput('^');
144 TTYput('?');
146 else if (ISCTL(c)) {
147 TTYput('^');
148 TTYput(UNCTL(c));
150 else if (rl_meta_chars && ISMETA(c)) {
151 TTYput('M');
152 TTYput('-');
153 TTYput(UNMETA(c));
155 else
156 TTYput(c);
159 STATIC void
160 TTYstring(p)
161 CHAR *p;
163 while (*p)
164 TTYshow(*p++);
167 STATIC unsigned int
168 TTYget()
170 CHAR c;
171 int r;
173 TTYflush();
174 if (Pushed) {
175 Pushed = 0;
176 return PushBack;
178 if (*Input)
179 return *Input++;
182 r= read(0, &c, (SIZE_T)1);
183 } while (r == -1 && errno == EINTR);
184 return r == 1 ? c : EOF;
187 #define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
189 STATIC void
190 TTYbackn(n)
191 int n;
193 while (--n >= 0)
194 TTYback();
197 STATIC void
198 TTYinfo()
200 static int init;
201 #if defined(USE_TERMCAP)
202 char *term;
203 char buff[2048];
204 char *bp;
205 #endif /* defined(USE_TERMCAP) */
206 #if defined(TIOCGWINSZ)
207 struct winsize W;
208 #endif /* defined(TIOCGWINSZ) */
210 if (init) {
211 #if defined(TIOCGWINSZ)
212 /* Perhaps we got resized. */
213 if (ioctl(0, TIOCGWINSZ, &W) >= 0
214 && W.ws_col > 0 && W.ws_row > 0) {
215 TTYwidth = (int)W.ws_col;
216 TTYrows = (int)W.ws_row;
218 #endif /* defined(TIOCGWINSZ) */
219 return;
221 init++;
223 TTYwidth = TTYrows = 0;
224 #if defined(USE_TERMCAP)
225 bp = &buff[0];
226 if ((term = getenv("TERM")) == NULL)
227 term = "dumb";
228 if (tgetent(buff, term) < 0) {
229 TTYwidth = SCREEN_WIDTH;
230 TTYrows = SCREEN_ROWS;
231 return;
233 if ((backspace = tgetstr("le", &bp)) != NULL)
234 backspace = strdup(backspace);
235 TTYwidth = tgetnum("co");
236 TTYrows = tgetnum("li");
237 #endif /* defined(USE_TERMCAP) */
239 #if defined(TIOCGWINSZ)
240 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
241 TTYwidth = (int)W.ws_col;
242 TTYrows = (int)W.ws_row;
244 #endif /* defined(TIOCGWINSZ) */
246 if (TTYwidth <= 0 || TTYrows <= 0) {
247 TTYwidth = SCREEN_WIDTH;
248 TTYrows = SCREEN_ROWS;
254 ** Print an array of words in columns.
256 STATIC void
257 columns(ac, av)
258 int ac;
259 CHAR **av;
261 CHAR *p;
262 int i;
263 int j;
264 int k;
265 int len;
266 int skip;
267 int longest;
268 int cols;
270 /* Find longest name, determine column count from that. */
271 for (longest = 0, i = 0; i < ac; i++)
272 if ((j = strlen((char *)av[i])) > longest)
273 longest = j;
274 cols = TTYwidth / (longest + 3);
276 TTYputs((CHAR *)NEWLINE);
277 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
278 for (j = i; j < ac; j += skip) {
279 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
280 TTYput(*p);
281 if (j + skip < ac)
282 while (++len < longest + 3)
283 TTYput(' ');
285 TTYputs((CHAR *)NEWLINE);
289 STATIC void
290 reposition()
292 int i;
293 CHAR *p;
295 TTYput('\r');
296 TTYputs((CONST CHAR *)Prompt);
297 for (i = Point, p = Line; --i >= 0; p++)
298 TTYshow(*p);
301 STATIC void
302 left(Change)
303 STATUS Change;
305 TTYback();
306 if (Point) {
307 if (ISCTL(Line[Point - 1]))
308 TTYback();
309 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
310 TTYback();
311 TTYback();
314 if (Change == CSmove)
315 Point--;
318 STATIC void
319 right(Change)
320 STATUS Change;
322 TTYshow(Line[Point]);
323 if (Change == CSmove)
324 Point++;
327 STATIC STATUS
328 ring_bell()
330 TTYput('\07');
331 TTYflush();
332 return CSstay;
335 STATIC STATUS
336 do_macro(c)
337 unsigned int c;
339 CHAR name[4];
341 name[0] = '_';
342 name[1] = c;
343 name[2] = '_';
344 name[3] = '\0';
346 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
347 Input = NIL;
348 return ring_bell();
350 return CSstay;
353 STATIC STATUS
354 do_forward(move)
355 STATUS move;
357 int i;
358 CHAR *p;
360 i = 0;
361 do {
362 p = &Line[Point];
363 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
364 if (move == CSmove)
365 right(CSstay);
367 for (; Point < End && isalnum(*p); Point++, p++)
368 if (move == CSmove)
369 right(CSstay);
371 if (Point == End)
372 break;
373 } while (++i < Repeat);
375 return CSstay;
378 STATIC STATUS
379 do_case(type)
380 CASE type;
382 int i;
383 int end;
384 int count;
385 CHAR *p;
387 (void)do_forward(CSstay);
388 if (OldPoint != Point) {
389 if ((count = Point - OldPoint) < 0)
390 count = -count;
391 Point = OldPoint;
392 if ((end = Point + count) > End)
393 end = End;
394 for (i = Point, p = &Line[i]; i < end; i++, p++) {
395 if (type == TOupper) {
396 if (islower(*p))
397 *p = toupper(*p);
399 else if (isupper(*p))
400 *p = tolower(*p);
401 right(CSmove);
404 return CSstay;
407 STATIC STATUS
408 case_down_word()
410 return do_case(TOlower);
413 STATIC STATUS
414 case_up_word()
416 return do_case(TOupper);
419 STATIC void
420 ceol()
422 int extras;
423 int i;
424 CHAR *p;
426 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
427 TTYput(' ');
428 if (ISCTL(*p)) {
429 TTYput(' ');
430 extras++;
432 else if (rl_meta_chars && ISMETA(*p)) {
433 TTYput(' ');
434 TTYput(' ');
435 extras += 2;
439 for (i += extras; i > Point; i--)
440 TTYback();
443 STATIC void
444 clear_line()
446 Point = -strlen(Prompt);
447 TTYput('\r');
448 ceol();
449 Point = 0;
450 End = 0;
451 Line[0] = '\0';
454 STATIC STATUS
455 insert_string(p)
456 CHAR *p;
458 SIZE_T len;
459 int i;
460 CHAR *new;
461 CHAR *q;
463 len = strlen((char *)p);
464 if (End + len >= Length) {
465 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
466 return CSstay;
467 if (Length) {
468 COPYFROMTO(new, Line, Length);
469 DISPOSE(Line);
471 Line = new;
472 Length += len + MEM_INC;
475 for (q = &Line[Point], i = End - Point; --i >= 0; )
476 q[len + i] = q[i];
477 COPYFROMTO(&Line[Point], p, len);
478 End += len;
479 Line[End] = '\0';
480 TTYstring(&Line[Point]);
481 Point += len;
483 return Point == End ? CSstay : CSmove;
486 STATIC STATUS
487 redisplay()
489 TTYputs((CONST CHAR *)NEWLINE);
490 TTYputs((CONST CHAR *)Prompt);
491 TTYstring(Line);
492 return CSmove;
495 STATIC STATUS
496 toggle_meta_mode()
498 rl_meta_chars = ! rl_meta_chars;
499 return redisplay();
503 STATIC CHAR *
504 next_hist()
506 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
509 STATIC CHAR *
510 prev_hist()
512 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
515 STATIC STATUS
516 do_insert_hist(p)
517 CHAR *p;
519 if (p == NULL)
520 return ring_bell();
521 Point = 0;
522 reposition();
523 ceol();
524 End = 0;
525 return insert_string(p);
528 STATIC STATUS
529 do_hist(move)
530 CHAR *(*move)();
532 CHAR *p;
533 int i;
535 i = 0;
536 do {
537 if ((p = (*move)()) == NULL)
538 return ring_bell();
539 } while (++i < Repeat);
540 return do_insert_hist(p);
543 STATIC STATUS
544 h_next()
546 return do_hist(next_hist);
549 STATIC STATUS
550 h_prev()
552 return do_hist(prev_hist);
555 STATIC STATUS
556 h_first()
558 return do_insert_hist(H.Lines[H.Pos = 0]);
561 STATIC STATUS
562 h_last()
564 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
568 ** Return zero if pat appears as a substring in text.
570 STATIC int
571 substrcmp(text, pat, len)
572 char *text;
573 char *pat;
574 int len;
576 char c;
578 if ((c = *pat) == '\0')
579 return *text == '\0';
580 for ( ; *text; text++)
581 if (*text == c && strncmp(text, pat, len) == 0)
582 return 0;
583 return 1;
586 STATIC CHAR *
587 search_hist(search, move)
588 CHAR *search;
589 CHAR *(*move)();
591 static CHAR *old_search;
592 int len;
593 int pos;
594 int (*match)();
595 char *pat;
597 /* Save or get remembered search pattern. */
598 if (search && *search) {
599 if (old_search)
600 DISPOSE(old_search);
601 old_search = (CHAR *)strdup((char *)search);
603 else {
604 if (old_search == NULL || *old_search == '\0')
605 return NULL;
606 search = old_search;
609 /* Set up pattern-finder. */
610 if (*search == '^') {
611 match = strncmp;
612 pat = (char *)(search + 1);
614 else {
615 match = substrcmp;
616 pat = (char *)search;
618 len = strlen(pat);
620 for (pos = H.Pos; (*move)() != NULL; )
621 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
622 return H.Lines[H.Pos];
623 H.Pos = pos;
624 return NULL;
627 STATIC STATUS
628 h_search()
630 static int Searching;
631 CONST char *old_prompt;
632 CHAR *(*move)();
633 CHAR *p;
635 if (Searching)
636 return ring_bell();
637 Searching = 1;
639 clear_line();
640 old_prompt = Prompt;
641 Prompt = "Search: ";
642 TTYputs((CONST CHAR *)Prompt);
643 move = Repeat == NO_ARG ? prev_hist : next_hist;
644 p = editinput();
645 Prompt = old_prompt;
646 Searching = 0;
647 TTYputs((CONST CHAR *)Prompt);
648 if (p == NULL && Signal > 0) {
649 Signal = 0;
650 clear_line();
651 return redisplay();
653 p = search_hist(p, move);
654 clear_line();
655 if (p == NULL) {
656 (void)ring_bell();
657 return redisplay();
659 return do_insert_hist(p);
662 STATIC STATUS
663 fd_char()
665 int i;
667 i = 0;
668 do {
669 if (Point >= End)
670 break;
671 right(CSmove);
672 } while (++i < Repeat);
673 return CSstay;
676 STATIC void
677 save_yank(begin, i)
678 int begin;
679 int i;
681 if (Yanked) {
682 DISPOSE(Yanked);
683 Yanked = NULL;
686 if (i < 1)
687 return;
689 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
690 COPYFROMTO(Yanked, &Line[begin], i);
691 Yanked[i] = '\0';
695 STATIC STATUS
696 delete_string(count)
697 int count;
699 int i;
700 CHAR *p;
702 if (count <= 0 || End == Point)
703 return ring_bell();
705 if (count == 1 && Point == End - 1) {
706 /* Optimize common case of delete at end of line. */
707 End--;
708 p = &Line[Point];
709 i = 1;
710 TTYput(' ');
711 if (ISCTL(*p)) {
712 i = 2;
713 TTYput(' ');
715 else if (rl_meta_chars && ISMETA(*p)) {
716 i = 3;
717 TTYput(' ');
718 TTYput(' ');
720 TTYbackn(i);
721 *p = '\0';
722 return CSmove;
724 if (Point + count > End && (count = End - Point) <= 0)
725 return CSstay;
727 if (count > 1)
728 save_yank(Point, count);
730 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
731 p[0] = p[count];
732 ceol();
733 End -= count;
734 TTYstring(&Line[Point]);
735 return CSmove;
738 STATIC STATUS
739 bk_char()
741 int i;
743 i = 0;
744 do {
745 if (Point == 0)
746 break;
747 left(CSmove);
748 } while (++i < Repeat);
750 return CSstay;
753 STATIC STATUS
754 bk_del_char()
756 int i;
758 i = 0;
759 do {
760 if (Point == 0)
761 break;
762 left(CSmove);
763 } while (++i < Repeat);
765 return delete_string(i);
768 STATIC STATUS
769 kill_line()
771 int i;
773 if (Repeat != NO_ARG) {
774 if (Repeat < Point) {
775 i = Point;
776 Point = Repeat;
777 reposition();
778 (void)delete_string(i - Point);
780 else if (Repeat > Point) {
781 right(CSmove);
782 (void)delete_string(Repeat - Point - 1);
784 return CSmove;
787 save_yank(Point, End - Point);
788 Line[Point] = '\0';
789 ceol();
790 End = Point;
791 return CSstay;
794 STATIC STATUS
795 insert_char(c)
796 int c;
798 STATUS s;
799 CHAR buff[2];
800 CHAR *p;
801 CHAR *q;
802 int i;
804 if (Repeat == NO_ARG || Repeat < 2) {
805 buff[0] = c;
806 buff[1] = '\0';
807 return insert_string(buff);
810 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
811 return CSstay;
812 for (i = Repeat, q = p; --i >= 0; )
813 *q++ = c;
814 *q = '\0';
815 Repeat = 0;
816 s = insert_string(p);
817 DISPOSE(p);
818 return s;
821 STATIC STATUS
822 meta()
824 unsigned int c;
825 KEYMAP *kp;
827 if ((c = TTYget()) == EOF)
828 return CSeof;
829 #if defined(ANSI_ARROWS)
830 /* Also include VT-100 arrows. */
831 if (c == '[' || c == 'O')
832 switch (c = TTYget()) {
833 default: return ring_bell();
834 case EOF: return CSeof;
835 case 'A': return h_prev();
836 case 'B': return h_next();
837 case 'C': return fd_char();
838 case 'D': return bk_char();
840 #endif /* defined(ANSI_ARROWS) */
842 if (isdigit(c)) {
843 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
844 Repeat = Repeat * 10 + c - '0';
845 Pushed = 1;
846 PushBack = c;
847 return CSstay;
850 if (isupper(c))
851 return do_macro(c);
852 for (kp = MetaMap; kp->Function; kp++)
853 if (kp->Key == c)
854 return (*kp->Function)();
856 return ring_bell();
859 STATIC STATUS
860 emacs(c)
861 unsigned int c;
863 STATUS s;
864 KEYMAP *kp;
866 OldPoint = Point;
867 if (rl_meta_chars && ISMETA(c)) {
868 Pushed = 1;
869 PushBack = UNMETA(c);
870 return meta();
872 for (kp = Map; kp->Function; kp++)
873 if (kp->Key == c)
874 break;
875 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
876 if (!Pushed)
877 /* No pushback means no repeat count; hacky, but true. */
878 Repeat = NO_ARG;
879 return s;
882 STATIC STATUS
883 TTYspecial(c)
884 unsigned int c;
886 if (ISMETA(c))
887 return CSdispatch;
889 if (c == rl_erase || c == DEL)
890 return bk_del_char();
891 if (c == rl_kill) {
892 if (Point != 0) {
893 Point = 0;
894 reposition();
896 Repeat = NO_ARG;
897 return kill_line();
899 if (c == rl_eof && Point == 0 && End == 0)
900 return CSeof;
901 if (c == rl_intr) {
902 Signal = SIGINT;
903 return CSsignal;
905 if (c == rl_quit) {
906 Signal = SIGQUIT;
907 return CSeof;
910 return CSdispatch;
913 STATIC CHAR *
914 editinput()
916 unsigned int c;
918 Repeat = NO_ARG;
919 OldPoint = Point = Mark = End = 0;
920 Line[0] = '\0';
922 Signal = -1;
923 while ((c = TTYget()) != EOF)
924 switch (TTYspecial(c)) {
925 case CSdone:
926 return Line;
927 case CSeof:
928 return NULL;
929 case CSsignal:
930 return (CHAR *)"";
931 case CSmove:
932 reposition();
933 break;
934 case CSdispatch:
935 switch (emacs(c)) {
936 case CSdone:
937 return Line;
938 case CSeof:
939 return NULL;
940 case CSsignal:
941 return (CHAR *)"";
942 case CSmove:
943 reposition();
944 break;
945 case CSdispatch:
946 case CSstay:
947 break;
949 break;
950 case CSstay:
951 break;
953 return NULL;
956 STATIC void
957 hist_add(p)
958 CHAR *p;
960 int i;
962 if ((p = (CHAR *)strdup((char *)p)) == NULL)
963 return;
964 if (H.Size < HIST_SIZE)
965 H.Lines[H.Size++] = p;
966 else {
967 DISPOSE(H.Lines[0]);
968 for (i = 0; i < HIST_SIZE - 1; i++)
969 H.Lines[i] = H.Lines[i + 1];
970 H.Lines[i] = p;
972 H.Pos = H.Size - 1;
976 ** For compatibility with FSF readline.
978 /* ARGSUSED0 */
979 void
980 rl_reset_terminal(p)
981 char *p;
985 void
986 rl_initialize()
990 char *
991 readline(prompt)
992 CONST char *prompt;
994 CHAR *line;
995 int s;
997 if (Line == NULL) {
998 Length = MEM_INC;
999 if ((Line = NEW(CHAR, Length)) == NULL)
1000 return NULL;
1003 TTYinfo();
1004 rl_ttyset(0);
1005 hist_add(NIL);
1006 ScreenSize = SCREEN_INC;
1007 Screen = NEW(char, ScreenSize);
1008 Prompt = prompt ? prompt : (char *)NIL;
1009 TTYputs((CONST CHAR *)Prompt);
1010 if ((line = editinput()) != NULL) {
1011 line = (CHAR *)strdup((char *)line);
1012 TTYputs((CHAR *)NEWLINE);
1013 TTYflush();
1015 rl_ttyset(1);
1016 DISPOSE(Screen);
1017 DISPOSE(H.Lines[--H.Size]);
1019 if (line != NULL && *line != '\0'
1020 #if defined(UNIQUE_HISTORY)
1021 && !(H.Pos && strcmp((char *) line, (char *) H.Lines[H.Pos - 1]) == 0)
1022 #endif /* defined(UNIQUE_HISTORY) */
1023 && !(H.Size && strcmp((char *) line, (char *) H.Lines[H.Size - 1]) == 0)
1025 hist_add(line);
1028 if (Signal > 0) {
1029 s = Signal;
1030 Signal = 0;
1031 (void)kill(getpid(), s);
1033 return (char *)line;
1036 void
1037 add_history(p)
1038 char *p;
1040 #ifdef obsolete /* Made part of readline(). -- kjb */
1041 if (p == NULL || *p == '\0')
1042 return;
1044 #if defined(UNIQUE_HISTORY)
1045 if (H.Pos && strcmp(p, (char *) H.Lines[H.Pos - 1]) == 0)
1046 return;
1047 #endif /* defined(UNIQUE_HISTORY) */
1048 if (H.Size && strcmp(p, (char *) H.Lines[H.Size - 1]) == 0)
1049 return;
1050 hist_add((CHAR *)p);
1051 #endif
1055 STATIC STATUS
1056 beg_line()
1058 if (Point) {
1059 Point = 0;
1060 return CSmove;
1062 return CSstay;
1065 STATIC STATUS
1066 del_char()
1068 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1071 STATIC STATUS
1072 end_line()
1074 if (Point != End) {
1075 Point = End;
1076 return CSmove;
1078 return CSstay;
1081 STATIC char SEPS[] = "\"#$&'()*:;<=>?[\\]^`{|}~\n\t ";
1084 ** Move back to the beginning of the current word and return an
1085 ** allocated copy of it.
1087 STATIC CHAR *
1088 find_word()
1090 CHAR *p, *q;
1091 CHAR *new;
1092 SIZE_T len;
1094 p = &Line[Point];
1095 while (p > Line) {
1096 p--;
1097 if (p > Line && p[-1] == '\\') {
1098 p--;
1099 } else {
1100 if (strchr(SEPS, (char) *p) != NULL) {
1101 p++;
1102 break;
1106 len = Point - (p - Line) + 1;
1107 if ((new = NEW(CHAR, len)) == NULL)
1108 return NULL;
1109 q = new;
1110 while (p < &Line[Point]) {
1111 if (*p == '\\') {
1112 if (++p == &Line[Point]) break;
1114 *q++ = *p++;
1116 *q = '\0';
1117 return new;
1120 STATIC STATUS
1121 c_possible()
1123 CHAR **av;
1124 CHAR *word;
1125 int ac;
1127 word = find_word();
1128 ac = rl_list_possib((char *)word, (char ***)&av);
1129 if (word)
1130 DISPOSE(word);
1131 if (ac) {
1132 columns(ac, av);
1133 while (--ac >= 0)
1134 DISPOSE(av[ac]);
1135 DISPOSE(av);
1136 return CSmove;
1138 return ring_bell();
1141 STATIC STATUS
1142 c_complete()
1144 CHAR *p, *q;
1145 CHAR *word, *new;
1146 SIZE_T len;
1147 int unique;
1148 STATUS s;
1150 word = find_word();
1151 p = (CHAR *)rl_complete((char *)word, &unique);
1152 if (word)
1153 DISPOSE(word);
1154 if (p) {
1155 len = strlen((char *)p);
1156 word = p;
1157 new = q = NEW(CHAR, 2 * len + 1);
1158 while (*p) {
1159 if ((*p < ' ' || strchr(SEPS, (char) *p) != NULL)
1160 && (!unique || p[1] != 0)) {
1161 *q++ = '\\';
1163 *q++ = *p++;
1165 *q = '\0';
1166 DISPOSE(word);
1167 if (len > 0) {
1168 s = insert_string(new);
1169 #if ANNOYING_NOISE
1170 if (!unique)
1171 (void)ring_bell();
1172 #endif
1174 DISPOSE(new);
1175 if (len > 0) return s;
1177 return c_possible();
1180 STATIC STATUS
1181 accept_line()
1183 Line[End] = '\0';
1184 return CSdone;
1187 STATIC STATUS
1188 transpose()
1190 CHAR c;
1192 if (Point) {
1193 if (Point == End)
1194 left(CSmove);
1195 c = Line[Point - 1];
1196 left(CSstay);
1197 Line[Point - 1] = Line[Point];
1198 TTYshow(Line[Point - 1]);
1199 Line[Point++] = c;
1200 TTYshow(c);
1202 return CSstay;
1205 STATIC STATUS
1206 quote()
1208 unsigned int c;
1210 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1213 STATIC STATUS
1214 wipe()
1216 int i;
1218 if (Mark > End)
1219 return ring_bell();
1221 if (Point > Mark) {
1222 i = Point;
1223 Point = Mark;
1224 Mark = i;
1225 reposition();
1228 return delete_string(Mark - Point);
1231 STATIC STATUS
1232 mk_set()
1234 Mark = Point;
1235 return CSstay;
1238 STATIC STATUS
1239 exchange()
1241 unsigned int c;
1243 if ((c = TTYget()) != CTL('X'))
1244 return c == EOF ? CSeof : ring_bell();
1246 if ((c = Mark) <= End) {
1247 Mark = Point;
1248 Point = c;
1249 return CSmove;
1251 return CSstay;
1254 STATIC STATUS
1255 yank()
1257 if (Yanked && *Yanked)
1258 return insert_string(Yanked);
1259 return CSstay;
1262 STATIC STATUS
1263 copy_region()
1265 if (Mark > End)
1266 return ring_bell();
1268 if (Point > Mark)
1269 save_yank(Mark, Point - Mark);
1270 else
1271 save_yank(Point, Mark - Point);
1273 return CSstay;
1276 STATIC STATUS
1277 move_to_char()
1279 unsigned int c;
1280 int i;
1281 CHAR *p;
1283 if ((c = TTYget()) == EOF)
1284 return CSeof;
1285 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1286 if (*p == c) {
1287 Point = i;
1288 return CSmove;
1290 return CSstay;
1293 STATIC STATUS
1294 fd_word()
1296 return do_forward(CSmove);
1299 STATIC STATUS
1300 fd_kill_word()
1302 int i;
1304 (void)do_forward(CSstay);
1305 if (OldPoint != Point) {
1306 i = Point - OldPoint;
1307 Point = OldPoint;
1308 return delete_string(i);
1310 return CSstay;
1313 STATIC STATUS
1314 bk_word()
1316 int i;
1317 CHAR *p;
1319 i = 0;
1320 do {
1321 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1322 left(CSmove);
1324 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1325 left(CSmove);
1327 if (Point == 0)
1328 break;
1329 } while (++i < Repeat);
1331 return CSstay;
1334 STATIC STATUS
1335 bk_kill_word()
1337 (void)bk_word();
1338 if (OldPoint != Point)
1339 return delete_string(OldPoint - Point);
1340 return CSstay;
1343 STATIC int
1344 argify(line, avp)
1345 CHAR *line;
1346 CHAR ***avp;
1348 CHAR *c;
1349 CHAR **p;
1350 CHAR **new;
1351 int ac;
1352 int i;
1354 i = MEM_INC;
1355 if ((*avp = p = NEW(CHAR*, i))== NULL)
1356 return 0;
1358 for (c = line; isspace(*c); c++)
1359 continue;
1360 if (*c == '\n' || *c == '\0')
1361 return 0;
1363 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1364 if (isspace(*c)) {
1365 *c++ = '\0';
1366 if (*c && *c != '\n') {
1367 if (ac + 1 == i) {
1368 new = NEW(CHAR*, i + MEM_INC);
1369 if (new == NULL) {
1370 p[ac] = NULL;
1371 return ac;
1373 COPYFROMTO(new, p, i * sizeof (char **));
1374 i += MEM_INC;
1375 DISPOSE(p);
1376 *avp = p = new;
1378 p[ac++] = c;
1381 else
1382 c++;
1384 *c = '\0';
1385 p[ac] = NULL;
1386 return ac;
1389 STATIC STATUS
1390 last_argument()
1392 CHAR **av;
1393 CHAR *p;
1394 STATUS s;
1395 int ac;
1397 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1398 return ring_bell();
1400 if ((p = (CHAR *)strdup((char *)p)) == NULL)
1401 return CSstay;
1402 ac = argify(p, &av);
1404 if (Repeat != NO_ARG)
1405 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1406 else
1407 s = ac ? insert_string(av[ac - 1]) : CSstay;
1409 if (ac)
1410 DISPOSE(av);
1411 DISPOSE(p);
1412 return s;
1415 STATIC KEYMAP Map[33] = {
1416 { CTL('@'), mk_set },
1417 { CTL('A'), beg_line },
1418 { CTL('B'), bk_char },
1419 { CTL('D'), del_char },
1420 { CTL('E'), end_line },
1421 { CTL('F'), fd_char },
1422 { CTL('G'), ring_bell },
1423 { CTL('H'), bk_del_char },
1424 { CTL('I'), c_complete },
1425 { CTL('J'), accept_line },
1426 { CTL('K'), kill_line },
1427 { CTL('L'), redisplay },
1428 { CTL('M'), accept_line },
1429 { CTL('N'), h_next },
1430 { CTL('O'), ring_bell },
1431 { CTL('P'), h_prev },
1432 { CTL('Q'), ring_bell },
1433 { CTL('R'), h_search },
1434 { CTL('S'), ring_bell },
1435 { CTL('T'), transpose },
1436 { CTL('U'), ring_bell },
1437 { CTL('V'), quote },
1438 { CTL('W'), bk_kill_word },
1439 { CTL('X'), exchange },
1440 { CTL('Y'), yank },
1441 { CTL('Z'), end_line },
1442 { CTL('['), meta },
1443 { CTL(']'), move_to_char },
1444 { CTL('^'), ring_bell },
1445 { CTL('_'), ring_bell },
1446 { 0, NULL }
1449 STATIC KEYMAP MetaMap[17]= {
1450 { CTL('H'), wipe },
1451 { DEL, wipe },
1452 { ' ', mk_set },
1453 { '.', last_argument },
1454 { '<', h_first },
1455 { '>', h_last },
1456 { '?', c_possible },
1457 { 'b', bk_word },
1458 { 'd', fd_kill_word },
1459 { 'f', fd_word },
1460 { 'l', case_down_word },
1461 { 'm', toggle_meta_mode },
1462 { 'u', case_up_word },
1463 { 'y', yank },
1464 { 'w', copy_region },
1465 { 0, NULL }
1469 * $PchId: editline.c,v 1.4 1996/02/22 21:16:56 philip Exp $