Fixes for /usr/xbin binaries bootstrap dir.
[minix3.git] / lib / editline / editline.c
blobb17be01d1bbd61418fbb6871dbdcab286782fee6
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 *getenv();
103 extern char *tgetstr();
104 extern int tgetent();
105 #endif /* defined(USE_TERMCAP) */
108 ** TTY input/output functions.
111 STATIC void
112 TTYflush()
114 if (ScreenCount) {
115 (void)write(1, Screen, ScreenCount);
116 ScreenCount = 0;
120 STATIC void
121 TTYput(c)
122 CHAR c;
124 Screen[ScreenCount] = c;
125 if (++ScreenCount >= ScreenSize - 1) {
126 ScreenSize += SCREEN_INC;
127 RENEW(Screen, char, ScreenSize);
131 STATIC void
132 TTYputs(p)
133 CHAR *p;
135 while (*p)
136 TTYput(*p++);
139 STATIC void
140 TTYshow(c)
141 CHAR c;
143 if (c == DEL) {
144 TTYput('^');
145 TTYput('?');
147 else if (ISCTL(c)) {
148 TTYput('^');
149 TTYput(UNCTL(c));
151 else if (rl_meta_chars && ISMETA(c)) {
152 TTYput('M');
153 TTYput('-');
154 TTYput(UNMETA(c));
156 else
157 TTYput(c);
160 STATIC void
161 TTYstring(p)
162 CHAR *p;
164 while (*p)
165 TTYshow(*p++);
168 STATIC unsigned int
169 TTYget()
171 CHAR c;
172 int r;
174 TTYflush();
175 if (Pushed) {
176 Pushed = 0;
177 return PushBack;
179 if (*Input)
180 return *Input++;
183 r= read(0, &c, (SIZE_T)1);
184 } while (r == -1 && errno == EINTR);
185 return r == 1 ? c : EOF;
188 #define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
190 STATIC void
191 TTYbackn(n)
192 int n;
194 while (--n >= 0)
195 TTYback();
198 STATIC void
199 TTYinfo()
201 static int init;
202 #if defined(USE_TERMCAP)
203 char *term;
204 char buff[2048];
205 char *bp;
206 #endif /* defined(USE_TERMCAP) */
207 #if defined(TIOCGWINSZ)
208 struct winsize W;
209 #endif /* defined(TIOCGWINSZ) */
211 if (init) {
212 #if defined(TIOCGWINSZ)
213 /* Perhaps we got resized. */
214 if (ioctl(0, TIOCGWINSZ, &W) >= 0
215 && W.ws_col > 0 && W.ws_row > 0) {
216 TTYwidth = (int)W.ws_col;
217 TTYrows = (int)W.ws_row;
219 #endif /* defined(TIOCGWINSZ) */
220 return;
222 init++;
224 TTYwidth = TTYrows = 0;
225 #if defined(USE_TERMCAP)
226 bp = &buff[0];
227 if ((term = getenv("TERM")) == NULL)
228 term = "dumb";
229 if (tgetent(buff, term) < 0) {
230 TTYwidth = SCREEN_WIDTH;
231 TTYrows = SCREEN_ROWS;
232 return;
234 if ((backspace = tgetstr("le", &bp)) != NULL)
235 backspace = strdup(backspace);
236 TTYwidth = tgetnum("co");
237 TTYrows = tgetnum("li");
238 #endif /* defined(USE_TERMCAP) */
240 #if defined(TIOCGWINSZ)
241 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
242 TTYwidth = (int)W.ws_col;
243 TTYrows = (int)W.ws_row;
245 #endif /* defined(TIOCGWINSZ) */
247 if (TTYwidth <= 0 || TTYrows <= 0) {
248 TTYwidth = SCREEN_WIDTH;
249 TTYrows = SCREEN_ROWS;
255 ** Print an array of words in columns.
257 STATIC void
258 columns(ac, av)
259 int ac;
260 CHAR **av;
262 CHAR *p;
263 int i;
264 int j;
265 int k;
266 int len;
267 int skip;
268 int longest;
269 int cols;
271 /* Find longest name, determine column count from that. */
272 for (longest = 0, i = 0; i < ac; i++)
273 if ((j = strlen((char *)av[i])) > longest)
274 longest = j;
275 cols = TTYwidth / (longest + 3);
277 TTYputs((CHAR *)NEWLINE);
278 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
279 for (j = i; j < ac; j += skip) {
280 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
281 TTYput(*p);
282 if (j + skip < ac)
283 while (++len < longest + 3)
284 TTYput(' ');
286 TTYputs((CHAR *)NEWLINE);
290 STATIC void
291 reposition()
293 int i;
294 CHAR *p;
296 TTYput('\r');
297 TTYputs((CONST CHAR *)Prompt);
298 for (i = Point, p = Line; --i >= 0; p++)
299 TTYshow(*p);
302 STATIC void
303 left(Change)
304 STATUS Change;
306 TTYback();
307 if (Point) {
308 if (ISCTL(Line[Point - 1]))
309 TTYback();
310 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
311 TTYback();
312 TTYback();
315 if (Change == CSmove)
316 Point--;
319 STATIC void
320 right(Change)
321 STATUS Change;
323 TTYshow(Line[Point]);
324 if (Change == CSmove)
325 Point++;
328 STATIC STATUS
329 ring_bell()
331 TTYput('\07');
332 TTYflush();
333 return CSstay;
336 STATIC STATUS
337 do_macro(c)
338 unsigned int c;
340 CHAR name[4];
342 name[0] = '_';
343 name[1] = c;
344 name[2] = '_';
345 name[3] = '\0';
347 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
348 Input = NIL;
349 return ring_bell();
351 return CSstay;
354 STATIC STATUS
355 do_forward(move)
356 STATUS move;
358 int i;
359 CHAR *p;
361 i = 0;
362 do {
363 p = &Line[Point];
364 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
365 if (move == CSmove)
366 right(CSstay);
368 for (; Point < End && isalnum(*p); Point++, p++)
369 if (move == CSmove)
370 right(CSstay);
372 if (Point == End)
373 break;
374 } while (++i < Repeat);
376 return CSstay;
379 STATIC STATUS
380 do_case(type)
381 CASE type;
383 int i;
384 int end;
385 int count;
386 CHAR *p;
388 (void)do_forward(CSstay);
389 if (OldPoint != Point) {
390 if ((count = Point - OldPoint) < 0)
391 count = -count;
392 Point = OldPoint;
393 if ((end = Point + count) > End)
394 end = End;
395 for (i = Point, p = &Line[i]; i < end; i++, p++) {
396 if (type == TOupper) {
397 if (islower(*p))
398 *p = toupper(*p);
400 else if (isupper(*p))
401 *p = tolower(*p);
402 right(CSmove);
405 return CSstay;
408 STATIC STATUS
409 case_down_word()
411 return do_case(TOlower);
414 STATIC STATUS
415 case_up_word()
417 return do_case(TOupper);
420 STATIC void
421 ceol()
423 int extras;
424 int i;
425 CHAR *p;
427 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
428 TTYput(' ');
429 if (ISCTL(*p)) {
430 TTYput(' ');
431 extras++;
433 else if (rl_meta_chars && ISMETA(*p)) {
434 TTYput(' ');
435 TTYput(' ');
436 extras += 2;
440 for (i += extras; i > Point; i--)
441 TTYback();
444 STATIC void
445 clear_line()
447 Point = -strlen(Prompt);
448 TTYput('\r');
449 ceol();
450 Point = 0;
451 End = 0;
452 Line[0] = '\0';
455 STATIC STATUS
456 insert_string(p)
457 CHAR *p;
459 SIZE_T len;
460 int i;
461 CHAR *new;
462 CHAR *q;
464 len = strlen((char *)p);
465 if (End + len >= Length) {
466 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
467 return CSstay;
468 if (Length) {
469 COPYFROMTO(new, Line, Length);
470 DISPOSE(Line);
472 Line = new;
473 Length += len + MEM_INC;
476 for (q = &Line[Point], i = End - Point; --i >= 0; )
477 q[len + i] = q[i];
478 COPYFROMTO(&Line[Point], p, len);
479 End += len;
480 Line[End] = '\0';
481 TTYstring(&Line[Point]);
482 Point += len;
484 return Point == End ? CSstay : CSmove;
487 STATIC STATUS
488 redisplay()
490 TTYputs((CONST CHAR *)NEWLINE);
491 TTYputs((CONST CHAR *)Prompt);
492 TTYstring(Line);
493 return CSmove;
496 STATIC STATUS
497 toggle_meta_mode()
499 rl_meta_chars = ! rl_meta_chars;
500 return redisplay();
504 STATIC CHAR *
505 next_hist()
507 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
510 STATIC CHAR *
511 prev_hist()
513 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
516 STATIC STATUS
517 do_insert_hist(p)
518 CHAR *p;
520 if (p == NULL)
521 return ring_bell();
522 Point = 0;
523 reposition();
524 ceol();
525 End = 0;
526 return insert_string(p);
529 STATIC STATUS
530 do_hist(move)
531 CHAR *(*move)();
533 CHAR *p;
534 int i;
536 i = 0;
537 do {
538 if ((p = (*move)()) == NULL)
539 return ring_bell();
540 } while (++i < Repeat);
541 return do_insert_hist(p);
544 STATIC STATUS
545 h_next()
547 return do_hist(next_hist);
550 STATIC STATUS
551 h_prev()
553 return do_hist(prev_hist);
556 STATIC STATUS
557 h_first()
559 return do_insert_hist(H.Lines[H.Pos = 0]);
562 STATIC STATUS
563 h_last()
565 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
569 ** Return zero if pat appears as a substring in text.
571 STATIC int
572 substrcmp(text, pat, len)
573 char *text;
574 char *pat;
575 int len;
577 char c;
579 if ((c = *pat) == '\0')
580 return *text == '\0';
581 for ( ; *text; text++)
582 if (*text == c && strncmp(text, pat, len) == 0)
583 return 0;
584 return 1;
587 STATIC CHAR *
588 search_hist(search, move)
589 CHAR *search;
590 CHAR *(*move)();
592 static CHAR *old_search;
593 int len;
594 int pos;
595 int (*match)();
596 char *pat;
598 /* Save or get remembered search pattern. */
599 if (search && *search) {
600 if (old_search)
601 DISPOSE(old_search);
602 old_search = (CHAR *)strdup((char *)search);
604 else {
605 if (old_search == NULL || *old_search == '\0')
606 return NULL;
607 search = old_search;
610 /* Set up pattern-finder. */
611 if (*search == '^') {
612 match = strncmp;
613 pat = (char *)(search + 1);
615 else {
616 match = substrcmp;
617 pat = (char *)search;
619 len = strlen(pat);
621 for (pos = H.Pos; (*move)() != NULL; )
622 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
623 return H.Lines[H.Pos];
624 H.Pos = pos;
625 return NULL;
628 STATIC STATUS
629 h_search()
631 static int Searching;
632 CONST char *old_prompt;
633 CHAR *(*move)();
634 CHAR *p;
636 if (Searching)
637 return ring_bell();
638 Searching = 1;
640 clear_line();
641 old_prompt = Prompt;
642 Prompt = "Search: ";
643 TTYputs((CONST CHAR *)Prompt);
644 move = Repeat == NO_ARG ? prev_hist : next_hist;
645 p = editinput();
646 Prompt = old_prompt;
647 Searching = 0;
648 TTYputs((CONST CHAR *)Prompt);
649 if (p == NULL && Signal > 0) {
650 Signal = 0;
651 clear_line();
652 return redisplay();
654 p = search_hist(p, move);
655 clear_line();
656 if (p == NULL) {
657 (void)ring_bell();
658 return redisplay();
660 return do_insert_hist(p);
663 STATIC STATUS
664 fd_char()
666 int i;
668 i = 0;
669 do {
670 if (Point >= End)
671 break;
672 right(CSmove);
673 } while (++i < Repeat);
674 return CSstay;
677 STATIC void
678 save_yank(begin, i)
679 int begin;
680 int i;
682 if (Yanked) {
683 DISPOSE(Yanked);
684 Yanked = NULL;
687 if (i < 1)
688 return;
690 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
691 COPYFROMTO(Yanked, &Line[begin], i);
692 Yanked[i] = '\0';
696 STATIC STATUS
697 delete_string(count)
698 int count;
700 int i;
701 CHAR *p;
703 if (count <= 0 || End == Point)
704 return ring_bell();
706 if (count == 1 && Point == End - 1) {
707 /* Optimize common case of delete at end of line. */
708 End--;
709 p = &Line[Point];
710 i = 1;
711 TTYput(' ');
712 if (ISCTL(*p)) {
713 i = 2;
714 TTYput(' ');
716 else if (rl_meta_chars && ISMETA(*p)) {
717 i = 3;
718 TTYput(' ');
719 TTYput(' ');
721 TTYbackn(i);
722 *p = '\0';
723 return CSmove;
725 if (Point + count > End && (count = End - Point) <= 0)
726 return CSstay;
728 if (count > 1)
729 save_yank(Point, count);
731 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
732 p[0] = p[count];
733 ceol();
734 End -= count;
735 TTYstring(&Line[Point]);
736 return CSmove;
739 STATIC STATUS
740 bk_char()
742 int i;
744 i = 0;
745 do {
746 if (Point == 0)
747 break;
748 left(CSmove);
749 } while (++i < Repeat);
751 return CSstay;
754 STATIC STATUS
755 bk_del_char()
757 int i;
759 i = 0;
760 do {
761 if (Point == 0)
762 break;
763 left(CSmove);
764 } while (++i < Repeat);
766 return delete_string(i);
769 STATIC STATUS
770 kill_line()
772 int i;
774 if (Repeat != NO_ARG) {
775 if (Repeat < Point) {
776 i = Point;
777 Point = Repeat;
778 reposition();
779 (void)delete_string(i - Point);
781 else if (Repeat > Point) {
782 right(CSmove);
783 (void)delete_string(Repeat - Point - 1);
785 return CSmove;
788 save_yank(Point, End - Point);
789 Line[Point] = '\0';
790 ceol();
791 End = Point;
792 return CSstay;
795 STATIC STATUS
796 insert_char(c)
797 int c;
799 STATUS s;
800 CHAR buff[2];
801 CHAR *p;
802 CHAR *q;
803 int i;
805 if (Repeat == NO_ARG || Repeat < 2) {
806 buff[0] = c;
807 buff[1] = '\0';
808 return insert_string(buff);
811 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
812 return CSstay;
813 for (i = Repeat, q = p; --i >= 0; )
814 *q++ = c;
815 *q = '\0';
816 Repeat = 0;
817 s = insert_string(p);
818 DISPOSE(p);
819 return s;
822 STATIC STATUS
823 meta()
825 unsigned int c;
826 KEYMAP *kp;
828 if ((c = TTYget()) == EOF)
829 return CSeof;
830 #if defined(ANSI_ARROWS)
831 /* Also include VT-100 arrows. */
832 if (c == '[' || c == 'O')
833 switch (c = TTYget()) {
834 default: return ring_bell();
835 case EOF: return CSeof;
836 case 'A': return h_prev();
837 case 'B': return h_next();
838 case 'C': return fd_char();
839 case 'D': return bk_char();
841 #endif /* defined(ANSI_ARROWS) */
843 if (isdigit(c)) {
844 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
845 Repeat = Repeat * 10 + c - '0';
846 Pushed = 1;
847 PushBack = c;
848 return CSstay;
851 if (isupper(c))
852 return do_macro(c);
853 for (kp = MetaMap; kp->Function; kp++)
854 if (kp->Key == c)
855 return (*kp->Function)();
857 return ring_bell();
860 STATIC STATUS
861 emacs(c)
862 unsigned int c;
864 STATUS s;
865 KEYMAP *kp;
867 OldPoint = Point;
868 if (rl_meta_chars && ISMETA(c)) {
869 Pushed = 1;
870 PushBack = UNMETA(c);
871 return meta();
873 for (kp = Map; kp->Function; kp++)
874 if (kp->Key == c)
875 break;
876 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
877 if (!Pushed)
878 /* No pushback means no repeat count; hacky, but true. */
879 Repeat = NO_ARG;
880 return s;
883 STATIC STATUS
884 TTYspecial(c)
885 unsigned int c;
887 if (ISMETA(c))
888 return CSdispatch;
890 if (c == rl_erase || c == DEL)
891 return bk_del_char();
892 if (c == rl_kill) {
893 if (Point != 0) {
894 Point = 0;
895 reposition();
897 Repeat = NO_ARG;
898 return kill_line();
900 if (c == rl_eof && Point == 0 && End == 0)
901 return CSeof;
902 if (c == rl_intr) {
903 Signal = SIGINT;
904 return CSsignal;
906 if (c == rl_quit) {
907 Signal = SIGQUIT;
908 return CSeof;
911 return CSdispatch;
914 STATIC CHAR *
915 editinput()
917 unsigned int c;
919 Repeat = NO_ARG;
920 OldPoint = Point = Mark = End = 0;
921 Line[0] = '\0';
923 Signal = -1;
924 while ((c = TTYget()) != EOF)
925 switch (TTYspecial(c)) {
926 case CSdone:
927 return Line;
928 case CSeof:
929 return NULL;
930 case CSsignal:
931 return (CHAR *)"";
932 case CSmove:
933 reposition();
934 break;
935 case CSdispatch:
936 switch (emacs(c)) {
937 case CSdone:
938 return Line;
939 case CSeof:
940 return NULL;
941 case CSsignal:
942 return (CHAR *)"";
943 case CSmove:
944 reposition();
945 break;
946 case CSdispatch:
947 case CSstay:
948 break;
950 break;
951 case CSstay:
952 break;
954 return NULL;
957 STATIC void
958 hist_add(p)
959 CHAR *p;
961 int i;
963 if ((p = (CHAR *)strdup((char *)p)) == NULL)
964 return;
965 if (H.Size < HIST_SIZE)
966 H.Lines[H.Size++] = p;
967 else {
968 DISPOSE(H.Lines[0]);
969 for (i = 0; i < HIST_SIZE - 1; i++)
970 H.Lines[i] = H.Lines[i + 1];
971 H.Lines[i] = p;
973 H.Pos = H.Size - 1;
977 ** For compatibility with FSF readline.
979 /* ARGSUSED0 */
980 void
981 rl_reset_terminal(p)
982 char *p;
986 void
987 rl_initialize()
991 char *
992 readline(prompt)
993 CONST char *prompt;
995 CHAR *line;
996 int s;
998 if (Line == NULL) {
999 Length = MEM_INC;
1000 if ((Line = NEW(CHAR, Length)) == NULL)
1001 return NULL;
1004 TTYinfo();
1005 rl_ttyset(0);
1006 hist_add(NIL);
1007 ScreenSize = SCREEN_INC;
1008 Screen = NEW(char, ScreenSize);
1009 Prompt = prompt ? prompt : (char *)NIL;
1010 TTYputs((CONST CHAR *)Prompt);
1011 if ((line = editinput()) != NULL) {
1012 line = (CHAR *)strdup((char *)line);
1013 TTYputs((CHAR *)NEWLINE);
1014 TTYflush();
1016 rl_ttyset(1);
1017 DISPOSE(Screen);
1018 DISPOSE(H.Lines[--H.Size]);
1020 if (line != NULL && *line != '\0'
1021 #if defined(UNIQUE_HISTORY)
1022 && !(H.Pos && strcmp((char *) line, (char *) H.Lines[H.Pos - 1]) == 0)
1023 #endif /* defined(UNIQUE_HISTORY) */
1024 && !(H.Size && strcmp((char *) line, (char *) H.Lines[H.Size - 1]) == 0)
1026 hist_add(line);
1029 if (Signal > 0) {
1030 s = Signal;
1031 Signal = 0;
1032 (void)kill(getpid(), s);
1034 return (char *)line;
1037 void
1038 add_history(p)
1039 char *p;
1041 #ifdef obsolete /* Made part of readline(). -- kjb */
1042 if (p == NULL || *p == '\0')
1043 return;
1045 #if defined(UNIQUE_HISTORY)
1046 if (H.Pos && strcmp(p, (char *) H.Lines[H.Pos - 1]) == 0)
1047 return;
1048 #endif /* defined(UNIQUE_HISTORY) */
1049 if (H.Size && strcmp(p, (char *) H.Lines[H.Size - 1]) == 0)
1050 return;
1051 hist_add((CHAR *)p);
1052 #endif
1056 STATIC STATUS
1057 beg_line()
1059 if (Point) {
1060 Point = 0;
1061 return CSmove;
1063 return CSstay;
1066 STATIC STATUS
1067 del_char()
1069 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1072 STATIC STATUS
1073 end_line()
1075 if (Point != End) {
1076 Point = End;
1077 return CSmove;
1079 return CSstay;
1082 STATIC char SEPS[] = "\"#$&'()*:;<=>?[\\]^`{|}~\n\t ";
1085 ** Move back to the beginning of the current word and return an
1086 ** allocated copy of it.
1088 STATIC CHAR *
1089 find_word()
1091 CHAR *p, *q;
1092 CHAR *new;
1093 SIZE_T len;
1095 p = &Line[Point];
1096 while (p > Line) {
1097 p--;
1098 if (p > Line && p[-1] == '\\') {
1099 p--;
1100 } else {
1101 if (strchr(SEPS, (char) *p) != NULL) {
1102 p++;
1103 break;
1107 len = Point - (p - Line) + 1;
1108 if ((new = NEW(CHAR, len)) == NULL)
1109 return NULL;
1110 q = new;
1111 while (p < &Line[Point]) {
1112 if (*p == '\\') {
1113 if (++p == &Line[Point]) break;
1115 *q++ = *p++;
1117 *q = '\0';
1118 return new;
1121 STATIC STATUS
1122 c_possible()
1124 CHAR **av;
1125 CHAR *word;
1126 int ac;
1128 word = find_word();
1129 ac = rl_list_possib((char *)word, (char ***)&av);
1130 if (word)
1131 DISPOSE(word);
1132 if (ac) {
1133 columns(ac, av);
1134 while (--ac >= 0)
1135 DISPOSE(av[ac]);
1136 DISPOSE(av);
1137 return CSmove;
1139 return ring_bell();
1142 STATIC STATUS
1143 c_complete()
1145 CHAR *p, *q;
1146 CHAR *word, *new;
1147 SIZE_T len;
1148 int unique;
1149 STATUS s;
1151 word = find_word();
1152 p = (CHAR *)rl_complete((char *)word, &unique);
1153 if (word)
1154 DISPOSE(word);
1155 if (p) {
1156 len = strlen((char *)p);
1157 word = p;
1158 new = q = NEW(CHAR, 2 * len + 1);
1159 while (*p) {
1160 if ((*p < ' ' || strchr(SEPS, (char) *p) != NULL)
1161 && (!unique || p[1] != 0)) {
1162 *q++ = '\\';
1164 *q++ = *p++;
1166 *q = '\0';
1167 DISPOSE(word);
1168 if (len > 0) {
1169 s = insert_string(new);
1170 #if ANNOYING_NOISE
1171 if (!unique)
1172 (void)ring_bell();
1173 #endif
1175 DISPOSE(new);
1176 if (len > 0) return s;
1178 return c_possible();
1181 STATIC STATUS
1182 accept_line()
1184 Line[End] = '\0';
1185 return CSdone;
1188 STATIC STATUS
1189 transpose()
1191 CHAR c;
1193 if (Point) {
1194 if (Point == End)
1195 left(CSmove);
1196 c = Line[Point - 1];
1197 left(CSstay);
1198 Line[Point - 1] = Line[Point];
1199 TTYshow(Line[Point - 1]);
1200 Line[Point++] = c;
1201 TTYshow(c);
1203 return CSstay;
1206 STATIC STATUS
1207 quote()
1209 unsigned int c;
1211 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1214 STATIC STATUS
1215 wipe()
1217 int i;
1219 if (Mark > End)
1220 return ring_bell();
1222 if (Point > Mark) {
1223 i = Point;
1224 Point = Mark;
1225 Mark = i;
1226 reposition();
1229 return delete_string(Mark - Point);
1232 STATIC STATUS
1233 mk_set()
1235 Mark = Point;
1236 return CSstay;
1239 STATIC STATUS
1240 exchange()
1242 unsigned int c;
1244 if ((c = TTYget()) != CTL('X'))
1245 return c == EOF ? CSeof : ring_bell();
1247 if ((c = Mark) <= End) {
1248 Mark = Point;
1249 Point = c;
1250 return CSmove;
1252 return CSstay;
1255 STATIC STATUS
1256 yank()
1258 if (Yanked && *Yanked)
1259 return insert_string(Yanked);
1260 return CSstay;
1263 STATIC STATUS
1264 copy_region()
1266 if (Mark > End)
1267 return ring_bell();
1269 if (Point > Mark)
1270 save_yank(Mark, Point - Mark);
1271 else
1272 save_yank(Point, Mark - Point);
1274 return CSstay;
1277 STATIC STATUS
1278 move_to_char()
1280 unsigned int c;
1281 int i;
1282 CHAR *p;
1284 if ((c = TTYget()) == EOF)
1285 return CSeof;
1286 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1287 if (*p == c) {
1288 Point = i;
1289 return CSmove;
1291 return CSstay;
1294 STATIC STATUS
1295 fd_word()
1297 return do_forward(CSmove);
1300 STATIC STATUS
1301 fd_kill_word()
1303 int i;
1305 (void)do_forward(CSstay);
1306 if (OldPoint != Point) {
1307 i = Point - OldPoint;
1308 Point = OldPoint;
1309 return delete_string(i);
1311 return CSstay;
1314 STATIC STATUS
1315 bk_word()
1317 int i;
1318 CHAR *p;
1320 i = 0;
1321 do {
1322 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1323 left(CSmove);
1325 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1326 left(CSmove);
1328 if (Point == 0)
1329 break;
1330 } while (++i < Repeat);
1332 return CSstay;
1335 STATIC STATUS
1336 bk_kill_word()
1338 (void)bk_word();
1339 if (OldPoint != Point)
1340 return delete_string(OldPoint - Point);
1341 return CSstay;
1344 STATIC int
1345 argify(line, avp)
1346 CHAR *line;
1347 CHAR ***avp;
1349 CHAR *c;
1350 CHAR **p;
1351 CHAR **new;
1352 int ac;
1353 int i;
1355 i = MEM_INC;
1356 if ((*avp = p = NEW(CHAR*, i))== NULL)
1357 return 0;
1359 for (c = line; isspace(*c); c++)
1360 continue;
1361 if (*c == '\n' || *c == '\0')
1362 return 0;
1364 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1365 if (isspace(*c)) {
1366 *c++ = '\0';
1367 if (*c && *c != '\n') {
1368 if (ac + 1 == i) {
1369 new = NEW(CHAR*, i + MEM_INC);
1370 if (new == NULL) {
1371 p[ac] = NULL;
1372 return ac;
1374 COPYFROMTO(new, p, i * sizeof (char **));
1375 i += MEM_INC;
1376 DISPOSE(p);
1377 *avp = p = new;
1379 p[ac++] = c;
1382 else
1383 c++;
1385 *c = '\0';
1386 p[ac] = NULL;
1387 return ac;
1390 STATIC STATUS
1391 last_argument()
1393 CHAR **av;
1394 CHAR *p;
1395 STATUS s;
1396 int ac;
1398 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1399 return ring_bell();
1401 if ((p = (CHAR *)strdup((char *)p)) == NULL)
1402 return CSstay;
1403 ac = argify(p, &av);
1405 if (Repeat != NO_ARG)
1406 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1407 else
1408 s = ac ? insert_string(av[ac - 1]) : CSstay;
1410 if (ac)
1411 DISPOSE(av);
1412 DISPOSE(p);
1413 return s;
1416 STATIC KEYMAP Map[33] = {
1417 { CTL('@'), mk_set },
1418 { CTL('A'), beg_line },
1419 { CTL('B'), bk_char },
1420 { CTL('D'), del_char },
1421 { CTL('E'), end_line },
1422 { CTL('F'), fd_char },
1423 { CTL('G'), ring_bell },
1424 { CTL('H'), bk_del_char },
1425 { CTL('I'), c_complete },
1426 { CTL('J'), accept_line },
1427 { CTL('K'), kill_line },
1428 { CTL('L'), redisplay },
1429 { CTL('M'), accept_line },
1430 { CTL('N'), h_next },
1431 { CTL('O'), ring_bell },
1432 { CTL('P'), h_prev },
1433 { CTL('Q'), ring_bell },
1434 { CTL('R'), h_search },
1435 { CTL('S'), ring_bell },
1436 { CTL('T'), transpose },
1437 { CTL('U'), ring_bell },
1438 { CTL('V'), quote },
1439 { CTL('W'), bk_kill_word },
1440 { CTL('X'), exchange },
1441 { CTL('Y'), yank },
1442 { CTL('Z'), end_line },
1443 { CTL('['), meta },
1444 { CTL(']'), move_to_char },
1445 { CTL('^'), ring_bell },
1446 { CTL('_'), ring_bell },
1447 { 0, NULL }
1450 STATIC KEYMAP MetaMap[17]= {
1451 { CTL('H'), wipe },
1452 { DEL, wipe },
1453 { ' ', mk_set },
1454 { '.', last_argument },
1455 { '<', h_first },
1456 { '>', h_last },
1457 { '?', c_possible },
1458 { 'b', bk_word },
1459 { 'd', fd_kill_word },
1460 { 'f', fd_word },
1461 { 'l', case_down_word },
1462 { 'm', toggle_meta_mode },
1463 { 'u', case_up_word },
1464 { 'y', yank },
1465 { 'w', copy_region },
1466 { 0, NULL }
1470 * $PchId: editline.c,v 1.4 1996/02/22 21:16:56 philip Exp $