remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / editline / editline.c
blob24fa8464a9a1f585efb7d5c68cf8d05da946b881
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 "editline.h"
25 #include <ctype.h>
26 #include <errno.h>
28 RCSID("$Id: editline.c,v 1.10 2001/09/13 01:19:54 assar Exp $");
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)();
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()
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()
182 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()
219 static int init;
220 char *term;
221 char buff[2048];
222 char *bp;
223 char *tmp;
224 #if defined(TIOCGWINSZ)
225 struct winsize W;
226 #endif /* defined(TIOCGWINSZ) */
228 if (init) {
229 #if defined(TIOCGWINSZ)
230 /* Perhaps we got resized. */
231 if (ioctl(0, TIOCGWINSZ, &W) >= 0
232 && W.ws_col > 0 && W.ws_row > 0) {
233 TTYwidth = (int)W.ws_col;
234 TTYrows = (int)W.ws_row;
236 #endif /* defined(TIOCGWINSZ) */
237 return;
239 init++;
241 TTYwidth = TTYrows = 0;
242 bp = &buff[0];
243 if ((term = getenv("TERM")) == NULL)
244 term = "dumb";
245 if (tgetent(buff, term) < 0) {
246 TTYwidth = SCREEN_WIDTH;
247 TTYrows = SCREEN_ROWS;
248 return;
250 tmp = tgetstr("le", &bp);
251 if (tmp != NULL)
252 backspace = strdup(tmp);
253 else
254 backspace = "\b";
255 TTYwidth = tgetnum("co");
256 TTYrows = tgetnum("li");
258 #if defined(TIOCGWINSZ)
259 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
260 TTYwidth = (int)W.ws_col;
261 TTYrows = (int)W.ws_row;
263 #endif /* defined(TIOCGWINSZ) */
265 if (TTYwidth <= 0 || TTYrows <= 0) {
266 TTYwidth = SCREEN_WIDTH;
267 TTYrows = SCREEN_ROWS;
273 ** Print an array of words in columns.
275 static void
276 columns(int ac, unsigned char **av)
278 unsigned char *p;
279 int i;
280 int j;
281 int k;
282 int len;
283 int skip;
284 int longest;
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()
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()
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()
422 return do_case(TOlower);
425 static el_STATUS
426 case_up_word()
428 return do_case(TOupper);
431 static void
432 ceol()
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()
458 Point = -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()
501 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
504 static unsigned char *
505 prev_hist()
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)())
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()
539 return do_hist(next_hist);
542 static el_STATUS
543 h_prev()
545 return do_hist(prev_hist);
548 static el_STATUS
549 h_first()
551 return do_insert_hist(H.Lines[H.Pos = 0]);
554 static el_STATUS
555 h_last()
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(char *text, char *pat, int len)
566 unsigned 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)())
579 static unsigned char *old_search;
580 int len;
581 int pos;
582 int (*match)();
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()
618 static int Searching;
619 const char *old_prompt;
620 unsigned char *(*move)();
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()
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()
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()
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()
747 TTYputs(NEWLINE);
748 TTYputs(Prompt);
749 TTYstring(Line);
750 return CSmove;
753 static el_STATUS
754 kill_line()
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()
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 (c = TTYget()) {
816 default: return ring_bell();
817 case EOF: return CSeof;
818 case 'A': return h_prev();
819 case 'B': return h_next();
820 case 'C': return fd_char();
821 case 'D': return bk_char();
824 if (isdigit(c)) {
825 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
826 Repeat = Repeat * 10 + c - '0';
827 Pushed = 1;
828 PushBack = c;
829 return CSstay;
832 if (isupper(c))
833 return do_macro(c);
834 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
835 if (kp->Key == c)
836 return (*kp->Function)();
838 return ring_bell();
841 static el_STATUS
842 emacs(unsigned int c)
844 el_STATUS s;
845 KEYMAP *kp;
847 if (ISMETA(c)) {
848 Pushed = 1;
849 PushBack = UNMETA(c);
850 return meta();
852 for (kp = Map; kp->Function; kp++)
853 if (kp->Key == c)
854 break;
855 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
856 if (!Pushed)
857 /* No pushback means no repeat count; hacky, but true. */
858 Repeat = NO_ARG;
859 return s;
862 static el_STATUS
863 TTYspecial(unsigned int c)
865 if (ISMETA(c))
866 return CSdispatch;
868 if (c == rl_erase || c == DEL)
869 return bk_del_char();
870 if (c == rl_kill) {
871 if (Point != 0) {
872 Point = 0;
873 reposition();
875 Repeat = NO_ARG;
876 return kill_line();
878 if (c == rl_intr || c == rl_quit) {
879 Point = End = 0;
880 Line[0] = '\0';
881 return redisplay();
883 if (c == rl_eof && Point == 0 && End == 0)
884 return CSeof;
886 return CSdispatch;
889 static unsigned char *
890 editinput()
892 unsigned int c;
894 Repeat = NO_ARG;
895 OldPoint = Point = Mark = End = 0;
896 Line[0] = '\0';
898 while ((c = TTYget()) != EOF)
899 switch (TTYspecial(c)) {
900 case CSdone:
901 return Line;
902 case CSeof:
903 return NULL;
904 case CSmove:
905 reposition();
906 break;
907 case CSdispatch:
908 switch (emacs(c)) {
909 case CSdone:
910 return Line;
911 case CSeof:
912 return NULL;
913 case CSmove:
914 reposition();
915 break;
916 case CSdispatch:
917 case CSstay:
918 break;
920 break;
921 case CSstay:
922 break;
924 return NULL;
927 static void
928 hist_add(unsigned char *p)
930 int i;
932 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
933 return;
934 if (H.Size < HIST_SIZE)
935 H.Lines[H.Size++] = p;
936 else {
937 free(H.Lines[0]);
938 for (i = 0; i < HIST_SIZE - 1; i++)
939 H.Lines[i] = H.Lines[i + 1];
940 H.Lines[i] = p;
942 H.Pos = H.Size - 1;
946 ** For compatibility with FSF readline.
948 /* ARGSUSED0 */
949 void
950 rl_reset_terminal(char *p)
954 void
955 rl_initialize(void)
959 char *
960 readline(const char* prompt)
962 unsigned char *line;
964 if (Line == NULL) {
965 Length = MEM_INC;
966 if ((Line = malloc(Length)) == NULL)
967 return NULL;
970 TTYinfo();
971 rl_ttyset(0);
972 hist_add(NIL);
973 ScreenSize = SCREEN_INC;
974 Screen = malloc(ScreenSize);
975 Prompt = prompt ? prompt : (char *)NIL;
976 TTYputs(Prompt);
977 if ((line = editinput()) != NULL) {
978 line = (unsigned char *)strdup((char *)line);
979 TTYputs(NEWLINE);
980 TTYflush();
982 rl_ttyset(1);
983 free(Screen);
984 free(H.Lines[--H.Size]);
985 return (char *)line;
988 void
989 add_history(char *p)
991 if (p == NULL || *p == '\0')
992 return;
994 #if defined(UNIQUE_HISTORY)
995 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
996 return;
997 #endif /* defined(UNIQUE_HISTORY) */
998 hist_add((unsigned char *)p);
1002 static el_STATUS
1003 beg_line()
1005 if (Point) {
1006 Point = 0;
1007 return CSmove;
1009 return CSstay;
1012 static el_STATUS
1013 del_char()
1015 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1018 static el_STATUS
1019 end_line()
1021 if (Point != End) {
1022 Point = End;
1023 return CSmove;
1025 return CSstay;
1029 ** Move back to the beginning of the current word and return an
1030 ** allocated copy of it.
1032 static unsigned char *
1033 find_word()
1035 static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
1036 unsigned char *p;
1037 unsigned char *new;
1038 size_t len;
1040 for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
1041 continue;
1042 len = Point - (p - Line) + 1;
1043 if ((new = malloc(len)) == NULL)
1044 return NULL;
1045 memcpy(new, p, len);
1046 new[len - 1] = '\0';
1047 return new;
1050 static el_STATUS
1051 c_complete()
1053 unsigned char *p;
1054 unsigned char *word;
1055 int unique;
1056 el_STATUS s;
1058 word = find_word();
1059 p = (unsigned char *)rl_complete((char *)word, &unique);
1060 if (word)
1061 free(word);
1062 if (p && *p) {
1063 s = insert_string(p);
1064 if (!unique)
1065 ring_bell();
1066 free(p);
1067 return s;
1069 return ring_bell();
1072 static el_STATUS
1073 c_possible()
1075 unsigned char **av;
1076 unsigned char *word;
1077 int ac;
1079 word = find_word();
1080 ac = rl_list_possib((char *)word, (char ***)&av);
1081 if (word)
1082 free(word);
1083 if (ac) {
1084 columns(ac, av);
1085 while (--ac >= 0)
1086 free(av[ac]);
1087 free(av);
1088 return CSmove;
1090 return ring_bell();
1093 static el_STATUS
1094 accept_line()
1096 Line[End] = '\0';
1097 return CSdone;
1100 static el_STATUS
1101 transpose()
1103 unsigned char c;
1105 if (Point) {
1106 if (Point == End)
1107 left(CSmove);
1108 c = Line[Point - 1];
1109 left(CSstay);
1110 Line[Point - 1] = Line[Point];
1111 TTYshow(Line[Point - 1]);
1112 Line[Point++] = c;
1113 TTYshow(c);
1115 return CSstay;
1118 static el_STATUS
1119 quote()
1121 unsigned int c;
1123 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1126 static el_STATUS
1127 wipe()
1129 int i;
1131 if (Mark > End)
1132 return ring_bell();
1134 if (Point > Mark) {
1135 i = Point;
1136 Point = Mark;
1137 Mark = i;
1138 reposition();
1141 return delete_string(Mark - Point);
1144 static el_STATUS
1145 mk_set()
1147 Mark = Point;
1148 return CSstay;
1151 static el_STATUS
1152 exchange()
1154 unsigned int c;
1156 if ((c = TTYget()) != CTL('X'))
1157 return c == EOF ? CSeof : ring_bell();
1159 if ((c = Mark) <= End) {
1160 Mark = Point;
1161 Point = c;
1162 return CSmove;
1164 return CSstay;
1167 static el_STATUS
1168 yank()
1170 if (Yanked && *Yanked)
1171 return insert_string(Yanked);
1172 return CSstay;
1175 static el_STATUS
1176 copy_region()
1178 if (Mark > End)
1179 return ring_bell();
1181 if (Point > Mark)
1182 save_yank(Mark, Point - Mark);
1183 else
1184 save_yank(Point, Mark - Point);
1186 return CSstay;
1189 static el_STATUS
1190 move_to_char()
1192 unsigned int c;
1193 int i;
1194 unsigned char *p;
1196 if ((c = TTYget()) == EOF)
1197 return CSeof;
1198 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1199 if (*p == c) {
1200 Point = i;
1201 return CSmove;
1203 return CSstay;
1206 static el_STATUS
1207 fd_word()
1209 return do_forward(CSmove);
1212 static el_STATUS
1213 fd_kill_word()
1215 int i;
1217 do_forward(CSstay);
1218 if (OldPoint != Point) {
1219 i = Point - OldPoint;
1220 Point = OldPoint;
1221 return delete_string(i);
1223 return CSstay;
1226 static el_STATUS
1227 bk_word()
1229 int i;
1230 unsigned char *p;
1232 i = 0;
1233 do {
1234 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1235 left(CSmove);
1237 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1238 left(CSmove);
1240 if (Point == 0)
1241 break;
1242 } while (++i < Repeat);
1244 return CSstay;
1247 static el_STATUS
1248 bk_kill_word()
1250 bk_word();
1251 if (OldPoint != Point)
1252 return delete_string(OldPoint - Point);
1253 return CSstay;
1256 static int
1257 argify(unsigned char *line, unsigned char ***avp)
1259 unsigned char *c;
1260 unsigned char **p;
1261 unsigned char **new;
1262 int ac;
1263 int i;
1265 i = MEM_INC;
1266 if ((*avp = p = malloc(sizeof(unsigned char*) * i))== NULL)
1267 return 0;
1269 for (c = line; isspace(*c); c++)
1270 continue;
1271 if (*c == '\n' || *c == '\0')
1272 return 0;
1274 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1275 if (isspace(*c)) {
1276 *c++ = '\0';
1277 if (*c && *c != '\n') {
1278 if (ac + 1 == i) {
1279 new = malloc(sizeof(unsigned char*) * (i + MEM_INC));
1280 if (new == NULL) {
1281 p[ac] = NULL;
1282 return ac;
1284 memcpy(new, p, i * sizeof (char **));
1285 i += MEM_INC;
1286 free(p);
1287 *avp = p = new;
1289 p[ac++] = c;
1292 else
1293 c++;
1295 *c = '\0';
1296 p[ac] = NULL;
1297 return ac;
1300 static el_STATUS
1301 last_argument()
1303 unsigned char **av;
1304 unsigned char *p;
1305 el_STATUS s;
1306 int ac;
1308 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1309 return ring_bell();
1311 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
1312 return CSstay;
1313 ac = argify(p, &av);
1315 if (Repeat != NO_ARG)
1316 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1317 else
1318 s = ac ? insert_string(av[ac - 1]) : CSstay;
1320 if (ac)
1321 free(av);
1322 free(p);
1323 return s;
1326 static KEYMAP Map[33] = {
1327 { CTL('@'), ring_bell },
1328 { CTL('A'), beg_line },
1329 { CTL('B'), bk_char },
1330 { CTL('D'), del_char },
1331 { CTL('E'), end_line },
1332 { CTL('F'), fd_char },
1333 { CTL('G'), ring_bell },
1334 { CTL('H'), bk_del_char },
1335 { CTL('I'), c_complete },
1336 { CTL('J'), accept_line },
1337 { CTL('K'), kill_line },
1338 { CTL('L'), redisplay },
1339 { CTL('M'), accept_line },
1340 { CTL('N'), h_next },
1341 { CTL('O'), ring_bell },
1342 { CTL('P'), h_prev },
1343 { CTL('Q'), ring_bell },
1344 { CTL('R'), h_search },
1345 { CTL('S'), ring_bell },
1346 { CTL('T'), transpose },
1347 { CTL('U'), ring_bell },
1348 { CTL('V'), quote },
1349 { CTL('W'), wipe },
1350 { CTL('X'), exchange },
1351 { CTL('Y'), yank },
1352 { CTL('Z'), ring_bell },
1353 { CTL('['), meta },
1354 { CTL(']'), move_to_char },
1355 { CTL('^'), ring_bell },
1356 { CTL('_'), ring_bell },
1357 { 0, NULL }
1360 static KEYMAP MetaMap[16]= {
1361 { CTL('H'), bk_kill_word },
1362 { DEL, bk_kill_word },
1363 { ' ', mk_set },
1364 { '.', last_argument },
1365 { '<', h_first },
1366 { '>', h_last },
1367 { '?', c_possible },
1368 { 'b', bk_word },
1369 { 'd', fd_kill_word },
1370 { 'f', fd_word },
1371 { 'l', case_down_word },
1372 { 'u', case_up_word },
1373 { 'y', yank },
1374 { 'w', copy_region },
1375 { 0, NULL }