No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / editline / editline.c
blob283b8f04145e5f9823a1d9cdec36452a613100f2
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("$Heimdal: editline.c 15581 2005-07-07 20:55:18Z lha $"
29 "$NetBSD$");
32 ** Manifest constants.
34 #define SCREEN_WIDTH 80
35 #define SCREEN_ROWS 24
36 #define NO_ARG (-1)
37 #define DEL 127
38 #define CTL(x) ((x) & 0x1F)
39 #define ISCTL(x) ((x) && (x) < ' ')
40 #define UNCTL(x) ((x) + 64)
41 #define META(x) ((x) | 0x80)
42 #define ISMETA(x) ((x) & 0x80)
43 #define UNMETA(x) ((x) & 0x7F)
44 #if !defined(HIST_SIZE)
45 #define HIST_SIZE 20
46 #endif /* !defined(HIST_SIZE) */
49 ** Command status codes.
51 typedef enum _el_STATUS {
52 CSdone, CSeof, CSmove, CSdispatch, CSstay
53 } el_STATUS;
56 ** The type of case-changing to perform.
58 typedef enum _CASE {
59 TOupper, TOlower
60 } CASE;
63 ** Key to command mapping.
65 typedef struct _KEYMAP {
66 unsigned char Key;
67 el_STATUS (*Function)(void);
68 } KEYMAP;
71 ** Command history structure.
73 typedef struct _HISTORY {
74 int Size;
75 int Pos;
76 unsigned char *Lines[HIST_SIZE];
77 } HISTORY;
80 ** Globals.
82 int rl_eof;
83 int rl_erase;
84 int rl_intr;
85 int rl_kill;
87 static unsigned char NIL[] = "";
88 static const unsigned char *Input = NIL;
89 static unsigned char *Line;
90 static const char *Prompt;
91 static unsigned char *Yanked;
92 static char *Screen;
93 static char NEWLINE[]= CRLF;
94 static HISTORY H;
95 int rl_quit;
96 static int Repeat;
97 static int End;
98 static int Mark;
99 static int OldPoint;
100 static int Point;
101 static int PushBack;
102 static int Pushed;
103 static KEYMAP Map[33];
104 static KEYMAP MetaMap[16];
105 static size_t Length;
106 static size_t ScreenCount;
107 static size_t ScreenSize;
108 static char *backspace;
109 static int TTYwidth;
110 static int TTYrows;
112 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
113 int rl_meta_chars = 1;
116 ** Declarations.
118 static unsigned char *editinput(void);
119 char *tgetstr(const char*, char**);
120 int tgetent(char*, const char*);
121 int tgetnum(const char*);
124 ** TTY input/output functions.
127 static void
128 TTYflush(void)
130 if (ScreenCount) {
131 write(1, Screen, ScreenCount);
132 ScreenCount = 0;
136 static void
137 TTYput(unsigned char c)
139 Screen[ScreenCount] = c;
140 if (++ScreenCount >= ScreenSize - 1) {
141 ScreenSize += SCREEN_INC;
142 Screen = realloc(Screen, ScreenSize);
146 static void
147 TTYputs(const char *p)
149 while (*p)
150 TTYput(*p++);
153 static void
154 TTYshow(unsigned char c)
156 if (c == DEL) {
157 TTYput('^');
158 TTYput('?');
160 else if (ISCTL(c)) {
161 TTYput('^');
162 TTYput(UNCTL(c));
164 else if (rl_meta_chars && ISMETA(c)) {
165 TTYput('M');
166 TTYput('-');
167 TTYput(UNMETA(c));
169 else
170 TTYput(c);
173 static void
174 TTYstring(unsigned char *p)
176 while (*p)
177 TTYshow(*p++);
180 static int
181 TTYget(void)
183 unsigned char c;
184 int e;
186 TTYflush();
187 if (Pushed) {
188 Pushed = 0;
189 return PushBack;
191 if (*Input)
192 return *Input++;
193 do {
194 e = read(0, &c, 1);
195 } while(e < 0 && errno == EINTR);
196 if(e == 1)
197 return c;
198 return EOF;
201 static void
202 TTYback(void)
204 if (backspace)
205 TTYputs(backspace);
206 else
207 TTYput('\b');
210 static void
211 TTYbackn(int n)
213 while (--n >= 0)
214 TTYback();
217 static void
218 TTYinfo(void)
220 static int init;
221 #if defined(TIOCGWINSZ)
222 struct winsize W;
223 #endif /* defined(TIOCGWINSZ) */
225 if (init) {
226 #if defined(TIOCGWINSZ)
227 /* Perhaps we got resized. */
228 if (ioctl(0, TIOCGWINSZ, &W) >= 0
229 && W.ws_col > 0 && W.ws_row > 0) {
230 TTYwidth = (int)W.ws_col;
231 TTYrows = (int)W.ws_row;
233 #endif /* defined(TIOCGWINSZ) */
234 return;
236 init++;
238 #ifdef HAVE_TGETENT
240 char buff[2048];
241 char *tmp;
242 char *bp;
243 const char *term;
245 TTYwidth = TTYrows = 0;
246 bp = &buff[0];
247 if ((term = getenv("TERM")) == NULL)
248 term = "dumb";
249 if (tgetent(buff, term) >= 0) {
251 tmp = tgetstr("le", &bp);
252 if (tmp != NULL)
253 backspace = strdup(tmp);
254 TTYwidth = tgetnum("co");
255 TTYrows = tgetnum("li");
256 return;
259 #endif
261 #if defined(TIOCGWINSZ)
262 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
263 TTYwidth = (int)W.ws_col;
264 TTYrows = (int)W.ws_row;
266 #endif /* defined(TIOCGWINSZ) */
268 if (TTYwidth <= 0 || TTYrows <= 0) {
269 TTYwidth = SCREEN_WIDTH;
270 TTYrows = SCREEN_ROWS;
276 ** Print an array of words in columns.
278 static void
279 columns(int ac, unsigned char **av)
281 unsigned char *p;
282 int i;
283 int j;
284 int k;
285 int len;
286 int skip;
287 int longest;
288 int cols;
290 /* Find longest name, determine column count from that. */
291 for (longest = 0, i = 0; i < ac; i++)
292 if ((j = strlen((char *)av[i])) > longest)
293 longest = j;
294 cols = TTYwidth / (longest + 3);
296 TTYputs(NEWLINE);
297 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
298 for (j = i; j < ac; j += skip) {
299 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
300 TTYput(*p);
301 if (j + skip < ac)
302 while (++len < longest + 3)
303 TTYput(' ');
305 TTYputs(NEWLINE);
309 static void
310 reposition(void)
312 int i;
313 unsigned char *p;
315 TTYput('\r');
316 TTYputs(Prompt);
317 for (i = Point, p = Line; --i >= 0; p++)
318 TTYshow(*p);
321 static void
322 left(el_STATUS Change)
324 TTYback();
325 if (Point) {
326 if (ISCTL(Line[Point - 1]))
327 TTYback();
328 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
329 TTYback();
330 TTYback();
333 if (Change == CSmove)
334 Point--;
337 static void
338 right(el_STATUS Change)
340 TTYshow(Line[Point]);
341 if (Change == CSmove)
342 Point++;
345 static el_STATUS
346 ring_bell(void)
348 TTYput('\07');
349 TTYflush();
350 return CSstay;
353 static el_STATUS
354 do_macro(unsigned char c)
356 unsigned char name[4];
358 name[0] = '_';
359 name[1] = c;
360 name[2] = '_';
361 name[3] = '\0';
363 if ((Input = (unsigned char *)getenv((char *)name)) == NULL) {
364 Input = NIL;
365 return ring_bell();
367 return CSstay;
370 static el_STATUS
371 do_forward(el_STATUS move)
373 int i;
374 unsigned char *p;
376 i = 0;
377 do {
378 p = &Line[Point];
379 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
380 if (move == CSmove)
381 right(CSstay);
383 for (; Point < End && isalnum(*p); Point++, p++)
384 if (move == CSmove)
385 right(CSstay);
387 if (Point == End)
388 break;
389 } while (++i < Repeat);
391 return CSstay;
394 static el_STATUS
395 do_case(CASE type)
397 int i;
398 int end;
399 int count;
400 unsigned char *p;
402 do_forward(CSstay);
403 if (OldPoint != Point) {
404 if ((count = Point - OldPoint) < 0)
405 count = -count;
406 Point = OldPoint;
407 if ((end = Point + count) > End)
408 end = End;
409 for (i = Point, p = &Line[i]; i < end; i++, p++) {
410 if (type == TOupper) {
411 if (islower(*p))
412 *p = toupper(*p);
414 else if (isupper(*p))
415 *p = tolower(*p);
416 right(CSmove);
419 return CSstay;
422 static el_STATUS
423 case_down_word(void)
425 return do_case(TOlower);
428 static el_STATUS
429 case_up_word(void)
431 return do_case(TOupper);
434 static void
435 ceol(void)
437 int extras;
438 int i;
439 unsigned char *p;
441 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
442 TTYput(' ');
443 if (ISCTL(*p)) {
444 TTYput(' ');
445 extras++;
447 else if (rl_meta_chars && ISMETA(*p)) {
448 TTYput(' ');
449 TTYput(' ');
450 extras += 2;
454 for (i += extras; i > Point; i--)
455 TTYback();
458 static void
459 clear_line(void)
461 Point = -strlen(Prompt);
462 TTYput('\r');
463 ceol();
464 Point = 0;
465 End = 0;
466 Line[0] = '\0';
469 static el_STATUS
470 insert_string(unsigned char *p)
472 size_t len;
473 int i;
474 unsigned char *new;
475 unsigned char *q;
477 len = strlen((char *)p);
478 if (End + len >= Length) {
479 if ((new = malloc(sizeof(unsigned char) * (Length + len + MEM_INC))) == NULL)
480 return CSstay;
481 if (Length) {
482 memcpy(new, Line, Length);
483 free(Line);
485 Line = new;
486 Length += len + MEM_INC;
489 for (q = &Line[Point], i = End - Point; --i >= 0; )
490 q[len + i] = q[i];
491 memcpy(&Line[Point], p, len);
492 End += len;
493 Line[End] = '\0';
494 TTYstring(&Line[Point]);
495 Point += len;
497 return Point == End ? CSstay : CSmove;
501 static unsigned char *
502 next_hist(void)
504 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
507 static unsigned char *
508 prev_hist(void)
510 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
513 static el_STATUS
514 do_insert_hist(unsigned char *p)
516 if (p == NULL)
517 return ring_bell();
518 Point = 0;
519 reposition();
520 ceol();
521 End = 0;
522 return insert_string(p);
525 static el_STATUS
526 do_hist(unsigned char *(*move)(void))
528 unsigned char *p;
529 int i;
531 i = 0;
532 do {
533 if ((p = (*move)()) == NULL)
534 return ring_bell();
535 } while (++i < Repeat);
536 return do_insert_hist(p);
539 static el_STATUS
540 h_next(void)
542 return do_hist(next_hist);
545 static el_STATUS
546 h_prev(void)
548 return do_hist(prev_hist);
551 static el_STATUS
552 h_first(void)
554 return do_insert_hist(H.Lines[H.Pos = 0]);
557 static el_STATUS
558 h_last(void)
560 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
564 ** Return zero if pat appears as a substring in text.
566 static int
567 substrcmp(const char *text, const char *pat, size_t len)
569 char c;
571 if ((c = *pat) == '\0')
572 return *text == '\0';
573 for ( ; *text; text++)
574 if (*text == c && strncmp(text, pat, len) == 0)
575 return 0;
576 return 1;
579 static unsigned char *
580 search_hist(unsigned char *search, unsigned char *(*move)(void))
582 static unsigned char *old_search;
583 int len;
584 int pos;
585 int (*match)(const char *, const char *, size_t);
586 char *pat;
588 /* Save or get remembered search pattern. */
589 if (search && *search) {
590 if (old_search)
591 free(old_search);
592 old_search = (unsigned char *)strdup((char *)search);
594 else {
595 if (old_search == NULL || *old_search == '\0')
596 return NULL;
597 search = old_search;
600 /* Set up pattern-finder. */
601 if (*search == '^') {
602 match = strncmp;
603 pat = (char *)(search + 1);
605 else {
606 match = substrcmp;
607 pat = (char *)search;
609 len = strlen(pat);
611 for (pos = H.Pos; (*move)() != NULL; )
612 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
613 return H.Lines[H.Pos];
614 H.Pos = pos;
615 return NULL;
618 static el_STATUS
619 h_search(void)
621 static int Searching;
622 const char *old_prompt;
623 unsigned char *(*move)(void);
624 unsigned char *p;
626 if (Searching)
627 return ring_bell();
628 Searching = 1;
630 clear_line();
631 old_prompt = Prompt;
632 Prompt = "Search: ";
633 TTYputs(Prompt);
634 move = Repeat == NO_ARG ? prev_hist : next_hist;
635 p = search_hist(editinput(), move);
636 clear_line();
637 Prompt = old_prompt;
638 TTYputs(Prompt);
640 Searching = 0;
641 return do_insert_hist(p);
644 static el_STATUS
645 fd_char(void)
647 int i;
649 i = 0;
650 do {
651 if (Point >= End)
652 break;
653 right(CSmove);
654 } while (++i < Repeat);
655 return CSstay;
658 static void
659 save_yank(int begin, int i)
661 if (Yanked) {
662 free(Yanked);
663 Yanked = NULL;
666 if (i < 1)
667 return;
669 if ((Yanked = malloc(sizeof(unsigned char) * (i + 1))) != NULL) {
670 memcpy(Yanked, &Line[begin], i);
671 Yanked[i+1] = '\0';
675 static el_STATUS
676 delete_string(int count)
678 int i;
679 unsigned char *p;
681 if (count <= 0 || End == Point)
682 return ring_bell();
684 if (count == 1 && Point == End - 1) {
685 /* Optimize common case of delete at end of line. */
686 End--;
687 p = &Line[Point];
688 i = 1;
689 TTYput(' ');
690 if (ISCTL(*p)) {
691 i = 2;
692 TTYput(' ');
694 else if (rl_meta_chars && ISMETA(*p)) {
695 i = 3;
696 TTYput(' ');
697 TTYput(' ');
699 TTYbackn(i);
700 *p = '\0';
701 return CSmove;
703 if (Point + count > End && (count = End - Point) <= 0)
704 return CSstay;
706 if (count > 1)
707 save_yank(Point, count);
709 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
710 p[0] = p[count];
711 ceol();
712 End -= count;
713 TTYstring(&Line[Point]);
714 return CSmove;
717 static el_STATUS
718 bk_char(void)
720 int i;
722 i = 0;
723 do {
724 if (Point == 0)
725 break;
726 left(CSmove);
727 } while (++i < Repeat);
729 return CSstay;
732 static el_STATUS
733 bk_del_char(void)
735 int i;
737 i = 0;
738 do {
739 if (Point == 0)
740 break;
741 left(CSmove);
742 } while (++i < Repeat);
744 return delete_string(i);
747 static el_STATUS
748 redisplay(void)
750 TTYputs(NEWLINE);
751 TTYputs(Prompt);
752 TTYstring(Line);
753 return CSmove;
756 static el_STATUS
757 kill_line(void)
759 int i;
761 if (Repeat != NO_ARG) {
762 if (Repeat < Point) {
763 i = Point;
764 Point = Repeat;
765 reposition();
766 delete_string(i - Point);
768 else if (Repeat > Point) {
769 right(CSmove);
770 delete_string(Repeat - Point - 1);
772 return CSmove;
775 save_yank(Point, End - Point);
776 Line[Point] = '\0';
777 ceol();
778 End = Point;
779 return CSstay;
782 static el_STATUS
783 insert_char(int c)
785 el_STATUS s;
786 unsigned char buff[2];
787 unsigned char *p;
788 unsigned char *q;
789 int i;
791 if (Repeat == NO_ARG || Repeat < 2) {
792 buff[0] = c;
793 buff[1] = '\0';
794 return insert_string(buff);
797 if ((p = malloc(Repeat + 1)) == NULL)
798 return CSstay;
799 for (i = Repeat, q = p; --i >= 0; )
800 *q++ = c;
801 *q = '\0';
802 Repeat = 0;
803 s = insert_string(p);
804 free(p);
805 return s;
808 static el_STATUS
809 meta(void)
811 unsigned int c;
812 KEYMAP *kp;
814 if ((c = TTYget()) == EOF)
815 return CSeof;
816 /* Also include VT-100 arrows. */
817 if (c == '[' || c == 'O')
818 switch (c = TTYget()) {
819 default: return ring_bell();
820 case EOF: return CSeof;
821 case 'A': return h_prev();
822 case 'B': return h_next();
823 case 'C': return fd_char();
824 case 'D': return bk_char();
827 if (isdigit(c)) {
828 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
829 Repeat = Repeat * 10 + c - '0';
830 Pushed = 1;
831 PushBack = c;
832 return CSstay;
835 if (isupper(c))
836 return do_macro(c);
837 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
838 if (kp->Key == c)
839 return (*kp->Function)();
841 return ring_bell();
844 static el_STATUS
845 emacs(unsigned int c)
847 el_STATUS s;
848 KEYMAP *kp;
850 if (ISMETA(c)) {
851 Pushed = 1;
852 PushBack = UNMETA(c);
853 return meta();
855 for (kp = Map; kp->Function; kp++)
856 if (kp->Key == c)
857 break;
858 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
859 if (!Pushed)
860 /* No pushback means no repeat count; hacky, but true. */
861 Repeat = NO_ARG;
862 return s;
865 static el_STATUS
866 TTYspecial(unsigned int c)
868 if (ISMETA(c))
869 return CSdispatch;
871 if (c == rl_erase || c == DEL)
872 return bk_del_char();
873 if (c == rl_kill) {
874 if (Point != 0) {
875 Point = 0;
876 reposition();
878 Repeat = NO_ARG;
879 return kill_line();
881 if (c == rl_intr || c == rl_quit) {
882 Point = End = 0;
883 Line[0] = '\0';
884 return redisplay();
886 if (c == rl_eof && Point == 0 && End == 0)
887 return CSeof;
889 return CSdispatch;
892 static unsigned char *
893 editinput(void)
895 unsigned int c;
897 Repeat = NO_ARG;
898 OldPoint = Point = Mark = End = 0;
899 Line[0] = '\0';
901 while ((c = TTYget()) != EOF)
902 switch (TTYspecial(c)) {
903 case CSdone:
904 return Line;
905 case CSeof:
906 return NULL;
907 case CSmove:
908 reposition();
909 break;
910 case CSdispatch:
911 switch (emacs(c)) {
912 case CSdone:
913 return Line;
914 case CSeof:
915 return NULL;
916 case CSmove:
917 reposition();
918 break;
919 case CSdispatch:
920 case CSstay:
921 break;
923 break;
924 case CSstay:
925 break;
927 return NULL;
930 static void
931 hist_add(unsigned char *p)
933 int i;
935 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
936 return;
937 if (H.Size < HIST_SIZE)
938 H.Lines[H.Size++] = p;
939 else {
940 free(H.Lines[0]);
941 for (i = 0; i < HIST_SIZE - 1; i++)
942 H.Lines[i] = H.Lines[i + 1];
943 H.Lines[i] = p;
945 H.Pos = H.Size - 1;
949 ** For compatibility with FSF readline.
951 /* ARGSUSED0 */
952 void
953 rl_reset_terminal(char *p)
957 void
958 rl_initialize(void)
962 char *
963 readline(const char* prompt)
965 unsigned char *line;
967 if (Line == NULL) {
968 Length = MEM_INC;
969 if ((Line = malloc(Length)) == NULL)
970 return NULL;
973 TTYinfo();
974 rl_ttyset(0);
975 hist_add(NIL);
976 ScreenSize = SCREEN_INC;
977 Screen = malloc(ScreenSize);
978 Prompt = prompt ? prompt : (char *)NIL;
979 TTYputs(Prompt);
980 if ((line = editinput()) != NULL) {
981 line = (unsigned char *)strdup((char *)line);
982 TTYputs(NEWLINE);
983 TTYflush();
985 rl_ttyset(1);
986 free(Screen);
987 free(H.Lines[--H.Size]);
988 return (char *)line;
991 void
992 add_history(char *p)
994 if (p == NULL || *p == '\0')
995 return;
997 #if defined(UNIQUE_HISTORY)
998 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
999 return;
1000 #endif /* defined(UNIQUE_HISTORY) */
1001 hist_add((unsigned char *)p);
1005 static el_STATUS
1006 beg_line(void)
1008 if (Point) {
1009 Point = 0;
1010 return CSmove;
1012 return CSstay;
1015 static el_STATUS
1016 del_char(void)
1018 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1021 static el_STATUS
1022 end_line(void)
1024 if (Point != End) {
1025 Point = End;
1026 return CSmove;
1028 return CSstay;
1032 ** Move back to the beginning of the current word and return an
1033 ** allocated copy of it.
1035 static unsigned char *
1036 find_word(void)
1038 static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
1039 unsigned char *p;
1040 unsigned char *new;
1041 size_t len;
1043 for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
1044 continue;
1045 len = Point - (p - Line) + 1;
1046 if ((new = malloc(len)) == NULL)
1047 return NULL;
1048 memcpy(new, p, len);
1049 new[len - 1] = '\0';
1050 return new;
1053 static el_STATUS
1054 c_complete(void)
1056 unsigned char *p;
1057 unsigned char *word;
1058 int unique;
1059 el_STATUS s;
1061 word = find_word();
1062 p = (unsigned char *)rl_complete((char *)word, &unique);
1063 if (word)
1064 free(word);
1065 if (p && *p) {
1066 s = insert_string(p);
1067 if (!unique)
1068 ring_bell();
1069 free(p);
1070 return s;
1072 return ring_bell();
1075 static el_STATUS
1076 c_possible(void)
1078 unsigned char **av;
1079 unsigned char *word;
1080 int ac;
1082 word = find_word();
1083 ac = rl_list_possib((char *)word, (void *)&av);
1084 if (word)
1085 free(word);
1086 if (ac) {
1087 columns(ac, av);
1088 while (--ac >= 0)
1089 free(av[ac]);
1090 free(av);
1091 return CSmove;
1093 return ring_bell();
1096 static el_STATUS
1097 accept_line(void)
1099 Line[End] = '\0';
1100 return CSdone;
1103 static el_STATUS
1104 transpose(void)
1106 unsigned char c;
1108 if (Point) {
1109 if (Point == End)
1110 left(CSmove);
1111 c = Line[Point - 1];
1112 left(CSstay);
1113 Line[Point - 1] = Line[Point];
1114 TTYshow(Line[Point - 1]);
1115 Line[Point++] = c;
1116 TTYshow(c);
1118 return CSstay;
1121 static el_STATUS
1122 quote(void)
1124 unsigned int c;
1126 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1129 static el_STATUS
1130 wipe(void)
1132 int i;
1134 if (Mark > End)
1135 return ring_bell();
1137 if (Point > Mark) {
1138 i = Point;
1139 Point = Mark;
1140 Mark = i;
1141 reposition();
1144 return delete_string(Mark - Point);
1147 static el_STATUS
1148 mk_set(void)
1150 Mark = Point;
1151 return CSstay;
1154 static el_STATUS
1155 exchange(void)
1157 unsigned int c;
1159 if ((c = TTYget()) != CTL('X'))
1160 return c == EOF ? CSeof : ring_bell();
1162 if ((c = Mark) <= End) {
1163 Mark = Point;
1164 Point = c;
1165 return CSmove;
1167 return CSstay;
1170 static el_STATUS
1171 yank(void)
1173 if (Yanked && *Yanked)
1174 return insert_string(Yanked);
1175 return CSstay;
1178 static el_STATUS
1179 copy_region(void)
1181 if (Mark > End)
1182 return ring_bell();
1184 if (Point > Mark)
1185 save_yank(Mark, Point - Mark);
1186 else
1187 save_yank(Point, Mark - Point);
1189 return CSstay;
1192 static el_STATUS
1193 move_to_char(void)
1195 unsigned int c;
1196 int i;
1197 unsigned char *p;
1199 if ((c = TTYget()) == EOF)
1200 return CSeof;
1201 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1202 if (*p == c) {
1203 Point = i;
1204 return CSmove;
1206 return CSstay;
1209 static el_STATUS
1210 fd_word(void)
1212 return do_forward(CSmove);
1215 static el_STATUS
1216 fd_kill_word(void)
1218 int i;
1220 do_forward(CSstay);
1221 if (OldPoint != Point) {
1222 i = Point - OldPoint;
1223 Point = OldPoint;
1224 return delete_string(i);
1226 return CSstay;
1229 static el_STATUS
1230 bk_word(void)
1232 int i;
1233 unsigned char *p;
1235 i = 0;
1236 do {
1237 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1238 left(CSmove);
1240 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1241 left(CSmove);
1243 if (Point == 0)
1244 break;
1245 } while (++i < Repeat);
1247 return CSstay;
1250 static el_STATUS
1251 bk_kill_word(void)
1253 bk_word();
1254 if (OldPoint != Point)
1255 return delete_string(OldPoint - Point);
1256 return CSstay;
1259 static int
1260 argify(unsigned char *line, unsigned char ***avp)
1262 unsigned char *c;
1263 unsigned char **p;
1264 unsigned char **new;
1265 int ac;
1266 int i;
1268 i = MEM_INC;
1269 if ((*avp = p = malloc(sizeof(unsigned char*) * i))== NULL)
1270 return 0;
1272 for (c = line; isspace(*c); c++)
1273 continue;
1274 if (*c == '\n' || *c == '\0')
1275 return 0;
1277 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1278 if (isspace(*c)) {
1279 *c++ = '\0';
1280 if (*c && *c != '\n') {
1281 if (ac + 1 == i) {
1282 new = malloc(sizeof(unsigned char*) * (i + MEM_INC));
1283 if (new == NULL) {
1284 p[ac] = NULL;
1285 return ac;
1287 memcpy(new, p, i * sizeof (char **));
1288 i += MEM_INC;
1289 free(p);
1290 *avp = p = new;
1292 p[ac++] = c;
1295 else
1296 c++;
1298 *c = '\0';
1299 p[ac] = NULL;
1300 return ac;
1303 static el_STATUS
1304 last_argument(void)
1306 unsigned char **av;
1307 unsigned char *p;
1308 el_STATUS s;
1309 int ac;
1311 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1312 return ring_bell();
1314 if ((p = (unsigned char *)strdup((char *)p)) == NULL)
1315 return CSstay;
1316 ac = argify(p, &av);
1318 if (Repeat != NO_ARG)
1319 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1320 else
1321 s = ac ? insert_string(av[ac - 1]) : CSstay;
1323 if (ac)
1324 free(av);
1325 free(p);
1326 return s;
1329 static KEYMAP Map[33] = {
1330 { CTL('@'), ring_bell },
1331 { CTL('A'), beg_line },
1332 { CTL('B'), bk_char },
1333 { CTL('D'), del_char },
1334 { CTL('E'), end_line },
1335 { CTL('F'), fd_char },
1336 { CTL('G'), ring_bell },
1337 { CTL('H'), bk_del_char },
1338 { CTL('I'), c_complete },
1339 { CTL('J'), accept_line },
1340 { CTL('K'), kill_line },
1341 { CTL('L'), redisplay },
1342 { CTL('M'), accept_line },
1343 { CTL('N'), h_next },
1344 { CTL('O'), ring_bell },
1345 { CTL('P'), h_prev },
1346 { CTL('Q'), ring_bell },
1347 { CTL('R'), h_search },
1348 { CTL('S'), ring_bell },
1349 { CTL('T'), transpose },
1350 { CTL('U'), ring_bell },
1351 { CTL('V'), quote },
1352 { CTL('W'), wipe },
1353 { CTL('X'), exchange },
1354 { CTL('Y'), yank },
1355 { CTL('Z'), ring_bell },
1356 { CTL('['), meta },
1357 { CTL(']'), move_to_char },
1358 { CTL('^'), ring_bell },
1359 { CTL('_'), ring_bell },
1360 { 0, NULL }
1363 static KEYMAP MetaMap[16]= {
1364 { CTL('H'), bk_kill_word },
1365 { DEL, bk_kill_word },
1366 { ' ', mk_set },
1367 { '.', last_argument },
1368 { '<', h_first },
1369 { '>', h_last },
1370 { '?', c_possible },
1371 { 'b', bk_word },
1372 { 'd', fd_kill_word },
1373 { 'f', fd_word },
1374 { 'l', case_down_word },
1375 { 'u', case_up_word },
1376 { 'y', yank },
1377 { 'w', copy_region },
1378 { 0, NULL }