libutil: add O_NOCTTY back to old pty open code
[minix.git] / lib / libedit / editline.c
blobfeda30b34fb679a323a8cce43380786d667385ab
1 /*
2 ** Main editing routines for editline library.
3 */
4 #include "editline.h"
5 #include <signal.h>
6 #include <errno.h>
7 #include <ctype.h>
8 #include <termcap.h>
9 #include <unistd.h>
12 ** Manifest constants.
14 #define SCREEN_WIDTH 80
15 #define SCREEN_ROWS 24
16 #define NO_ARG (-1)
17 #define DEL 127
18 #define CTL(x) ((x) & 0x1F)
19 #define ISCTL(x) ((x) && (x) < ' ')
20 #define UNCTL(x) ((x) + 64)
21 #define META(x) ((x) | 0x80)
22 #define ISMETA(x) ((x) & 0x80)
23 #define UNMETA(x) ((x) & 0x7F)
24 #if !defined(HIST_SIZE)
25 #define HIST_SIZE 20
26 #endif /* !defined(HIST_SIZE) */
29 ** Command status codes.
31 typedef enum _STATUS {
32 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
33 } STATUS;
36 ** The type of case-changing to perform.
38 typedef enum _CASE {
39 TOupper, TOlower
40 } CASE;
43 ** Key to command mapping.
45 typedef struct _KEYMAP {
46 CHAR Key;
47 STATUS (*Function)();
48 } KEYMAP;
51 ** Command history structure.
53 typedef struct _HISTORY {
54 int Size;
55 int Pos;
56 CHAR *Lines[HIST_SIZE];
57 } HISTORY;
60 ** Globals.
62 int rl_eof;
63 int rl_erase;
64 int rl_intr;
65 int rl_kill;
66 int rl_quit;
68 STATIC CHAR NIL[] = "";
69 STATIC CONST CHAR *Input = NIL;
70 STATIC CHAR *Line;
71 STATIC CONST char *Prompt;
72 STATIC CHAR *Yanked;
73 STATIC char *Screen;
74 STATIC char NEWLINE[]= CRLF;
75 STATIC HISTORY H;
76 STATIC int Repeat;
77 STATIC int End;
78 STATIC int Mark;
79 STATIC int OldPoint;
80 STATIC int Point;
81 STATIC int PushBack;
82 STATIC int Pushed;
83 STATIC int Signal;
84 static KEYMAP Map[33];
85 static KEYMAP MetaMap[17];
86 STATIC SIZE_T Length;
87 STATIC SIZE_T ScreenCount;
88 STATIC SIZE_T ScreenSize;
89 STATIC char *backspace;
90 STATIC int TTYwidth;
91 STATIC int TTYrows;
93 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
94 int rl_meta_chars = 0;
97 ** Declarations.
99 STATIC CHAR *editinput();
100 #if defined(USE_TERMCAP)
101 extern char *tgetstr();
102 extern int tgetent();
103 #endif /* defined(USE_TERMCAP) */
106 ** TTY input/output functions.
109 STATIC void
110 TTYflush()
112 if (ScreenCount) {
113 (void)write(1, Screen, ScreenCount);
114 ScreenCount = 0;
118 STATIC void
119 TTYput(c)
120 CHAR c;
122 Screen[ScreenCount] = c;
123 if (++ScreenCount >= ScreenSize - 1) {
124 ScreenSize += SCREEN_INC;
125 RENEW(Screen, char, ScreenSize);
129 STATIC void
130 TTYputs(p)
131 CHAR *p;
133 while (*p)
134 TTYput(*p++);
137 STATIC void
138 TTYshow(c)
139 CHAR c;
141 if (c == DEL) {
142 TTYput('^');
143 TTYput('?');
145 else if (ISCTL(c)) {
146 TTYput('^');
147 TTYput(UNCTL(c));
149 else if (rl_meta_chars && ISMETA(c)) {
150 TTYput('M');
151 TTYput('-');
152 TTYput(UNMETA(c));
154 else
155 TTYput(c);
158 STATIC void
159 TTYstring(p)
160 CHAR *p;
162 while (*p)
163 TTYshow(*p++);
166 STATIC unsigned int
167 TTYget()
169 CHAR c;
170 int r;
172 TTYflush();
173 if (Pushed) {
174 Pushed = 0;
175 return PushBack;
177 if (*Input)
178 return *Input++;
181 r= read(0, &c, (SIZE_T)1);
182 } while (r == -1 && errno == EINTR);
183 return r == 1 ? c : EOF;
186 #define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
188 STATIC void
189 TTYbackn(n)
190 int n;
192 while (--n >= 0)
193 TTYback();
196 STATIC void
197 TTYinfo()
199 static int init;
200 #if defined(USE_TERMCAP)
201 char *term;
202 char buff[2048];
203 char *bp;
204 #endif /* defined(USE_TERMCAP) */
205 #if defined(TIOCGWINSZ)
206 struct winsize W;
207 #endif /* defined(TIOCGWINSZ) */
209 if (init) {
210 #if defined(TIOCGWINSZ)
211 /* Perhaps we got resized. */
212 if (ioctl(0, TIOCGWINSZ, &W) >= 0
213 && W.ws_col > 0 && W.ws_row > 0) {
214 TTYwidth = (int)W.ws_col;
215 TTYrows = (int)W.ws_row;
217 #endif /* defined(TIOCGWINSZ) */
218 return;
220 init++;
222 TTYwidth = TTYrows = 0;
223 #if defined(USE_TERMCAP)
224 bp = &buff[0];
225 if ((term = getenv("TERM")) == NULL)
226 term = "dumb";
227 if (tgetent(buff, term) < 0) {
228 TTYwidth = SCREEN_WIDTH;
229 TTYrows = SCREEN_ROWS;
230 return;
232 if ((backspace = tgetstr("le", &bp)) != NULL)
233 backspace = strdup(backspace);
234 TTYwidth = tgetnum("co");
235 TTYrows = tgetnum("li");
236 #endif /* defined(USE_TERMCAP) */
238 #if defined(TIOCGWINSZ)
239 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
240 TTYwidth = (int)W.ws_col;
241 TTYrows = (int)W.ws_row;
243 #endif /* defined(TIOCGWINSZ) */
245 if (TTYwidth <= 0 || TTYrows <= 0) {
246 TTYwidth = SCREEN_WIDTH;
247 TTYrows = SCREEN_ROWS;
253 ** Print an array of words in columns.
255 STATIC void
256 columns(ac, av)
257 int ac;
258 CHAR **av;
260 CHAR *p;
261 int i;
262 int j;
263 int k;
264 int len;
265 int skip;
266 int longest;
267 int cols;
269 /* Find longest name, determine column count from that. */
270 for (longest = 0, i = 0; i < ac; i++)
271 if ((j = strlen((char *)av[i])) > longest)
272 longest = j;
273 cols = TTYwidth / (longest + 3);
275 TTYputs((CHAR *)NEWLINE);
276 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
277 for (j = i; j < ac; j += skip) {
278 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
279 TTYput(*p);
280 if (j + skip < ac)
281 while (++len < longest + 3)
282 TTYput(' ');
284 TTYputs((CHAR *)NEWLINE);
288 STATIC void
289 reposition()
291 int i;
292 CHAR *p;
294 TTYput('\r');
295 TTYputs((CHAR *)Prompt);
296 for (i = Point, p = Line; --i >= 0; p++)
297 TTYshow(*p);
300 STATIC void
301 left(Change)
302 STATUS Change;
304 TTYback();
305 if (Point) {
306 if (ISCTL(Line[Point - 1]))
307 TTYback();
308 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
309 TTYback();
310 TTYback();
313 if (Change == CSmove)
314 Point--;
317 STATIC void
318 right(Change)
319 STATUS Change;
321 TTYshow(Line[Point]);
322 if (Change == CSmove)
323 Point++;
326 STATIC STATUS
327 ring_bell()
329 TTYput('\07');
330 TTYflush();
331 return CSstay;
334 STATIC STATUS
335 do_macro(c)
336 unsigned int c;
338 CHAR name[4];
340 name[0] = '_';
341 name[1] = c;
342 name[2] = '_';
343 name[3] = '\0';
345 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
346 Input = NIL;
347 return ring_bell();
349 return CSstay;
352 STATIC STATUS
353 do_forward(move)
354 STATUS move;
356 int i;
357 CHAR *p;
359 i = 0;
360 do {
361 p = &Line[Point];
362 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
363 if (move == CSmove)
364 right(CSstay);
366 for (; Point < End && isalnum(*p); Point++, p++)
367 if (move == CSmove)
368 right(CSstay);
370 if (Point == End)
371 break;
372 } while (++i < Repeat);
374 return CSstay;
377 STATIC STATUS
378 do_case(type)
379 CASE type;
381 int i;
382 int end;
383 int count;
384 CHAR *p;
386 (void)do_forward(CSstay);
387 if (OldPoint != Point) {
388 if ((count = Point - OldPoint) < 0)
389 count = -count;
390 Point = OldPoint;
391 if ((end = Point + count) > End)
392 end = End;
393 for (i = Point, p = &Line[i]; i < end; i++, p++) {
394 if (type == TOupper) {
395 if (islower(*p))
396 *p = toupper(*p);
398 else if (isupper(*p))
399 *p = tolower(*p);
400 right(CSmove);
403 return CSstay;
406 STATIC STATUS
407 case_down_word()
409 return do_case(TOlower);
412 STATIC STATUS
413 case_up_word()
415 return do_case(TOupper);
418 STATIC void
419 ceol()
421 int extras;
422 int i;
423 CHAR *p;
425 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
426 TTYput(' ');
427 if (ISCTL(*p)) {
428 TTYput(' ');
429 extras++;
431 else if (rl_meta_chars && ISMETA(*p)) {
432 TTYput(' ');
433 TTYput(' ');
434 extras += 2;
438 for (i += extras; i > Point; i--)
439 TTYback();
442 STATIC void
443 clear_line()
445 Point = -strlen(Prompt);
446 TTYput('\r');
447 ceol();
448 Point = 0;
449 End = 0;
450 Line[0] = '\0';
453 STATIC STATUS
454 insert_string(p)
455 CHAR *p;
457 SIZE_T len;
458 int i;
459 CHAR *new;
460 CHAR *q;
462 len = strlen((char *)p);
463 if (End + len >= Length) {
464 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
465 return CSstay;
466 if (Length) {
467 COPYFROMTO(new, Line, Length);
468 DISPOSE(Line);
470 Line = new;
471 Length += len + MEM_INC;
474 for (q = &Line[Point], i = End - Point; --i >= 0; )
475 q[len + i] = q[i];
476 COPYFROMTO(&Line[Point], p, len);
477 End += len;
478 Line[End] = '\0';
479 TTYstring(&Line[Point]);
480 Point += len;
482 return Point == End ? CSstay : CSmove;
485 STATIC STATUS
486 redisplay()
488 TTYputs((CHAR *) NEWLINE);
489 TTYputs((CHAR *)Prompt);
490 TTYstring(Line);
491 return CSmove;
494 STATIC STATUS
495 toggle_meta_mode()
497 rl_meta_chars = ! rl_meta_chars;
498 return redisplay();
502 STATIC CHAR *
503 next_hist()
505 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
508 STATIC CHAR *
509 prev_hist()
511 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
514 STATIC STATUS
515 do_insert_hist(p)
516 CHAR *p;
518 if (p == NULL)
519 return ring_bell();
520 Point = 0;
521 reposition();
522 ceol();
523 End = 0;
524 return insert_string(p);
527 STATIC STATUS
528 do_hist(move)
529 CHAR *(*move)();
531 CHAR *p;
532 int i;
534 i = 0;
535 do {
536 if ((p = (*move)()) == NULL)
537 return ring_bell();
538 } while (++i < Repeat);
539 return do_insert_hist(p);
542 STATIC STATUS
543 h_next()
545 return do_hist(next_hist);
548 STATIC STATUS
549 h_prev()
551 return do_hist(prev_hist);
554 STATIC STATUS
555 h_first()
557 return do_insert_hist(H.Lines[H.Pos = 0]);
560 STATIC STATUS
561 h_last()
563 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
567 ** Return zero if pat appears as a substring in text.
569 STATIC int
570 substrcmp(text, pat, len)
571 char *text;
572 char *pat;
573 int len;
575 char c;
577 if ((c = *pat) == '\0')
578 return *text == '\0';
579 for ( ; *text; text++)
580 if (*text == c && strncmp(text, pat, len) == 0)
581 return 0;
582 return 1;
585 STATIC CHAR *
586 search_hist(search, move)
587 CHAR *search;
588 CHAR *(*move)();
590 static CHAR *old_search;
591 int len;
592 int pos;
593 int (*match)();
594 char *pat;
596 /* Save or get remembered search pattern. */
597 if (search && *search) {
598 if (old_search)
599 DISPOSE(old_search);
600 old_search = (CHAR *)strdup((char *)search);
602 else {
603 if (old_search == NULL || *old_search == '\0')
604 return NULL;
605 search = old_search;
608 /* Set up pattern-finder. */
609 if (*search == '^') {
610 match = strncmp;
611 pat = (char *)(search + 1);
613 else {
614 match = substrcmp;
615 pat = (char *)search;
617 len = strlen(pat);
619 for (pos = H.Pos; (*move)() != NULL; )
620 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
621 return H.Lines[H.Pos];
622 H.Pos = pos;
623 return NULL;
626 STATIC STATUS
627 h_search()
629 static int Searching;
630 CONST char *old_prompt;
631 CHAR *(*move)();
632 CHAR *p;
634 if (Searching)
635 return ring_bell();
636 Searching = 1;
638 clear_line();
639 old_prompt = Prompt;
640 Prompt = "Search: ";
641 TTYputs((CHAR *)Prompt);
642 move = Repeat == NO_ARG ? prev_hist : next_hist;
643 p = editinput();
644 Prompt = old_prompt;
645 Searching = 0;
646 TTYputs((CHAR *)Prompt);
647 if (p == NULL && Signal > 0) {
648 Signal = 0;
649 clear_line();
650 return redisplay();
652 p = search_hist(p, move);
653 clear_line();
654 if (p == NULL) {
655 (void)ring_bell();
656 return redisplay();
658 return do_insert_hist(p);
661 STATIC STATUS
662 fd_char()
664 int i;
666 i = 0;
667 do {
668 if (Point >= End)
669 break;
670 right(CSmove);
671 } while (++i < Repeat);
672 return CSstay;
675 STATIC void
676 save_yank(begin, i)
677 int begin;
678 int i;
680 if (Yanked) {
681 DISPOSE(Yanked);
682 Yanked = NULL;
685 if (i < 1)
686 return;
688 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
689 COPYFROMTO(Yanked, &Line[begin], i);
690 Yanked[i] = '\0';
694 STATIC STATUS
695 delete_string(count)
696 int count;
698 int i;
699 CHAR *p;
701 if (count <= 0 || End == Point)
702 return ring_bell();
704 if (count == 1 && Point == End - 1) {
705 /* Optimize common case of delete at end of line. */
706 End--;
707 p = &Line[Point];
708 i = 1;
709 TTYput(' ');
710 if (ISCTL(*p)) {
711 i = 2;
712 TTYput(' ');
714 else if (rl_meta_chars && ISMETA(*p)) {
715 i = 3;
716 TTYput(' ');
717 TTYput(' ');
719 TTYbackn(i);
720 *p = '\0';
721 return CSmove;
723 if (Point + count > End && (count = End - Point) <= 0)
724 return CSstay;
726 if (count > 1)
727 save_yank(Point, count);
729 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
730 p[0] = p[count];
731 ceol();
732 End -= count;
733 TTYstring(&Line[Point]);
734 return CSmove;
737 STATIC STATUS
738 bk_char()
740 int i;
742 i = 0;
743 do {
744 if (Point == 0)
745 break;
746 left(CSmove);
747 } while (++i < Repeat);
749 return CSstay;
752 STATIC STATUS
753 bk_del_char()
755 int i;
757 i = 0;
758 do {
759 if (Point == 0)
760 break;
761 left(CSmove);
762 } while (++i < Repeat);
764 return delete_string(i);
767 STATIC STATUS
768 kill_line()
770 int i;
772 if (Repeat != NO_ARG) {
773 if (Repeat < Point) {
774 i = Point;
775 Point = Repeat;
776 reposition();
777 (void)delete_string(i - Point);
779 else if (Repeat > Point) {
780 right(CSmove);
781 (void)delete_string(Repeat - Point - 1);
783 return CSmove;
786 save_yank(Point, End - Point);
787 Line[Point] = '\0';
788 ceol();
789 End = Point;
790 return CSstay;
793 STATIC STATUS
794 insert_char(c)
795 int c;
797 STATUS s;
798 CHAR buff[2];
799 CHAR *p;
800 CHAR *q;
801 int i;
803 if (Repeat == NO_ARG || Repeat < 2) {
804 buff[0] = c;
805 buff[1] = '\0';
806 return insert_string(buff);
809 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
810 return CSstay;
811 for (i = Repeat, q = p; --i >= 0; )
812 *q++ = c;
813 *q = '\0';
814 Repeat = 0;
815 s = insert_string(p);
816 DISPOSE(p);
817 return s;
820 STATIC STATUS
821 meta()
823 unsigned int c;
824 KEYMAP *kp;
826 if ((c = TTYget()) == EOF)
827 return CSeof;
828 #if defined(ANSI_ARROWS)
829 /* Also include VT-100 arrows. */
830 if (c == '[' || c == 'O')
831 switch (c = TTYget()) {
832 default: return ring_bell();
833 case EOF: return CSeof;
834 case 'A': return h_prev();
835 case 'B': return h_next();
836 case 'C': return fd_char();
837 case 'D': return bk_char();
839 #endif /* defined(ANSI_ARROWS) */
841 if (isdigit(c)) {
842 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
843 Repeat = Repeat * 10 + c - '0';
844 Pushed = 1;
845 PushBack = c;
846 return CSstay;
849 if (isupper(c))
850 return do_macro(c);
851 for (kp = MetaMap; kp->Function; kp++)
852 if (kp->Key == c)
853 return (*kp->Function)();
855 return ring_bell();
858 STATIC STATUS
859 emacs(c)
860 unsigned int c;
862 STATUS s;
863 KEYMAP *kp;
865 OldPoint = Point;
866 if (rl_meta_chars && ISMETA(c)) {
867 Pushed = 1;
868 PushBack = UNMETA(c);
869 return meta();
871 for (kp = Map; kp->Function; kp++)
872 if (kp->Key == c)
873 break;
874 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
875 if (!Pushed)
876 /* No pushback means no repeat count; hacky, but true. */
877 Repeat = NO_ARG;
878 return s;
881 STATIC STATUS
882 TTYspecial(c)
883 unsigned int c;
885 if (ISMETA(c))
886 return CSdispatch;
888 if (c == rl_erase || c == DEL)
889 return bk_del_char();
890 if (c == rl_kill) {
891 if (Point != 0) {
892 Point = 0;
893 reposition();
895 Repeat = NO_ARG;
896 return kill_line();
898 if (c == rl_eof && Point == 0 && End == 0)
899 return CSeof;
900 if (c == rl_intr) {
901 Signal = SIGINT;
902 return CSsignal;
904 if (c == rl_quit) {
905 Signal = SIGQUIT;
906 return CSeof;
909 return CSdispatch;
912 STATIC CHAR *
913 editinput()
915 unsigned int c;
917 Repeat = NO_ARG;
918 OldPoint = Point = Mark = End = 0;
919 Line[0] = '\0';
921 Signal = -1;
922 while ((c = TTYget()) != EOF)
923 switch (TTYspecial(c)) {
924 case CSdone:
925 return Line;
926 case CSeof:
927 return NULL;
928 case CSsignal:
929 return (CHAR *)"";
930 case CSmove:
931 reposition();
932 break;
933 case CSdispatch:
934 switch (emacs(c)) {
935 case CSdone:
936 return Line;
937 case CSeof:
938 return NULL;
939 case CSsignal:
940 return (CHAR *)"";
941 case CSmove:
942 reposition();
943 break;
944 case CSdispatch:
945 case CSstay:
946 break;
948 break;
949 case CSstay:
950 break;
952 return NULL;
955 STATIC void
956 hist_add(p)
957 CHAR *p;
959 int i;
961 if ((p = (CHAR *)strdup((char *)p)) == NULL)
962 return;
963 if (H.Size < HIST_SIZE)
964 H.Lines[H.Size++] = p;
965 else {
966 DISPOSE(H.Lines[0]);
967 for (i = 0; i < HIST_SIZE - 1; i++)
968 H.Lines[i] = H.Lines[i + 1];
969 H.Lines[i] = p;
971 H.Pos = H.Size - 1;
975 ** For compatibility with FSF readline.
977 /* ARGSUSED0 */
978 void
979 rl_reset_terminal(p)
980 char *p;
984 void
985 rl_initialize()
989 char *
990 readline(prompt)
991 CONST char *prompt;
993 CHAR *line;
994 int s;
996 if (Line == NULL) {
997 Length = MEM_INC;
998 if ((Line = NEW(CHAR, Length)) == NULL)
999 return NULL;
1002 TTYinfo();
1003 rl_ttyset(0);
1004 hist_add(NIL);
1005 ScreenSize = SCREEN_INC;
1006 Screen = NEW(char, ScreenSize);
1007 Prompt = prompt ? prompt : (char *)NIL;
1008 TTYputs((CHAR *)Prompt);
1009 if ((line = editinput()) != NULL) {
1010 line = (CHAR *)strdup((char *)line);
1011 TTYputs((CHAR *)NEWLINE);
1012 TTYflush();
1014 rl_ttyset(1);
1015 DISPOSE(Screen);
1016 DISPOSE(H.Lines[--H.Size]);
1018 if (line != NULL && *line != '\0'
1019 #if defined(UNIQUE_HISTORY)
1020 && !(H.Pos && strcmp((char *) line, (char *) H.Lines[H.Pos - 1]) == 0)
1021 #endif /* defined(UNIQUE_HISTORY) */
1022 && !(H.Size && strcmp((char *) line, (char *) H.Lines[H.Size - 1]) == 0)
1024 hist_add(line);
1027 if (Signal > 0) {
1028 s = Signal;
1029 Signal = 0;
1030 (void)kill(getpid(), s);
1032 return (char *)line;
1035 void
1036 add_history(p)
1037 char *p;
1039 #ifdef obsolete /* Made part of readline(). -- kjb */
1040 if (p == NULL || *p == '\0')
1041 return;
1043 #if defined(UNIQUE_HISTORY)
1044 if (H.Pos && strcmp(p, (char *) H.Lines[H.Pos - 1]) == 0)
1045 return;
1046 #endif /* defined(UNIQUE_HISTORY) */
1047 if (H.Size && strcmp(p, (char *) H.Lines[H.Size - 1]) == 0)
1048 return;
1049 hist_add((CHAR *)p);
1050 #endif
1054 STATIC STATUS
1055 beg_line()
1057 if (Point) {
1058 Point = 0;
1059 return CSmove;
1061 return CSstay;
1064 STATIC STATUS
1065 del_char()
1067 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1070 STATIC STATUS
1071 end_line()
1073 if (Point != End) {
1074 Point = End;
1075 return CSmove;
1077 return CSstay;
1080 STATIC char SEPS[] = "\"#$&'()*:;<=>?[\\]^`{|}~\n\t ";
1083 ** Move back to the beginning of the current word and return an
1084 ** allocated copy of it.
1086 STATIC CHAR *
1087 find_word()
1089 CHAR *p, *q;
1090 CHAR *new;
1091 SIZE_T len;
1093 p = &Line[Point];
1094 while (p > Line) {
1095 p--;
1096 if (p > Line && p[-1] == '\\') {
1097 p--;
1098 } else {
1099 if (strchr(SEPS, (char) *p) != NULL) {
1100 p++;
1101 break;
1105 len = Point - (p - Line) + 1;
1106 if ((new = NEW(CHAR, len)) == NULL)
1107 return NULL;
1108 q = new;
1109 while (p < &Line[Point]) {
1110 if (*p == '\\') {
1111 if (++p == &Line[Point]) break;
1113 *q++ = *p++;
1115 *q = '\0';
1116 return new;
1119 STATIC STATUS
1120 c_possible()
1122 CHAR **av;
1123 CHAR *word;
1124 int ac;
1126 word = find_word();
1127 ac = rl_list_possib((char *)word, (char ***)&av);
1128 if (word)
1129 DISPOSE(word);
1130 if (ac) {
1131 columns(ac, av);
1132 while (--ac >= 0)
1133 DISPOSE(av[ac]);
1134 DISPOSE(av);
1135 return CSmove;
1137 return ring_bell();
1140 STATIC STATUS
1141 c_complete()
1143 CHAR *p, *q;
1144 CHAR *word, *new;
1145 SIZE_T len;
1146 int unique;
1147 STATUS s;
1149 word = find_word();
1150 p = (CHAR *)rl_complete((char *)word, &unique);
1151 if (word)
1152 DISPOSE(word);
1153 if (p) {
1154 len = strlen((char *)p);
1155 word = p;
1156 new = q = NEW(CHAR, 2 * len + 1);
1157 while (*p) {
1158 if ((*p < ' ' || strchr(SEPS, (char) *p) != NULL)
1159 && (!unique || p[1] != 0)) {
1160 *q++ = '\\';
1162 *q++ = *p++;
1164 *q = '\0';
1165 DISPOSE(word);
1166 if (len > 0) {
1167 s = insert_string(new);
1168 #if ANNOYING_NOISE
1169 if (!unique)
1170 (void)ring_bell();
1171 #endif
1173 DISPOSE(new);
1174 if (len > 0) return s;
1176 return c_possible();
1179 STATIC STATUS
1180 accept_line()
1182 Line[End] = '\0';
1183 return CSdone;
1186 STATIC STATUS
1187 transpose()
1189 CHAR c;
1191 if (Point) {
1192 if (Point == End)
1193 left(CSmove);
1194 c = Line[Point - 1];
1195 left(CSstay);
1196 Line[Point - 1] = Line[Point];
1197 TTYshow(Line[Point - 1]);
1198 Line[Point++] = c;
1199 TTYshow(c);
1201 return CSstay;
1204 STATIC STATUS
1205 quote()
1207 unsigned int c;
1209 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1212 STATIC STATUS
1213 wipe()
1215 int i;
1217 if (Mark > End)
1218 return ring_bell();
1220 if (Point > Mark) {
1221 i = Point;
1222 Point = Mark;
1223 Mark = i;
1224 reposition();
1227 return delete_string(Mark - Point);
1230 STATIC STATUS
1231 mk_set()
1233 Mark = Point;
1234 return CSstay;
1237 STATIC STATUS
1238 exchange()
1240 unsigned int c;
1242 if ((c = TTYget()) != CTL('X'))
1243 return c == EOF ? CSeof : ring_bell();
1245 if ((c = Mark) <= End) {
1246 Mark = Point;
1247 Point = c;
1248 return CSmove;
1250 return CSstay;
1253 STATIC STATUS
1254 yank()
1256 if (Yanked && *Yanked)
1257 return insert_string(Yanked);
1258 return CSstay;
1261 STATIC STATUS
1262 copy_region()
1264 if (Mark > End)
1265 return ring_bell();
1267 if (Point > Mark)
1268 save_yank(Mark, Point - Mark);
1269 else
1270 save_yank(Point, Mark - Point);
1272 return CSstay;
1275 STATIC STATUS
1276 move_to_char()
1278 unsigned int c;
1279 int i;
1280 CHAR *p;
1282 if ((c = TTYget()) == EOF)
1283 return CSeof;
1284 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1285 if (*p == c) {
1286 Point = i;
1287 return CSmove;
1289 return CSstay;
1292 STATIC STATUS
1293 fd_word()
1295 return do_forward(CSmove);
1298 STATIC STATUS
1299 fd_kill_word()
1301 int i;
1303 (void)do_forward(CSstay);
1304 if (OldPoint != Point) {
1305 i = Point - OldPoint;
1306 Point = OldPoint;
1307 return delete_string(i);
1309 return CSstay;
1312 STATIC STATUS
1313 bk_word()
1315 int i;
1316 CHAR *p;
1318 i = 0;
1319 do {
1320 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1321 left(CSmove);
1323 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1324 left(CSmove);
1326 if (Point == 0)
1327 break;
1328 } while (++i < Repeat);
1330 return CSstay;
1333 STATIC STATUS
1334 bk_kill_word()
1336 (void)bk_word();
1337 if (OldPoint != Point)
1338 return delete_string(OldPoint - Point);
1339 return CSstay;
1342 STATIC int
1343 argify(line, avp)
1344 CHAR *line;
1345 CHAR ***avp;
1347 CHAR *c;
1348 CHAR **p;
1349 CHAR **new;
1350 int ac;
1351 int i;
1353 i = MEM_INC;
1354 if ((*avp = p = NEW(CHAR*, i))== NULL)
1355 return 0;
1357 for (c = line; isspace(*c); c++)
1358 continue;
1359 if (*c == '\n' || *c == '\0')
1360 return 0;
1362 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1363 if (isspace(*c)) {
1364 *c++ = '\0';
1365 if (*c && *c != '\n') {
1366 if (ac + 1 == i) {
1367 new = NEW(CHAR*, i + MEM_INC);
1368 if (new == NULL) {
1369 p[ac] = NULL;
1370 return ac;
1372 COPYFROMTO(new, p, i * sizeof (char **));
1373 i += MEM_INC;
1374 DISPOSE(p);
1375 *avp = p = new;
1377 p[ac++] = c;
1380 else
1381 c++;
1383 *c = '\0';
1384 p[ac] = NULL;
1385 return ac;
1388 STATIC STATUS
1389 last_argument()
1391 CHAR **av;
1392 CHAR *p;
1393 STATUS s;
1394 int ac;
1396 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1397 return ring_bell();
1399 if ((p = (CHAR *)strdup((char *)p)) == NULL)
1400 return CSstay;
1401 ac = argify(p, &av);
1403 if (Repeat != NO_ARG)
1404 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1405 else
1406 s = ac ? insert_string(av[ac - 1]) : CSstay;
1408 if (ac)
1409 DISPOSE(av);
1410 DISPOSE(p);
1411 return s;
1414 STATIC KEYMAP Map[33] = {
1415 { CTL('@'), mk_set },
1416 { CTL('A'), beg_line },
1417 { CTL('B'), bk_char },
1418 { CTL('D'), del_char },
1419 { CTL('E'), end_line },
1420 { CTL('F'), fd_char },
1421 { CTL('G'), ring_bell },
1422 { CTL('H'), bk_del_char },
1423 { CTL('I'), c_complete },
1424 { CTL('J'), accept_line },
1425 { CTL('K'), kill_line },
1426 { CTL('L'), redisplay },
1427 { CTL('M'), accept_line },
1428 { CTL('N'), h_next },
1429 { CTL('O'), ring_bell },
1430 { CTL('P'), h_prev },
1431 { CTL('Q'), ring_bell },
1432 { CTL('R'), h_search },
1433 { CTL('S'), ring_bell },
1434 { CTL('T'), transpose },
1435 { CTL('U'), ring_bell },
1436 { CTL('V'), quote },
1437 { CTL('W'), bk_kill_word },
1438 { CTL('X'), exchange },
1439 { CTL('Y'), yank },
1440 { CTL('Z'), end_line },
1441 { CTL('['), meta },
1442 { CTL(']'), move_to_char },
1443 { CTL('^'), ring_bell },
1444 { CTL('_'), ring_bell },
1445 { 0, NULL }
1448 STATIC KEYMAP MetaMap[17]= {
1449 { CTL('H'), wipe },
1450 { DEL, wipe },
1451 { ' ', mk_set },
1452 { '.', last_argument },
1453 { '<', h_first },
1454 { '>', h_last },
1455 { '?', c_possible },
1456 { 'b', bk_word },
1457 { 'd', fd_kill_word },
1458 { 'f', fd_word },
1459 { 'l', case_down_word },
1460 { 'm', toggle_meta_mode },
1461 { 'u', case_up_word },
1462 { 'y', yank },
1463 { 'w', copy_region },
1464 { 0, NULL }
1468 * $PchId: editline.c,v 1.4 1996/02/22 21:16:56 philip Exp $