doxygen
[heimdal.git] / lib / editline / editline.c
blob23987f38840bd1eaa3f8d7ee226ac8dd660cf48f
1 /* Copyright 1992 Simmule Turner and Rich Salz. All rights reserved.
3 * This software is not subject to any license of the American Telephone
4 * and Telegraph Company or of the Regents of the University of California.
6 * Permission is granted to anyone to use this software for any purpose on
7 * any computer system, and to alter it and redistribute it freely, subject
8 * to the following restrictions:
9 * 1. The authors are not responsible for the consequences of use of this
10 * software, no matter how awful, even if they arise from flaws in it.
11 * 2. The origin of this software must not be misrepresented, either by
12 * explicit claim or by omission. Since few users ever read sources,
13 * credits must appear in the documentation.
14 * 3. Altered versions must be plainly marked as such, and must not be
15 * misrepresented as being the original software. Since few users
16 * ever read sources, credits must appear in the documentation.
17 * 4. This notice may not be removed or altered.
21 ** Main editing routines for editline library.
23 #include <config.h>
24 #include "edit_locl.h"
25 #include <ctype.h>
26 #include <errno.h>
28 RCSID("$Id$");
31 ** Manifest constants.
33 #define SCREEN_WIDTH 80
34 #define SCREEN_ROWS 24
35 #define NO_ARG (-1)
36 #define DEL 127
37 #define CTL(x) ((x) & 0x1F)
38 #define ISCTL(x) ((x) && (x) < ' ')
39 #define UNCTL(x) ((x) + 64)
40 #define META(x) ((x) | 0x80)
41 #define ISMETA(x) ((x) & 0x80)
42 #define UNMETA(x) ((x) & 0x7F)
43 #if !defined(HIST_SIZE)
44 #define HIST_SIZE 20
45 #endif /* !defined(HIST_SIZE) */
48 ** Command status codes.
50 typedef enum _el_STATUS {
51 CSdone, CSeof, CSmove, CSdispatch, CSstay
52 } el_STATUS;
55 ** The type of case-changing to perform.
57 typedef enum _CASE {
58 TOupper, TOlower
59 } CASE;
62 ** Key to command mapping.
64 typedef struct _KEYMAP {
65 unsigned char Key;
66 el_STATUS (*Function)(void);
67 } KEYMAP;
70 ** Command history structure.
72 typedef struct _HISTORY {
73 int Size;
74 int Pos;
75 unsigned char *Lines[HIST_SIZE];
76 } HISTORY;
79 ** Globals.
81 int rl_eof;
82 int rl_erase;
83 int rl_intr;
84 int rl_kill;
86 static unsigned char NIL[] = "";
87 static const unsigned char *Input = NIL;
88 static unsigned char *Line;
89 static const char *Prompt;
90 static unsigned char *Yanked;
91 static char *Screen;
92 static char NEWLINE[]= CRLF;
93 static HISTORY H;
94 int rl_quit;
95 static int Repeat;
96 static int End;
97 static int Mark;
98 static int OldPoint;
99 static int Point;
100 static int PushBack;
101 static int Pushed;
102 static KEYMAP Map[33];
103 static KEYMAP MetaMap[16];
104 static size_t Length;
105 static size_t ScreenCount;
106 static size_t ScreenSize;
107 static char *backspace;
108 static int TTYwidth;
109 static int TTYrows;
111 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
112 int rl_meta_chars = 1;
115 ** Declarations.
117 static unsigned char *editinput(void);
118 char *tgetstr(const char*, char**);
119 int tgetent(char*, const char*);
120 int tgetnum(const char*);
123 ** TTY input/output functions.
126 static void
127 TTYflush(void)
129 if (ScreenCount) {
130 write(1, Screen, ScreenCount);
131 ScreenCount = 0;
135 static void
136 TTYput(unsigned char c)
138 Screen[ScreenCount] = c;
139 if (++ScreenCount >= ScreenSize - 1) {
140 ScreenSize += SCREEN_INC;
141 Screen = realloc(Screen, ScreenSize);
145 static void
146 TTYputs(const char *p)
148 while (*p)
149 TTYput(*p++);
152 static void
153 TTYshow(unsigned char c)
155 if (c == DEL) {
156 TTYput('^');
157 TTYput('?');
159 else if (ISCTL(c)) {
160 TTYput('^');
161 TTYput(UNCTL(c));
163 else if (rl_meta_chars && ISMETA(c)) {
164 TTYput('M');
165 TTYput('-');
166 TTYput(UNMETA(c));
168 else
169 TTYput(c);
172 static void
173 TTYstring(unsigned char *p)
175 while (*p)
176 TTYshow(*p++);
179 static int
180 TTYget(void)
182 unsigned char c;
183 int e;
185 TTYflush();
186 if (Pushed) {
187 Pushed = 0;
188 return PushBack;
190 if (*Input)
191 return *Input++;
192 do {
193 e = read(0, &c, 1);
194 } while(e < 0 && errno == EINTR);
195 if(e == 1)
196 return c;
197 return EOF;
200 static void
201 TTYback(void)
203 if (backspace)
204 TTYputs(backspace);
205 else
206 TTYput('\b');
209 static void
210 TTYbackn(int n)
212 while (--n >= 0)
213 TTYback();
216 static void
217 TTYinfo(void)
219 static int init;
220 #if defined(TIOCGWINSZ)
221 struct winsize W;
222 #endif /* defined(TIOCGWINSZ) */
224 if (init) {
225 #if defined(TIOCGWINSZ)
226 /* Perhaps we got resized. */
227 if (ioctl(0, TIOCGWINSZ, &W) >= 0
228 && W.ws_col > 0 && W.ws_row > 0) {
229 TTYwidth = (int)W.ws_col;
230 TTYrows = (int)W.ws_row;
232 #endif /* defined(TIOCGWINSZ) */
233 return;
235 init++;
237 #ifdef HAVE_TGETENT
239 char buff[2048];
240 char *tmp;
241 char *bp;
242 const char *term;
244 TTYwidth = TTYrows = 0;
245 bp = &buff[0];
246 if ((term = getenv("TERM")) == NULL)
247 term = "dumb";
248 if (tgetent(buff, term) >= 0) {
250 tmp = tgetstr("le", &bp);
251 if (tmp != NULL)
252 backspace = strdup(tmp);
253 TTYwidth = tgetnum("co");
254 TTYrows = tgetnum("li");
255 return;
258 #endif
260 #if defined(TIOCGWINSZ)
261 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
262 TTYwidth = (int)W.ws_col;
263 TTYrows = (int)W.ws_row;
265 #endif /* defined(TIOCGWINSZ) */
267 if (TTYwidth <= 0 || TTYrows <= 0) {
268 TTYwidth = SCREEN_WIDTH;
269 TTYrows = SCREEN_ROWS;
275 ** Print an array of words in columns.
277 static void
278 columns(int ac, unsigned char **av)
280 unsigned char *p;
281 int i;
282 int j;
283 int k;
284 int len;
285 int skip;
286 int longest;
287 int cols;
289 /* Find longest name, determine column count from that. */
290 for (longest = 0, i = 0; i < ac; i++)
291 if ((j = strlen((char *)av[i])) > longest)
292 longest = j;
293 cols = TTYwidth / (longest + 3);
295 TTYputs(NEWLINE);
296 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
297 for (j = i; j < ac; j += skip) {
298 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
299 TTYput(*p);
300 if (j + skip < ac)
301 while (++len < longest + 3)
302 TTYput(' ');
304 TTYputs(NEWLINE);
308 static void
309 reposition(void)
311 int i;
312 unsigned char *p;
314 TTYput('\r');
315 TTYputs(Prompt);
316 for (i = Point, p = Line; --i >= 0; p++)
317 TTYshow(*p);
320 static void
321 left(el_STATUS Change)
323 TTYback();
324 if (Point) {
325 if (ISCTL(Line[Point - 1]))
326 TTYback();
327 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
328 TTYback();
329 TTYback();
332 if (Change == CSmove)
333 Point--;
336 static void
337 right(el_STATUS Change)
339 TTYshow(Line[Point]);
340 if (Change == CSmove)
341 Point++;
344 static el_STATUS
345 ring_bell(void)
347 TTYput('\07');
348 TTYflush();
349 return CSstay;
352 static el_STATUS
353 do_macro(unsigned char c)
355 unsigned char name[4];
357 name[0] = '_';
358 name[1] = c;
359 name[2] = '_';
360 name[3] = '\0';
362 if ((Input = (unsigned char *)getenv((char *)name)) == NULL) {
363 Input = NIL;
364 return ring_bell();
366 return CSstay;
369 static el_STATUS
370 do_forward(el_STATUS move)
372 int i;
373 unsigned char *p;
375 i = 0;
376 do {
377 p = &Line[Point];
378 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
379 if (move == CSmove)
380 right(CSstay);
382 for (; Point < End && isalnum(*p); Point++, p++)
383 if (move == CSmove)
384 right(CSstay);
386 if (Point == End)
387 break;
388 } while (++i < Repeat);
390 return CSstay;
393 static el_STATUS
394 do_case(CASE type)
396 int i;
397 int end;
398 int count;
399 unsigned char *p;
401 do_forward(CSstay);
402 if (OldPoint != Point) {
403 if ((count = Point - OldPoint) < 0)
404 count = -count;
405 Point = OldPoint;
406 if ((end = Point + count) > End)
407 end = End;
408 for (i = Point, p = &Line[i]; i < end; i++, p++) {
409 if (type == TOupper) {
410 if (islower(*p))
411 *p = toupper(*p);
413 else if (isupper(*p))
414 *p = tolower(*p);
415 right(CSmove);
418 return CSstay;
421 static el_STATUS
422 case_down_word(void)
424 return do_case(TOlower);
427 static el_STATUS
428 case_up_word(void)
430 return do_case(TOupper);
433 static void
434 ceol(void)
436 int extras;
437 int i;
438 unsigned char *p;
440 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
441 TTYput(' ');
442 if (ISCTL(*p)) {
443 TTYput(' ');
444 extras++;
446 else if (rl_meta_chars && ISMETA(*p)) {
447 TTYput(' ');
448 TTYput(' ');
449 extras += 2;
453 for (i += extras; i > Point; i--)
454 TTYback();
457 static void
458 clear_line(void)
460 Point = -strlen(Prompt);
461 TTYput('\r');
462 ceol();
463 Point = 0;
464 End = 0;
465 Line[0] = '\0';
468 static el_STATUS
469 insert_string(unsigned char *p)
471 size_t len;
472 int i;
473 unsigned char *new;
474 unsigned char *q;
476 len = strlen((char *)p);
477 if (End + len >= Length) {
478 if ((new = malloc(sizeof(unsigned char) * (Length + len + MEM_INC))) == NULL)
479 return CSstay;
480 if (Length) {
481 memcpy(new, Line, Length);
482 free(Line);
484 Line = new;
485 Length += len + MEM_INC;
488 for (q = &Line[Point], i = End - Point; --i >= 0; )
489 q[len + i] = q[i];
490 memcpy(&Line[Point], p, len);
491 End += len;
492 Line[End] = '\0';
493 TTYstring(&Line[Point]);
494 Point += len;
496 return Point == End ? CSstay : CSmove;
500 static unsigned char *
501 next_hist(void)
503 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
506 static unsigned char *
507 prev_hist(void)
509 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
512 static el_STATUS
513 do_insert_hist(unsigned char *p)
515 if (p == NULL)
516 return ring_bell();
517 Point = 0;
518 reposition();
519 ceol();
520 End = 0;
521 return insert_string(p);
524 static el_STATUS
525 do_hist(unsigned char *(*move)(void))
527 unsigned char *p;
528 int i;
530 i = 0;
531 do {
532 if ((p = (*move)()) == NULL)
533 return ring_bell();
534 } while (++i < Repeat);
535 return do_insert_hist(p);
538 static el_STATUS
539 h_next(void)
541 return do_hist(next_hist);
544 static el_STATUS
545 h_prev(void)
547 return do_hist(prev_hist);
550 static el_STATUS
551 h_first(void)
553 return do_insert_hist(H.Lines[H.Pos = 0]);
556 static el_STATUS
557 h_last(void)
559 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
563 ** Return zero if pat appears as a substring in text.
565 static int
566 substrcmp(const char *text, const char *pat, size_t len)
568 char c;
570 if ((c = *pat) == '\0')
571 return *text == '\0';
572 for ( ; *text; text++)
573 if (*text == c && strncmp(text, pat, len) == 0)
574 return 0;
575 return 1;
578 static unsigned char *
579 search_hist(unsigned char *search, unsigned char *(*move)(void))
581 static unsigned char *old_search;
582 int len;
583 int pos;
584 int (*match)(const char *, const char *, size_t);
585 char *pat;
587 /* Save or get remembered search pattern. */
588 if (search && *search) {
589 if (old_search)
590 free(old_search);
591 old_search = (unsigned char *)strdup((char *)search);
593 else {
594 if (old_search == NULL || *old_search == '\0')
595 return NULL;
596 search = old_search;
599 /* Set up pattern-finder. */
600 if (*search == '^') {
601 match = strncmp;
602 pat = (char *)(search + 1);
604 else {
605 match = substrcmp;
606 pat = (char *)search;
608 len = strlen(pat);
610 for (pos = H.Pos; (*move)() != NULL; )
611 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
612 return H.Lines[H.Pos];
613 H.Pos = pos;
614 return NULL;
617 static el_STATUS
618 h_search(void)
620 static int Searching;
621 const char *old_prompt;
622 unsigned char *(*move)(void);
623 unsigned char *p;
625 if (Searching)
626 return ring_bell();
627 Searching = 1;
629 clear_line();
630 old_prompt = Prompt;
631 Prompt = "Search: ";
632 TTYputs(Prompt);
633 move = Repeat == NO_ARG ? prev_hist : next_hist;
634 p = search_hist(editinput(), move);
635 clear_line();
636 Prompt = old_prompt;
637 TTYputs(Prompt);
639 Searching = 0;
640 return do_insert_hist(p);
643 static el_STATUS
644 fd_char(void)
646 int i;
648 i = 0;
649 do {
650 if (Point >= End)
651 break;
652 right(CSmove);
653 } while (++i < Repeat);
654 return CSstay;
657 static void
658 save_yank(int begin, int i)
660 if (Yanked) {
661 free(Yanked);
662 Yanked = NULL;
665 if (i < 1)
666 return;
668 if ((Yanked = malloc(sizeof(unsigned char) * (i + 1))) != NULL) {
669 memcpy(Yanked, &Line[begin], i);
670 Yanked[i+1] = '\0';
674 static el_STATUS
675 delete_string(int count)
677 int i;
678 unsigned char *p;
680 if (count <= 0 || End == Point)
681 return ring_bell();
683 if (count == 1 && Point == End - 1) {
684 /* Optimize common case of delete at end of line. */
685 End--;
686 p = &Line[Point];
687 i = 1;
688 TTYput(' ');
689 if (ISCTL(*p)) {
690 i = 2;
691 TTYput(' ');
693 else if (rl_meta_chars && ISMETA(*p)) {
694 i = 3;
695 TTYput(' ');
696 TTYput(' ');
698 TTYbackn(i);
699 *p = '\0';
700 return CSmove;
702 if (Point + count > End && (count = End - Point) <= 0)
703 return CSstay;
705 if (count > 1)
706 save_yank(Point, count);
708 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
709 p[0] = p[count];
710 ceol();
711 End -= count;
712 TTYstring(&Line[Point]);
713 return CSmove;
716 static el_STATUS
717 bk_char(void)
719 int i;
721 i = 0;
722 do {
723 if (Point == 0)
724 break;
725 left(CSmove);
726 } while (++i < Repeat);
728 return CSstay;
731 static el_STATUS
732 bk_del_char(void)
734 int i;
736 i = 0;
737 do {
738 if (Point == 0)
739 break;
740 left(CSmove);
741 } while (++i < Repeat);
743 return delete_string(i);
746 static el_STATUS
747 redisplay(void)
749 TTYputs(NEWLINE);
750 TTYputs(Prompt);
751 TTYstring(Line);
752 return CSmove;
755 static el_STATUS
756 kill_line(void)
758 int i;
760 if (Repeat != NO_ARG) {
761 if (Repeat < Point) {
762 i = Point;
763 Point = Repeat;
764 reposition();
765 delete_string(i - Point);
767 else if (Repeat > Point) {
768 right(CSmove);
769 delete_string(Repeat - Point - 1);
771 return CSmove;
774 save_yank(Point, End - Point);
775 Line[Point] = '\0';
776 ceol();
777 End = Point;
778 return CSstay;
781 static el_STATUS
782 insert_char(int c)
784 el_STATUS s;
785 unsigned char buff[2];
786 unsigned char *p;
787 unsigned char *q;
788 int i;
790 if (Repeat == NO_ARG || Repeat < 2) {
791 buff[0] = c;
792 buff[1] = '\0';
793 return insert_string(buff);
796 if ((p = malloc(Repeat + 1)) == NULL)
797 return CSstay;
798 for (i = Repeat, q = p; --i >= 0; )
799 *q++ = c;
800 *q = '\0';
801 Repeat = 0;
802 s = insert_string(p);
803 free(p);
804 return s;
807 static el_STATUS
808 meta(void)
810 unsigned int c;
811 KEYMAP *kp;
813 if ((c = TTYget()) == EOF)
814 return CSeof;
815 /* Also include VT-100 arrows. */
816 if (c == '[' || c == 'O')
817 switch (c = TTYget()) {
818 default: return ring_bell();
819 case EOF: return CSeof;
820 case 'A': return h_prev();
821 case 'B': return h_next();
822 case 'C': return fd_char();
823 case 'D': return bk_char();
826 if (isdigit(c)) {
827 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
828 Repeat = Repeat * 10 + c - '0';
829 Pushed = 1;
830 PushBack = c;
831 return CSstay;
834 if (isupper(c))
835 return do_macro(c);
836 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
837 if (kp->Key == c)
838 return (*kp->Function)();
840 return ring_bell();
843 static el_STATUS
844 emacs(unsigned int c)
846 el_STATUS s;
847 KEYMAP *kp;
849 if (ISMETA(c)) {
850 Pushed = 1;
851 PushBack = UNMETA(c);
852 return meta();
854 for (kp = Map; kp->Function; kp++)
855 if (kp->Key == c)
856 break;
857 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
858 if (!Pushed)
859 /* No pushback means no repeat count; hacky, but true. */
860 Repeat = NO_ARG;
861 return s;
864 static el_STATUS
865 TTYspecial(unsigned int c)
867 if (ISMETA(c))
868 return CSdispatch;
870 if (c == rl_erase || c == DEL)
871 return bk_del_char();
872 if (c == rl_kill) {
873 if (Point != 0) {
874 Point = 0;
875 reposition();
877 Repeat = NO_ARG;
878 return kill_line();
880 if (c == rl_intr || c == rl_quit) {
881 Point = End = 0;
882 Line[0] = '\0';
883 return redisplay();
885 if (c == rl_eof && Point == 0 && End == 0)
886 return CSeof;
888 return CSdispatch;
891 static unsigned char *
892 editinput(void)
894 unsigned int c;
896 Repeat = NO_ARG;
897 OldPoint = Point = Mark = End = 0;
898 Line[0] = '\0';
900 while ((c = TTYget()) != EOF)
901 switch (TTYspecial(c)) {
902 case CSdone:
903 return Line;
904 case CSeof:
905 return NULL;
906 case CSmove:
907 reposition();
908 break;
909 case CSdispatch:
910 switch (emacs(c)) {
911 case CSdone:
912 return Line;
913 case CSeof:
914 return NULL;
915 case CSmove:
916 reposition();
917 break;
918 case CSdispatch:
919 case CSstay:
920 break;
922 break;
923 case CSstay:
924 break;
926 return NULL;
929 static void
930 hist_add(unsigned char *p)
932 int i;
934 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
935 return;
936 if (H.Size < HIST_SIZE)
937 H.Lines[H.Size++] = p;
938 else {
939 free(H.Lines[0]);
940 for (i = 0; i < HIST_SIZE - 1; i++)
941 H.Lines[i] = H.Lines[i + 1];
942 H.Lines[i] = p;
944 H.Pos = H.Size - 1;
948 ** For compatibility with FSF readline.
950 /* ARGSUSED0 */
951 void
952 rl_reset_terminal(char *p)
956 void
957 rl_initialize(void)
961 char *
962 readline(const char* prompt)
964 unsigned char *line;
966 if (Line == NULL) {
967 Length = MEM_INC;
968 if ((Line = malloc(Length)) == NULL)
969 return NULL;
972 TTYinfo();
973 rl_ttyset(0);
974 hist_add(NIL);
975 ScreenSize = SCREEN_INC;
976 Screen = malloc(ScreenSize);
977 Prompt = prompt ? prompt : (char *)NIL;
978 TTYputs(Prompt);
979 if ((line = editinput()) != NULL) {
980 line = (unsigned char *)strdup((char *)line);
981 TTYputs(NEWLINE);
982 TTYflush();
984 rl_ttyset(1);
985 free(Screen);
986 free(H.Lines[--H.Size]);
987 return (char *)line;
990 void
991 add_history(char *p)
993 if (p == NULL || *p == '\0')
994 return;
996 #if defined(UNIQUE_HISTORY)
997 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
998 return;
999 #endif /* defined(UNIQUE_HISTORY) */
1000 hist_add((unsigned char *)p);
1004 static el_STATUS
1005 beg_line(void)
1007 if (Point) {
1008 Point = 0;
1009 return CSmove;
1011 return CSstay;
1014 static el_STATUS
1015 del_char(void)
1017 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1020 static el_STATUS
1021 end_line(void)
1023 if (Point != End) {
1024 Point = End;
1025 return CSmove;
1027 return CSstay;
1031 ** Move back to the beginning of the current word and return an
1032 ** allocated copy of it.
1034 static unsigned char *
1035 find_word(void)
1037 static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
1038 unsigned char *p;
1039 unsigned char *new;
1040 size_t len;
1042 for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
1043 continue;
1044 len = Point - (p - Line) + 1;
1045 if ((new = malloc(len)) == NULL)
1046 return NULL;
1047 memcpy(new, p, len);
1048 new[len - 1] = '\0';
1049 return new;
1052 static el_STATUS
1053 c_complete(void)
1055 unsigned char *p;
1056 unsigned char *word;
1057 int unique;
1058 el_STATUS s;
1060 word = find_word();
1061 p = (unsigned char *)rl_complete((char *)word, &unique);
1062 if (word)
1063 free(word);
1064 if (p && *p) {
1065 s = insert_string(p);
1066 if (!unique)
1067 ring_bell();
1068 free(p);
1069 return s;
1071 return ring_bell();
1074 static el_STATUS
1075 c_possible(void)
1077 unsigned char **av;
1078 unsigned char *word;
1079 int ac;
1081 word = find_word();
1082 ac = rl_list_possib((char *)word, (void *)&av);
1083 if (word)
1084 free(word);
1085 if (ac) {
1086 columns(ac, av);
1087 while (--ac >= 0)
1088 free(av[ac]);
1089 free(av);
1090 return CSmove;
1092 return ring_bell();
1095 static el_STATUS
1096 accept_line(void)
1098 Line[End] = '\0';
1099 return CSdone;
1102 static el_STATUS
1103 transpose(void)
1105 unsigned char c;
1107 if (Point) {
1108 if (Point == End)
1109 left(CSmove);
1110 c = Line[Point - 1];
1111 left(CSstay);
1112 Line[Point - 1] = Line[Point];
1113 TTYshow(Line[Point - 1]);
1114 Line[Point++] = c;
1115 TTYshow(c);
1117 return CSstay;
1120 static el_STATUS
1121 quote(void)
1123 unsigned int c;
1125 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1128 static el_STATUS
1129 wipe(void)
1131 int i;
1133 if (Mark > End)
1134 return ring_bell();
1136 if (Point > Mark) {
1137 i = Point;
1138 Point = Mark;
1139 Mark = i;
1140 reposition();
1143 return delete_string(Mark - Point);
1146 static el_STATUS
1147 mk_set(void)
1149 Mark = Point;
1150 return CSstay;
1153 static el_STATUS
1154 exchange(void)
1156 unsigned int c;
1158 if ((c = TTYget()) != CTL('X'))
1159 return c == EOF ? CSeof : ring_bell();
1161 if ((c = Mark) <= End) {
1162 Mark = Point;
1163 Point = c;
1164 return CSmove;
1166 return CSstay;
1169 static el_STATUS
1170 yank(void)
1172 if (Yanked && *Yanked)
1173 return insert_string(Yanked);
1174 return CSstay;
1177 static el_STATUS
1178 copy_region(void)
1180 if (Mark > End)
1181 return ring_bell();
1183 if (Point > Mark)
1184 save_yank(Mark, Point - Mark);
1185 else
1186 save_yank(Point, Mark - Point);
1188 return CSstay;
1191 static el_STATUS
1192 move_to_char(void)
1194 unsigned int c;
1195 int i;
1196 unsigned char *p;
1198 if ((c = TTYget()) == EOF)
1199 return CSeof;
1200 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1201 if (*p == c) {
1202 Point = i;
1203 return CSmove;
1205 return CSstay;
1208 static el_STATUS
1209 fd_word(void)
1211 return do_forward(CSmove);
1214 static el_STATUS
1215 fd_kill_word(void)
1217 int i;
1219 do_forward(CSstay);
1220 if (OldPoint != Point) {
1221 i = Point - OldPoint;
1222 Point = OldPoint;
1223 return delete_string(i);
1225 return CSstay;
1228 static el_STATUS
1229 bk_word(void)
1231 int i;
1232 unsigned char *p;
1234 i = 0;
1235 do {
1236 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1237 left(CSmove);
1239 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1240 left(CSmove);
1242 if (Point == 0)
1243 break;
1244 } while (++i < Repeat);
1246 return CSstay;
1249 static el_STATUS
1250 bk_kill_word(void)
1252 bk_word();
1253 if (OldPoint != Point)
1254 return delete_string(OldPoint - Point);
1255 return CSstay;
1258 static int
1259 argify(unsigned char *line, unsigned char ***avp)
1261 unsigned char *c;
1262 unsigned char **p;
1263 unsigned char **new;
1264 int ac;
1265 int i;
1267 i = MEM_INC;
1268 if ((*avp = p = malloc(sizeof(unsigned char*) * i))== NULL)
1269 return 0;
1271 for (c = line; isspace(*c); c++)
1272 continue;
1273 if (*c == '\n' || *c == '\0')
1274 return 0;
1276 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1277 if (isspace(*c)) {
1278 *c++ = '\0';
1279 if (*c && *c != '\n') {
1280 if (ac + 1 == i) {
1281 new = malloc(sizeof(unsigned char*) * (i + MEM_INC));
1282 if (new == NULL) {
1283 p[ac] = NULL;
1284 return ac;
1286 memcpy(new, p, i * sizeof (char **));
1287 i += MEM_INC;
1288 free(p);
1289 *avp = p = new;
1291 p[ac++] = c;
1294 else
1295 c++;
1297 *c = '\0';
1298 p[ac] = NULL;
1299 return ac;
1302 static el_STATUS
1303 last_argument(void)
1305 unsigned char **av;
1306 unsigned char *p;
1307 el_STATUS s;
1308 int ac;
1310 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1311 return ring_bell();
1313 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
1314 return CSstay;
1315 ac = argify(p, &av);
1317 if (Repeat != NO_ARG)
1318 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1319 else
1320 s = ac ? insert_string(av[ac - 1]) : CSstay;
1322 if (ac)
1323 free(av);
1324 free(p);
1325 return s;
1328 static KEYMAP Map[33] = {
1329 { CTL('@'), ring_bell },
1330 { CTL('A'), beg_line },
1331 { CTL('B'), bk_char },
1332 { CTL('D'), del_char },
1333 { CTL('E'), end_line },
1334 { CTL('F'), fd_char },
1335 { CTL('G'), ring_bell },
1336 { CTL('H'), bk_del_char },
1337 { CTL('I'), c_complete },
1338 { CTL('J'), accept_line },
1339 { CTL('K'), kill_line },
1340 { CTL('L'), redisplay },
1341 { CTL('M'), accept_line },
1342 { CTL('N'), h_next },
1343 { CTL('O'), ring_bell },
1344 { CTL('P'), h_prev },
1345 { CTL('Q'), ring_bell },
1346 { CTL('R'), h_search },
1347 { CTL('S'), ring_bell },
1348 { CTL('T'), transpose },
1349 { CTL('U'), ring_bell },
1350 { CTL('V'), quote },
1351 { CTL('W'), wipe },
1352 { CTL('X'), exchange },
1353 { CTL('Y'), yank },
1354 { CTL('Z'), ring_bell },
1355 { CTL('['), meta },
1356 { CTL(']'), move_to_char },
1357 { CTL('^'), ring_bell },
1358 { CTL('_'), ring_bell },
1359 { 0, NULL }
1362 static KEYMAP MetaMap[16]= {
1363 { CTL('H'), bk_kill_word },
1364 { DEL, bk_kill_word },
1365 { ' ', mk_set },
1366 { '.', last_argument },
1367 { '<', h_first },
1368 { '>', h_last },
1369 { '?', c_possible },
1370 { 'b', bk_word },
1371 { 'd', fd_kill_word },
1372 { 'f', fd_word },
1373 { 'l', case_down_word },
1374 { 'u', case_up_word },
1375 { 'y', yank },
1376 { 'w', copy_region },
1377 { 0, NULL }