Make build on windows
[heimdal.git] / lib / editline / editline.c
blob29c7189ef23f0348b35da88e28f3ac2e15ef98e6
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 size_t len;
282 int k;
283 int skip;
284 unsigned int longest, i, j;
285 int cols;
287 /* Find longest name, determine column count from that. */
288 for (longest = 0, i = 0; i < ac; i++)
289 if ((j = strlen((char *)av[i])) > longest)
290 longest = j;
291 cols = TTYwidth / (longest + 3);
293 TTYputs(NEWLINE);
294 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
295 for (j = i; j < ac; j += skip) {
296 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
297 TTYput(*p);
298 if (j + skip < ac)
299 while (++len < longest + 3)
300 TTYput(' ');
302 TTYputs(NEWLINE);
306 static void
307 reposition(void)
309 int i;
310 unsigned char *p;
312 TTYput('\r');
313 TTYputs(Prompt);
314 for (i = Point, p = Line; --i >= 0; p++)
315 TTYshow(*p);
318 static void
319 left(el_STATUS Change)
321 TTYback();
322 if (Point) {
323 if (ISCTL(Line[Point - 1]))
324 TTYback();
325 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
326 TTYback();
327 TTYback();
330 if (Change == CSmove)
331 Point--;
334 static void
335 right(el_STATUS Change)
337 TTYshow(Line[Point]);
338 if (Change == CSmove)
339 Point++;
342 static el_STATUS
343 ring_bell(void)
345 TTYput('\07');
346 TTYflush();
347 return CSstay;
350 static el_STATUS
351 do_macro(unsigned char c)
353 unsigned char name[4];
355 name[0] = '_';
356 name[1] = c;
357 name[2] = '_';
358 name[3] = '\0';
360 if ((Input = (unsigned char *)getenv((char *)name)) == NULL) {
361 Input = NIL;
362 return ring_bell();
364 return CSstay;
367 static el_STATUS
368 do_forward(el_STATUS move)
370 int i;
371 unsigned char *p;
373 i = 0;
374 do {
375 p = &Line[Point];
376 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
377 if (move == CSmove)
378 right(CSstay);
380 for (; Point < End && isalnum(*p); Point++, p++)
381 if (move == CSmove)
382 right(CSstay);
384 if (Point == End)
385 break;
386 } while (++i < Repeat);
388 return CSstay;
391 static el_STATUS
392 do_case(CASE type)
394 int i;
395 int end;
396 int count;
397 unsigned char *p;
399 do_forward(CSstay);
400 if (OldPoint != Point) {
401 if ((count = Point - OldPoint) < 0)
402 count = -count;
403 Point = OldPoint;
404 if ((end = Point + count) > End)
405 end = End;
406 for (i = Point, p = &Line[i]; i < end; i++, p++) {
407 if (type == TOupper) {
408 if (islower(*p))
409 *p = toupper(*p);
411 else if (isupper(*p))
412 *p = tolower(*p);
413 right(CSmove);
416 return CSstay;
419 static el_STATUS
420 case_down_word(void)
422 return do_case(TOlower);
425 static el_STATUS
426 case_up_word(void)
428 return do_case(TOupper);
431 static void
432 ceol(void)
434 int extras;
435 int i;
436 unsigned char *p;
438 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
439 TTYput(' ');
440 if (ISCTL(*p)) {
441 TTYput(' ');
442 extras++;
444 else if (rl_meta_chars && ISMETA(*p)) {
445 TTYput(' ');
446 TTYput(' ');
447 extras += 2;
451 for (i += extras; i > Point; i--)
452 TTYback();
455 static void
456 clear_line(void)
458 Point = -(int)strlen(Prompt);
459 TTYput('\r');
460 ceol();
461 Point = 0;
462 End = 0;
463 Line[0] = '\0';
466 static el_STATUS
467 insert_string(unsigned char *p)
469 size_t len;
470 int i;
471 unsigned char *new;
472 unsigned char *q;
474 len = strlen((char *)p);
475 if (End + len >= Length) {
476 if ((new = malloc(sizeof(unsigned char) * (Length + len + MEM_INC))) == NULL)
477 return CSstay;
478 if (Length) {
479 memcpy(new, Line, Length);
480 free(Line);
482 Line = new;
483 Length += len + MEM_INC;
486 for (q = &Line[Point], i = End - Point; --i >= 0; )
487 q[len + i] = q[i];
488 memcpy(&Line[Point], p, len);
489 End += len;
490 Line[End] = '\0';
491 TTYstring(&Line[Point]);
492 Point += len;
494 return Point == End ? CSstay : CSmove;
498 static unsigned char *
499 next_hist(void)
501 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
504 static unsigned char *
505 prev_hist(void)
507 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
510 static el_STATUS
511 do_insert_hist(unsigned char *p)
513 if (p == NULL)
514 return ring_bell();
515 Point = 0;
516 reposition();
517 ceol();
518 End = 0;
519 return insert_string(p);
522 static el_STATUS
523 do_hist(unsigned char *(*move)(void))
525 unsigned char *p;
526 int i;
528 i = 0;
529 do {
530 if ((p = (*move)()) == NULL)
531 return ring_bell();
532 } while (++i < Repeat);
533 return do_insert_hist(p);
536 static el_STATUS
537 h_next(void)
539 return do_hist(next_hist);
542 static el_STATUS
543 h_prev(void)
545 return do_hist(prev_hist);
548 static el_STATUS
549 h_first(void)
551 return do_insert_hist(H.Lines[H.Pos = 0]);
554 static el_STATUS
555 h_last(void)
557 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
561 ** Return zero if pat appears as a substring in text.
563 static int
564 substrcmp(const char *text, const char *pat, size_t len)
566 char c;
568 if ((c = *pat) == '\0')
569 return *text == '\0';
570 for ( ; *text; text++)
571 if (*text == c && strncmp(text, pat, len) == 0)
572 return 0;
573 return 1;
576 static unsigned char *
577 search_hist(unsigned char *search, unsigned char *(*move)(void))
579 static unsigned char *old_search;
580 int len;
581 int pos;
582 int (*match)(const char *, const char *, size_t);
583 char *pat;
585 /* Save or get remembered search pattern. */
586 if (search && *search) {
587 if (old_search)
588 free(old_search);
589 old_search = (unsigned char *)strdup((char *)search);
591 else {
592 if (old_search == NULL || *old_search == '\0')
593 return NULL;
594 search = old_search;
597 /* Set up pattern-finder. */
598 if (*search == '^') {
599 match = strncmp;
600 pat = (char *)(search + 1);
602 else {
603 match = substrcmp;
604 pat = (char *)search;
606 len = strlen(pat);
608 for (pos = H.Pos; (*move)() != NULL; )
609 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
610 return H.Lines[H.Pos];
611 H.Pos = pos;
612 return NULL;
615 static el_STATUS
616 h_search(void)
618 static int Searching;
619 const char *old_prompt;
620 unsigned char *(*move)(void);
621 unsigned char *p;
623 if (Searching)
624 return ring_bell();
625 Searching = 1;
627 clear_line();
628 old_prompt = Prompt;
629 Prompt = "Search: ";
630 TTYputs(Prompt);
631 move = Repeat == NO_ARG ? prev_hist : next_hist;
632 p = search_hist(editinput(), move);
633 clear_line();
634 Prompt = old_prompt;
635 TTYputs(Prompt);
637 Searching = 0;
638 return do_insert_hist(p);
641 static el_STATUS
642 fd_char(void)
644 int i;
646 i = 0;
647 do {
648 if (Point >= End)
649 break;
650 right(CSmove);
651 } while (++i < Repeat);
652 return CSstay;
655 static void
656 save_yank(int begin, int i)
658 if (Yanked) {
659 free(Yanked);
660 Yanked = NULL;
663 if (i < 1)
664 return;
666 if ((Yanked = malloc(sizeof(unsigned char) * (i + 1))) != NULL) {
667 memcpy(Yanked, &Line[begin], i);
668 Yanked[i+1] = '\0';
672 static el_STATUS
673 delete_string(int count)
675 int i;
676 unsigned char *p;
678 if (count <= 0 || End == Point)
679 return ring_bell();
681 if (count == 1 && Point == End - 1) {
682 /* Optimize common case of delete at end of line. */
683 End--;
684 p = &Line[Point];
685 i = 1;
686 TTYput(' ');
687 if (ISCTL(*p)) {
688 i = 2;
689 TTYput(' ');
691 else if (rl_meta_chars && ISMETA(*p)) {
692 i = 3;
693 TTYput(' ');
694 TTYput(' ');
696 TTYbackn(i);
697 *p = '\0';
698 return CSmove;
700 if (Point + count > End && (count = End - Point) <= 0)
701 return CSstay;
703 if (count > 1)
704 save_yank(Point, count);
706 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
707 p[0] = p[count];
708 ceol();
709 End -= count;
710 TTYstring(&Line[Point]);
711 return CSmove;
714 static el_STATUS
715 bk_char(void)
717 int i;
719 i = 0;
720 do {
721 if (Point == 0)
722 break;
723 left(CSmove);
724 } while (++i < Repeat);
726 return CSstay;
729 static el_STATUS
730 bk_del_char(void)
732 int i;
734 i = 0;
735 do {
736 if (Point == 0)
737 break;
738 left(CSmove);
739 } while (++i < Repeat);
741 return delete_string(i);
744 static el_STATUS
745 redisplay(void)
747 TTYputs(NEWLINE);
748 TTYputs(Prompt);
749 TTYstring(Line);
750 return CSmove;
753 static el_STATUS
754 kill_line(void)
756 int i;
758 if (Repeat != NO_ARG) {
759 if (Repeat < Point) {
760 i = Point;
761 Point = Repeat;
762 reposition();
763 delete_string(i - Point);
765 else if (Repeat > Point) {
766 right(CSmove);
767 delete_string(Repeat - Point - 1);
769 return CSmove;
772 save_yank(Point, End - Point);
773 Line[Point] = '\0';
774 ceol();
775 End = Point;
776 return CSstay;
779 static el_STATUS
780 insert_char(int c)
782 el_STATUS s;
783 unsigned char buff[2];
784 unsigned char *p;
785 unsigned char *q;
786 int i;
788 if (Repeat == NO_ARG || Repeat < 2) {
789 buff[0] = c;
790 buff[1] = '\0';
791 return insert_string(buff);
794 if ((p = malloc(Repeat + 1)) == NULL)
795 return CSstay;
796 for (i = Repeat, q = p; --i >= 0; )
797 *q++ = c;
798 *q = '\0';
799 Repeat = 0;
800 s = insert_string(p);
801 free(p);
802 return s;
805 static el_STATUS
806 meta(void)
808 unsigned int c;
809 KEYMAP *kp;
811 if ((c = TTYget()) == EOF)
812 return CSeof;
813 /* Also include VT-100 arrows. */
814 if (c == '[' || c == 'O') {
815 switch (TTYget()) {
816 case EOF: return CSeof;
817 case 'A': return h_prev();
818 case 'B': return h_next();
819 case 'C': return fd_char();
820 case 'D': return bk_char();
822 return ring_bell();
825 if (isdigit(c)) {
826 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
827 Repeat = Repeat * 10 + c - '0';
828 Pushed = 1;
829 PushBack = c;
830 return CSstay;
833 if (isupper(c))
834 return do_macro(c);
835 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
836 if (kp->Key == c)
837 return (*kp->Function)();
839 return ring_bell();
842 static el_STATUS
843 emacs(unsigned int c)
845 el_STATUS s;
846 KEYMAP *kp;
848 if (ISMETA(c)) {
849 Pushed = 1;
850 PushBack = UNMETA(c);
851 return meta();
853 for (kp = Map; kp->Function; kp++)
854 if (kp->Key == c)
855 break;
856 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
857 if (!Pushed)
858 /* No pushback means no repeat count; hacky, but true. */
859 Repeat = NO_ARG;
860 return s;
863 static el_STATUS
864 TTYspecial(unsigned int c)
866 if (ISMETA(c))
867 return CSdispatch;
869 if (c == rl_erase || c == DEL)
870 return bk_del_char();
871 if (c == rl_kill) {
872 if (Point != 0) {
873 Point = 0;
874 reposition();
876 Repeat = NO_ARG;
877 return kill_line();
879 if (c == rl_intr || c == rl_quit) {
880 Point = End = 0;
881 Line[0] = '\0';
882 return redisplay();
884 if (c == rl_eof && Point == 0 && End == 0)
885 return CSeof;
887 return CSdispatch;
890 static unsigned char *
891 editinput(void)
893 unsigned int c;
895 Repeat = NO_ARG;
896 OldPoint = Point = Mark = End = 0;
897 Line[0] = '\0';
899 while ((c = TTYget()) != EOF)
900 switch (TTYspecial(c)) {
901 case CSdone:
902 return Line;
903 case CSeof:
904 return NULL;
905 case CSmove:
906 reposition();
907 break;
908 case CSdispatch:
909 switch (emacs(c)) {
910 case CSdone:
911 return Line;
912 case CSeof:
913 return NULL;
914 case CSmove:
915 reposition();
916 break;
917 case CSdispatch:
918 case CSstay:
919 break;
921 break;
922 case CSstay:
923 break;
925 return NULL;
928 static void
929 hist_add(unsigned char *p)
931 int i;
933 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
934 return;
935 if (H.Size < HIST_SIZE)
936 H.Lines[H.Size++] = p;
937 else {
938 free(H.Lines[0]);
939 for (i = 0; i < HIST_SIZE - 1; i++)
940 H.Lines[i] = H.Lines[i + 1];
941 H.Lines[i] = p;
943 H.Pos = H.Size - 1;
947 ** For compatibility with FSF readline.
949 /* ARGSUSED0 */
950 void
951 rl_reset_terminal(char *p)
955 void
956 rl_initialize(void)
960 char *
961 readline(const char* prompt)
963 unsigned char *line;
965 if (Line == NULL) {
966 Length = MEM_INC;
967 if ((Line = malloc(Length)) == NULL)
968 return NULL;
971 TTYinfo();
972 rl_ttyset(0);
973 hist_add(NIL);
974 ScreenSize = SCREEN_INC;
975 Screen = malloc(ScreenSize);
976 Prompt = prompt ? prompt : (char *)NIL;
977 TTYputs(Prompt);
978 if ((line = editinput()) != NULL) {
979 line = (unsigned char *)strdup((char *)line);
980 TTYputs(NEWLINE);
981 TTYflush();
983 rl_ttyset(1);
984 free(Screen);
985 free(H.Lines[--H.Size]);
986 return (char *)line;
989 void
990 add_history(char *p)
992 if (p == NULL || *p == '\0')
993 return;
995 #if defined(UNIQUE_HISTORY)
996 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
997 return;
998 #endif /* defined(UNIQUE_HISTORY) */
999 hist_add((unsigned char *)p);
1003 static el_STATUS
1004 beg_line(void)
1006 if (Point) {
1007 Point = 0;
1008 return CSmove;
1010 return CSstay;
1013 static el_STATUS
1014 del_char(void)
1016 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1019 static el_STATUS
1020 end_line(void)
1022 if (Point != End) {
1023 Point = End;
1024 return CSmove;
1026 return CSstay;
1030 ** Move back to the beginning of the current word and return an
1031 ** allocated copy of it.
1033 static unsigned char *
1034 find_word(void)
1036 static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
1037 unsigned char *p;
1038 unsigned char *new;
1039 size_t len;
1041 for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
1042 continue;
1043 len = Point - (p - Line) + 1;
1044 if ((new = malloc(len)) == NULL)
1045 return NULL;
1046 memcpy(new, p, len);
1047 new[len - 1] = '\0';
1048 return new;
1051 static el_STATUS
1052 c_complete(void)
1054 unsigned char *p;
1055 unsigned char *word;
1056 int unique;
1057 el_STATUS s;
1059 word = find_word();
1060 p = (unsigned char *)rl_complete((char *)word, &unique);
1061 if (word)
1062 free(word);
1063 if (p && *p) {
1064 s = insert_string(p);
1065 if (!unique)
1066 ring_bell();
1067 free(p);
1068 return s;
1070 return ring_bell();
1073 static el_STATUS
1074 c_possible(void)
1076 unsigned char **av;
1077 unsigned char *word;
1078 int ac;
1080 word = find_word();
1081 ac = rl_list_possib((char *)word, (void *)&av);
1082 if (word)
1083 free(word);
1084 if (ac) {
1085 columns(ac, av);
1086 while (--ac >= 0)
1087 free(av[ac]);
1088 free(av);
1089 return CSmove;
1091 return ring_bell();
1094 static el_STATUS
1095 accept_line(void)
1097 Line[End] = '\0';
1098 return CSdone;
1101 static el_STATUS
1102 transpose(void)
1104 unsigned char c;
1106 if (Point) {
1107 if (Point == End)
1108 left(CSmove);
1109 c = Line[Point - 1];
1110 left(CSstay);
1111 Line[Point - 1] = Line[Point];
1112 TTYshow(Line[Point - 1]);
1113 Line[Point++] = c;
1114 TTYshow(c);
1116 return CSstay;
1119 static el_STATUS
1120 quote(void)
1122 unsigned int c;
1124 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1127 static el_STATUS
1128 wipe(void)
1130 int i;
1132 if (Mark > End)
1133 return ring_bell();
1135 if (Point > Mark) {
1136 i = Point;
1137 Point = Mark;
1138 Mark = i;
1139 reposition();
1142 return delete_string(Mark - Point);
1145 static el_STATUS
1146 mk_set(void)
1148 Mark = Point;
1149 return CSstay;
1152 static el_STATUS
1153 exchange(void)
1155 unsigned int c;
1157 if ((c = TTYget()) != CTL('X'))
1158 return c == EOF ? CSeof : ring_bell();
1160 if ((c = Mark) <= End) {
1161 Mark = Point;
1162 Point = c;
1163 return CSmove;
1165 return CSstay;
1168 static el_STATUS
1169 yank(void)
1171 if (Yanked && *Yanked)
1172 return insert_string(Yanked);
1173 return CSstay;
1176 static el_STATUS
1177 copy_region(void)
1179 if (Mark > End)
1180 return ring_bell();
1182 if (Point > Mark)
1183 save_yank(Mark, Point - Mark);
1184 else
1185 save_yank(Point, Mark - Point);
1187 return CSstay;
1190 static el_STATUS
1191 move_to_char(void)
1193 unsigned int c;
1194 int i;
1195 unsigned char *p;
1197 if ((c = TTYget()) == EOF)
1198 return CSeof;
1199 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1200 if (*p == c) {
1201 Point = i;
1202 return CSmove;
1204 return CSstay;
1207 static el_STATUS
1208 fd_word(void)
1210 return do_forward(CSmove);
1213 static el_STATUS
1214 fd_kill_word(void)
1216 int i;
1218 do_forward(CSstay);
1219 if (OldPoint != Point) {
1220 i = Point - OldPoint;
1221 Point = OldPoint;
1222 return delete_string(i);
1224 return CSstay;
1227 static el_STATUS
1228 bk_word(void)
1230 int i;
1231 unsigned char *p;
1233 i = 0;
1234 do {
1235 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1236 left(CSmove);
1238 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1239 left(CSmove);
1241 if (Point == 0)
1242 break;
1243 } while (++i < Repeat);
1245 return CSstay;
1248 static el_STATUS
1249 bk_kill_word(void)
1251 bk_word();
1252 if (OldPoint != Point)
1253 return delete_string(OldPoint - Point);
1254 return CSstay;
1257 static int
1258 argify(unsigned char *line, unsigned char ***avp)
1260 unsigned char *c;
1261 unsigned char **p;
1262 unsigned char **new;
1263 int ac;
1264 int i;
1266 i = MEM_INC;
1267 if ((*avp = p = malloc(sizeof(unsigned char*) * i))== NULL)
1268 return 0;
1270 for (c = line; isspace(*c); c++)
1271 continue;
1272 if (*c == '\n' || *c == '\0')
1273 return 0;
1275 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1276 if (isspace(*c)) {
1277 *c++ = '\0';
1278 if (*c && *c != '\n') {
1279 if (ac + 1 == i) {
1280 new = malloc(sizeof(unsigned char*) * (i + MEM_INC));
1281 if (new == NULL) {
1282 p[ac] = NULL;
1283 return ac;
1285 memcpy(new, p, i * sizeof (char **));
1286 i += MEM_INC;
1287 free(p);
1288 *avp = p = new;
1290 p[ac++] = c;
1293 else
1294 c++;
1296 *c = '\0';
1297 p[ac] = NULL;
1298 return ac;
1301 static el_STATUS
1302 last_argument(void)
1304 unsigned char **av = NULL;
1305 unsigned char *p;
1306 el_STATUS s;
1307 int ac;
1309 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1310 return ring_bell();
1312 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
1313 return CSstay;
1314 ac = argify(p, &av);
1316 if (Repeat != NO_ARG)
1317 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1318 else
1319 s = ac ? insert_string(av[ac - 1]) : CSstay;
1321 if (av)
1322 free(av);
1323 free(p);
1324 return s;
1327 static KEYMAP Map[33] = {
1328 { CTL('@'), ring_bell },
1329 { CTL('A'), beg_line },
1330 { CTL('B'), bk_char },
1331 { CTL('D'), del_char },
1332 { CTL('E'), end_line },
1333 { CTL('F'), fd_char },
1334 { CTL('G'), ring_bell },
1335 { CTL('H'), bk_del_char },
1336 { CTL('I'), c_complete },
1337 { CTL('J'), accept_line },
1338 { CTL('K'), kill_line },
1339 { CTL('L'), redisplay },
1340 { CTL('M'), accept_line },
1341 { CTL('N'), h_next },
1342 { CTL('O'), ring_bell },
1343 { CTL('P'), h_prev },
1344 { CTL('Q'), ring_bell },
1345 { CTL('R'), h_search },
1346 { CTL('S'), ring_bell },
1347 { CTL('T'), transpose },
1348 { CTL('U'), ring_bell },
1349 { CTL('V'), quote },
1350 { CTL('W'), wipe },
1351 { CTL('X'), exchange },
1352 { CTL('Y'), yank },
1353 { CTL('Z'), ring_bell },
1354 { CTL('['), meta },
1355 { CTL(']'), move_to_char },
1356 { CTL('^'), ring_bell },
1357 { CTL('_'), ring_bell },
1358 { 0, NULL }
1361 static KEYMAP MetaMap[16]= {
1362 { CTL('H'), bk_kill_word },
1363 { DEL, bk_kill_word },
1364 { ' ', mk_set },
1365 { '.', last_argument },
1366 { '<', h_first },
1367 { '>', h_last },
1368 { '?', c_possible },
1369 { 'b', bk_word },
1370 { 'd', fd_kill_word },
1371 { 'f', fd_word },
1372 { 'l', case_down_word },
1373 { 'u', case_up_word },
1374 { 'y', yank },
1375 { 'w', copy_region },
1376 { 0, NULL }