Release 960712
[wine/multimedia.git] / debugger / readline / editline.c
blobeea22d76a48372ea2b52aac171fd81bc3a58bb85
1 /* $Revision: 1.4 $
2 **
3 ** Main editing routines for editline library.
4 */
5 #include "editline.h"
6 #include <ctype.h>
7 #include <stdlib.h>
9 /*
10 ** Manifest constants.
12 #define SCREEN_WIDTH 80
13 #define SCREEN_ROWS 24
14 #define NO_ARG (-1)
15 #define DEL 127
16 #define CTL(x) ((x) & 0x1F)
17 #define ISCTL(x) ((x) && (x) < ' ')
18 #define UNCTL(x) ((x) + 64)
19 #define META(x) ((x) | 0x80)
20 #define ISMETA(x) ((x) & 0x80)
21 #define UNMETA(x) ((x) & 0x7F)
22 #if !defined(HIST_SIZE)
23 #define HIST_SIZE 20
24 #endif /* !defined(HIST_SIZE) */
27 ** Command status codes.
29 typedef enum _STATUS {
30 CSdone, CSeof, CSmove, CSdispatch, CSstay
31 } STATUS;
34 ** The type of case-changing to perform.
36 typedef enum _CASE {
37 TOupper, TOlower
38 } CASE;
41 ** Key to command mapping.
43 typedef struct _KEYMAP {
44 CHAR Key;
45 STATUS (*Function)();
46 } KEYMAP;
49 ** Command history structure.
51 typedef struct _HISTORY {
52 int Size;
53 int Pos;
54 CHAR *Lines[HIST_SIZE];
55 } HISTORY;
58 ** Globals.
60 int rl_eof;
61 int rl_erase;
62 int rl_intr;
63 int rl_kill;
65 STATIC CHAR NIL[] = "";
66 STATIC CONST CHAR *Input = NIL;
67 STATIC CHAR *Line;
68 STATIC CONST char *Prompt;
69 STATIC CHAR *Yanked;
70 STATIC char *Screen;
71 STATIC char NEWLINE[]= CRLF;
72 STATIC HISTORY H;
73 int rl_quit;
74 STATIC int Repeat;
75 STATIC int End;
76 STATIC int Mark;
77 STATIC int OldPoint;
78 STATIC int Point;
79 STATIC int PushBack;
80 STATIC int Pushed;
81 STATIC KEYMAP Map[33];
82 STATIC KEYMAP MetaMap[16];
83 STATIC SIZE_T Length;
84 STATIC SIZE_T ScreenCount;
85 STATIC SIZE_T ScreenSize;
86 STATIC char *backspace;
87 STATIC int TTYwidth;
88 STATIC int TTYrows;
90 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
91 int rl_meta_chars = 1;
94 ** Declarations.
96 STATIC CHAR *editinput();
97 extern int read();
98 extern int write();
99 #if defined(USE_TERMCAP)
100 extern char *getenv();
101 extern char *tgetstr();
102 extern int tgetent();
103 #endif /* defined(USE_TERMCAP) */
106 ** TTY input/output functions.
109 STATIC void
110 TTYflush()
112 if (ScreenCount) {
113 (void)write(1, Screen, ScreenCount);
114 ScreenCount = 0;
118 STATIC void
119 TTYput(c)
120 CHAR c;
122 Screen[ScreenCount] = c;
123 if (++ScreenCount >= ScreenSize - 1) {
124 ScreenSize += SCREEN_INC;
125 RENEW(Screen, char, ScreenSize);
129 STATIC void
130 TTYputs(p)
131 CHAR *p;
133 while (*p)
134 TTYput(*p++);
137 STATIC void
138 TTYshow(c)
139 CHAR c;
141 if (c == DEL) {
142 TTYput('^');
143 TTYput('?');
145 else if (ISCTL(c)) {
146 TTYput('^');
147 TTYput(UNCTL(c));
149 else if (rl_meta_chars && ISMETA(c)) {
150 TTYput('M');
151 TTYput('-');
152 TTYput(UNMETA(c));
154 else
155 TTYput(c);
158 STATIC void
159 TTYstring(p)
160 CHAR *p;
162 while (*p)
163 TTYshow(*p++);
166 STATIC unsigned int
167 TTYget()
169 CHAR c;
171 TTYflush();
172 if (Pushed) {
173 Pushed = 0;
174 return PushBack;
176 if (*Input)
177 return *Input++;
178 return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
181 #define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
183 STATIC void
184 TTYbackn(n)
185 int n;
187 while (--n >= 0)
188 TTYback();
191 STATIC void
192 TTYinfo()
194 static int init;
195 #if defined(USE_TERMCAP)
196 char *term;
197 char buff[2048];
198 char *bp;
199 #endif /* defined(USE_TERMCAP) */
200 #if defined(TIOCGWINSZ)
201 struct winsize W;
202 #endif /* defined(TIOCGWINSZ) */
204 if (init) {
205 #if defined(TIOCGWINSZ)
206 /* Perhaps we got resized. */
207 if (ioctl(0, TIOCGWINSZ, &W) >= 0
208 && W.ws_col > 0 && W.ws_row > 0) {
209 TTYwidth = (int)W.ws_col;
210 TTYrows = (int)W.ws_row;
212 #endif /* defined(TIOCGWINSZ) */
213 return;
215 init++;
217 TTYwidth = TTYrows = 0;
218 #if defined(USE_TERMCAP)
219 bp = &buff[0];
220 if ((term = getenv("TERM")) == NULL)
221 term = "dumb";
222 if (tgetent(buff, term) < 0) {
223 TTYwidth = SCREEN_WIDTH;
224 TTYrows = SCREEN_ROWS;
225 return;
227 backspace = tgetstr("le", &bp);
228 TTYwidth = tgetnum("co");
229 TTYrows = tgetnum("li");
230 #endif /* defined(USE_TERMCAP) */
232 #if defined(TIOCGWINSZ)
233 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
234 TTYwidth = (int)W.ws_col;
235 TTYrows = (int)W.ws_row;
237 #endif /* defined(TIOCGWINSZ) */
239 if (TTYwidth <= 0 || TTYrows <= 0) {
240 TTYwidth = SCREEN_WIDTH;
241 TTYrows = SCREEN_ROWS;
247 STATIC void
248 reposition()
250 int i;
251 CHAR *p;
253 TTYput('\r');
254 TTYputs((CHAR *)Prompt);
255 for (i = Point, p = Line; --i >= 0; p++)
256 TTYshow(*p);
259 STATIC void
260 left(Change)
261 STATUS Change;
263 TTYback();
264 if (Point) {
265 if (ISCTL(Line[Point - 1]))
266 TTYback();
267 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
268 TTYback();
269 TTYback();
272 if (Change == CSmove)
273 Point--;
276 STATIC void
277 right(Change)
278 STATUS Change;
280 TTYshow(Line[Point]);
281 if (Change == CSmove)
282 Point++;
285 STATIC STATUS
286 ring_bell()
288 TTYput('\07');
289 TTYflush();
290 return CSstay;
293 STATIC STATUS
294 do_macro(c)
295 unsigned int c;
297 CHAR name[4];
299 name[0] = '_';
300 name[1] = c;
301 name[2] = '_';
302 name[3] = '\0';
304 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
305 Input = NIL;
306 return ring_bell();
308 return CSstay;
311 STATIC STATUS
312 do_forward(move)
313 STATUS move;
315 int i;
316 CHAR *p;
318 i = 0;
319 do {
320 p = &Line[Point];
321 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
322 if (move == CSmove)
323 right(CSstay);
325 for (; Point < End && isalnum(*p); Point++, p++)
326 if (move == CSmove)
327 right(CSstay);
329 if (Point == End)
330 break;
331 } while (++i < Repeat);
333 return CSstay;
336 STATIC STATUS
337 do_case(type)
338 CASE type;
340 int i;
341 int end;
342 int count;
343 CHAR *p;
345 (void)do_forward(CSstay);
346 if (OldPoint != Point) {
347 if ((count = Point - OldPoint) < 0)
348 count = -count;
349 Point = OldPoint;
350 if ((end = Point + count) > End)
351 end = End;
352 for (i = Point, p = &Line[i]; i < end; i++, p++) {
353 if (type == TOupper) {
354 if (islower(*p))
355 *p = toupper(*p);
357 else if (isupper(*p))
358 *p = tolower(*p);
359 right(CSmove);
362 return CSstay;
365 STATIC STATUS
366 case_down_word()
368 return do_case(TOlower);
371 STATIC STATUS
372 case_up_word()
374 return do_case(TOupper);
377 STATIC void
378 ceol()
380 int extras;
381 int i;
382 CHAR *p;
384 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
385 TTYput(' ');
386 if (ISCTL(*p)) {
387 TTYput(' ');
388 extras++;
390 else if (rl_meta_chars && ISMETA(*p)) {
391 TTYput(' ');
392 TTYput(' ');
393 extras += 2;
397 for (i += extras; i > Point; i--)
398 TTYback();
401 STATIC void
402 clear_line()
404 Point = -strlen(Prompt);
405 TTYput('\r');
406 ceol();
407 Point = 0;
408 End = 0;
409 Line[0] = '\0';
412 STATIC STATUS
413 insert_string(p)
414 CHAR *p;
416 SIZE_T len;
417 int i;
418 CHAR *new;
419 CHAR *q;
421 len = strlen((char *)p);
422 if (End + len >= Length) {
423 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
424 return CSstay;
425 if (Length) {
426 COPYFROMTO(new, Line, Length);
427 DISPOSE(Line);
429 Line = new;
430 Length += len + MEM_INC;
433 for (q = &Line[Point], i = End - Point; --i >= 0; )
434 q[len + i] = q[i];
435 COPYFROMTO(&Line[Point], p, len);
436 End += len;
437 Line[End] = '\0';
438 TTYstring(&Line[Point]);
439 Point += len;
441 return Point == End ? CSstay : CSmove;
445 STATIC CHAR *
446 next_hist()
448 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
451 STATIC CHAR *
452 prev_hist()
454 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
457 STATIC STATUS
458 do_insert_hist(p)
459 CHAR *p;
461 if (p == NULL)
462 return ring_bell();
463 Point = 0;
464 reposition();
465 ceol();
466 End = 0;
467 return insert_string(p);
470 STATIC STATUS
471 do_hist(move)
472 CHAR *(*move)();
474 CHAR *p;
475 int i;
477 i = 0;
478 do {
479 if ((p = (*move)()) == NULL)
480 return ring_bell();
481 } while (++i < Repeat);
482 return do_insert_hist(p);
485 STATIC STATUS
486 h_next()
488 return do_hist(next_hist);
491 STATIC STATUS
492 h_prev()
494 return do_hist(prev_hist);
497 STATIC STATUS
498 h_first()
500 return do_insert_hist(H.Lines[H.Pos = 0]);
503 STATIC STATUS
504 h_last()
506 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
510 ** Return zero if pat appears as a substring in text.
512 STATIC int
513 substrcmp(text, pat, len)
514 char *text;
515 char *pat;
516 int len;
518 CHAR c;
520 if ((c = *pat) == '\0')
521 return *text == '\0';
522 for ( ; *text; text++)
523 if ((CHAR)*text == c && strncmp(text, pat, len) == 0)
524 return 0;
525 return 1;
528 STATIC CHAR *
529 search_hist(search, move)
530 CHAR *search;
531 CHAR *(*move)();
533 static CHAR *old_search;
534 int len;
535 int pos;
536 int (*match)();
537 char *pat;
539 /* Save or get remembered search pattern. */
540 if (search && *search) {
541 if (old_search)
542 DISPOSE(old_search);
543 old_search = (CHAR *)strdup((char *)search);
545 else {
546 if (old_search == NULL || *old_search == '\0')
547 return NULL;
548 search = old_search;
551 /* Set up pattern-finder. */
552 if (*search == '^') {
553 match = strncmp;
554 pat = (char *)(search + 1);
556 else {
557 match = substrcmp;
558 pat = (char *)search;
560 len = strlen(pat);
562 for (pos = H.Pos; (*move)() != NULL; )
563 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
564 return H.Lines[H.Pos];
565 H.Pos = pos;
566 return NULL;
569 STATIC STATUS
570 h_search()
572 static int Searching;
573 CONST char *old_prompt;
574 CHAR *(*move)();
575 CHAR *p;
577 if (Searching)
578 return ring_bell();
579 Searching = 1;
581 clear_line();
582 old_prompt = Prompt;
583 Prompt = "Search: ";
584 TTYputs((CHAR *)Prompt);
585 move = Repeat == NO_ARG ? prev_hist : next_hist;
586 p = search_hist(editinput(), move);
587 clear_line();
588 Prompt = old_prompt;
589 TTYputs((CHAR *)Prompt);
591 Searching = 0;
592 return do_insert_hist(p);
595 STATIC STATUS
596 fd_char()
598 int i;
600 i = 0;
601 do {
602 if (Point >= End)
603 break;
604 right(CSmove);
605 } while (++i < Repeat);
606 return CSstay;
609 STATIC void
610 save_yank(begin, i)
611 int begin;
612 int i;
614 if (Yanked) {
615 DISPOSE(Yanked);
616 Yanked = NULL;
619 if (i < 1)
620 return;
622 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
623 COPYFROMTO(Yanked, &Line[begin], i);
624 Yanked[i] = '\0';
628 STATIC STATUS
629 delete_string(count)
630 int count;
632 int i;
633 CHAR *p;
635 if (count <= 0 || End == Point)
636 return ring_bell();
638 if (count == 1 && Point == End - 1) {
639 /* Optimize common case of delete at end of line. */
640 End--;
641 p = &Line[Point];
642 i = 1;
643 TTYput(' ');
644 if (ISCTL(*p)) {
645 i = 2;
646 TTYput(' ');
648 else if (rl_meta_chars && ISMETA(*p)) {
649 i = 3;
650 TTYput(' ');
651 TTYput(' ');
653 TTYbackn(i);
654 *p = '\0';
655 return CSmove;
657 if (Point + count > End && (count = End - Point) <= 0)
658 return CSstay;
660 if (count > 1)
661 save_yank(Point, count);
663 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
664 p[0] = p[count];
665 ceol();
666 End -= count;
667 TTYstring(&Line[Point]);
668 return CSmove;
671 STATIC STATUS
672 bk_char()
674 int i;
676 i = 0;
677 do {
678 if (Point == 0)
679 break;
680 left(CSmove);
681 } while (++i < Repeat);
683 return CSstay;
686 STATIC STATUS
687 bk_del_char()
689 int i;
691 i = 0;
692 do {
693 if (Point == 0)
694 break;
695 left(CSmove);
696 } while (++i < Repeat);
698 return delete_string(i);
701 STATIC STATUS
702 redisplay()
704 TTYputs((CHAR *)NEWLINE);
705 TTYputs((CHAR *)Prompt);
706 TTYstring(Line);
707 return CSmove;
710 STATIC STATUS
711 kill_line()
713 int i;
715 if (Repeat != NO_ARG) {
716 if (Repeat < Point) {
717 i = Point;
718 Point = Repeat;
719 reposition();
720 (void)delete_string(i - Point);
722 else if (Repeat > Point) {
723 right(CSmove);
724 (void)delete_string(Repeat - Point - 1);
726 return CSmove;
729 save_yank(Point, End - Point);
730 Line[Point] = '\0';
731 ceol();
732 End = Point;
733 return CSstay;
736 STATIC STATUS
737 insert_char(c)
738 int c;
740 STATUS s;
741 CHAR buff[2];
742 CHAR *p;
743 CHAR *q;
744 int i;
746 if (Repeat == NO_ARG || Repeat < 2) {
747 buff[0] = c;
748 buff[1] = '\0';
749 return insert_string(buff);
752 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
753 return CSstay;
754 for (i = Repeat, q = p; --i >= 0; )
755 *q++ = c;
756 *q = '\0';
757 Repeat = 0;
758 s = insert_string(p);
759 DISPOSE(p);
760 return s;
763 STATIC STATUS
764 meta()
766 unsigned int c;
767 KEYMAP *kp;
769 if ((c = TTYget()) == EOF)
770 return CSeof;
771 #if defined(ANSI_ARROWS)
772 /* Also include VT-100 arrows. */
773 if (c == '[' || c == 'O')
774 switch (c = TTYget()) {
775 default: return ring_bell();
776 case EOF: return CSeof;
777 case 'A': return h_prev();
778 case 'B': return h_next();
779 case 'C': return fd_char();
780 case 'D': return bk_char();
782 #endif /* defined(ANSI_ARROWS) */
784 if (isdigit(c)) {
785 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
786 Repeat = Repeat * 10 + c - '0';
787 Pushed = 1;
788 PushBack = c;
789 return CSstay;
792 if (isupper(c))
793 return do_macro(c);
794 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
795 if (kp->Key == c)
796 return (*kp->Function)();
798 return ring_bell();
801 STATIC STATUS
802 emacs(c)
803 unsigned int c;
805 STATUS s;
806 KEYMAP *kp;
808 if (ISMETA(c)) {
809 Pushed = 1;
810 PushBack = UNMETA(c);
811 return meta();
813 for (kp = Map; kp->Function; kp++)
814 if (kp->Key == c)
815 break;
816 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
817 if (!Pushed)
818 /* No pushback means no repeat count; hacky, but true. */
819 Repeat = NO_ARG;
820 return s;
823 STATIC STATUS
824 TTYspecial(c)
825 unsigned int c;
827 if (ISMETA(c))
828 return CSdispatch;
830 if (c == rl_erase || c == DEL)
831 return bk_del_char();
832 if (c == rl_kill) {
833 if (Point != 0) {
834 Point = 0;
835 reposition();
837 Repeat = NO_ARG;
838 return kill_line();
840 if (c == rl_intr || c == rl_quit) {
841 Point = End = 0;
842 Line[0] = '\0';
843 return redisplay();
845 if (c == rl_eof && Point == 0 && End == 0)
846 return CSeof;
848 return CSdispatch;
851 STATIC CHAR *
852 editinput()
854 unsigned int c;
856 Repeat = NO_ARG;
857 OldPoint = Point = Mark = End = 0;
858 Line[0] = '\0';
860 while ((c = TTYget()) != EOF)
861 switch (TTYspecial(c)) {
862 case CSdone:
863 return Line;
864 case CSeof:
865 return NULL;
866 case CSmove:
867 reposition();
868 break;
869 case CSdispatch:
870 switch (emacs(c)) {
871 case CSdone:
872 return Line;
873 case CSeof:
874 return NULL;
875 case CSmove:
876 reposition();
877 break;
878 case CSdispatch:
879 case CSstay:
880 break;
882 break;
883 case CSstay:
884 break;
886 return NULL;
889 STATIC void
890 hist_add(p)
891 CHAR *p;
893 int i;
895 if ((p = (CHAR *)strdup((char *)p)) == NULL)
896 return;
897 if (H.Size < HIST_SIZE)
898 H.Lines[H.Size++] = p;
899 else {
900 DISPOSE(H.Lines[0]);
901 for (i = 0; i < HIST_SIZE - 1; i++)
902 H.Lines[i] = H.Lines[i + 1];
903 H.Lines[i] = p;
905 H.Pos = H.Size - 1;
909 ** For compatibility with FSF readline.
911 /* ARGSUSED0 */
912 void
913 rl_reset_terminal(p)
914 char *p;
918 void
919 rl_initialize()
923 char *
924 readline(prompt)
925 CONST char *prompt;
927 CHAR *line;
929 if (Line == NULL) {
930 Length = MEM_INC;
931 if ((Line = NEW(CHAR, Length)) == NULL)
932 return NULL;
935 TTYinfo();
936 rl_ttyset(0);
937 hist_add(NIL);
938 ScreenSize = SCREEN_INC;
939 Screen = NEW(char, ScreenSize);
940 Prompt = prompt ? prompt : (char *)NIL;
941 TTYputs((CHAR *)Prompt);
942 if ((line = editinput()) != NULL) {
943 line = (CHAR *)strdup((char *)line);
944 TTYputs((CHAR *)NEWLINE);
945 TTYflush();
947 rl_ttyset(1);
948 DISPOSE(Screen);
949 DISPOSE(H.Lines[--H.Size]);
950 return (char *)line;
953 void
954 add_history(p)
955 char *p;
957 if (p == NULL || *p == '\0')
958 return;
960 #if defined(UNIQUE_HISTORY)
961 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
962 return;
963 #endif /* defined(UNIQUE_HISTORY) */
964 hist_add((CHAR *)p);
968 STATIC STATUS
969 beg_line()
971 if (Point) {
972 Point = 0;
973 return CSmove;
975 return CSstay;
978 STATIC STATUS
979 del_char()
981 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
984 STATIC STATUS
985 end_line()
987 if (Point != End) {
988 Point = End;
989 return CSmove;
991 return CSstay;
994 STATIC STATUS
995 accept_line()
997 Line[End] = '\0';
998 return CSdone;
1001 STATIC STATUS
1002 transpose()
1004 CHAR c;
1006 if (Point) {
1007 if (Point == End)
1008 left(CSmove);
1009 c = Line[Point - 1];
1010 left(CSstay);
1011 Line[Point - 1] = Line[Point];
1012 TTYshow(Line[Point - 1]);
1013 Line[Point++] = c;
1014 TTYshow(c);
1016 return CSstay;
1019 STATIC STATUS
1020 quote()
1022 unsigned int c;
1024 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1027 STATIC STATUS
1028 wipe()
1030 int i;
1032 if (Mark > End)
1033 return ring_bell();
1035 if (Point > Mark) {
1036 i = Point;
1037 Point = Mark;
1038 Mark = i;
1039 reposition();
1042 return delete_string(Mark - Point);
1045 STATIC STATUS
1046 mk_set()
1048 Mark = Point;
1049 return CSstay;
1052 STATIC STATUS
1053 exchange()
1055 unsigned int c;
1057 if ((c = TTYget()) != CTL('X'))
1058 return c == EOF ? CSeof : ring_bell();
1060 if ((c = Mark) <= End) {
1061 Mark = Point;
1062 Point = c;
1063 return CSmove;
1065 return CSstay;
1068 STATIC STATUS
1069 yank()
1071 if (Yanked && *Yanked)
1072 return insert_string(Yanked);
1073 return CSstay;
1076 STATIC STATUS
1077 copy_region()
1079 if (Mark > End)
1080 return ring_bell();
1082 if (Point > Mark)
1083 save_yank(Mark, Point - Mark);
1084 else
1085 save_yank(Point, Mark - Point);
1087 return CSstay;
1090 STATIC STATUS
1091 move_to_char()
1093 unsigned int c;
1094 int i;
1095 CHAR *p;
1097 if ((c = TTYget()) == EOF)
1098 return CSeof;
1099 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1100 if (*p == c) {
1101 Point = i;
1102 return CSmove;
1104 return CSstay;
1107 STATIC STATUS
1108 fd_word()
1110 return do_forward(CSmove);
1113 STATIC STATUS
1114 fd_kill_word()
1116 int i;
1118 (void)do_forward(CSstay);
1119 if (OldPoint != Point) {
1120 i = Point - OldPoint;
1121 Point = OldPoint;
1122 return delete_string(i);
1124 return CSstay;
1127 STATIC STATUS
1128 bk_word()
1130 int i;
1131 CHAR *p;
1133 i = 0;
1134 do {
1135 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1136 left(CSmove);
1138 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1139 left(CSmove);
1141 if (Point == 0)
1142 break;
1143 } while (++i < Repeat);
1145 return CSstay;
1148 STATIC STATUS
1149 bk_kill_word()
1151 (void)bk_word();
1152 if (OldPoint != Point)
1153 return delete_string(OldPoint - Point);
1154 return CSstay;
1157 STATIC int
1158 argify(line, avp)
1159 CHAR *line;
1160 CHAR ***avp;
1162 CHAR *c;
1163 CHAR **p;
1164 CHAR **new;
1165 int ac;
1166 int i;
1168 i = MEM_INC;
1169 if ((*avp = p = NEW(CHAR*, i))== NULL)
1170 return 0;
1172 for (c = line; isspace(*c); c++)
1173 continue;
1174 if (*c == '\n' || *c == '\0')
1175 return 0;
1177 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1178 if (isspace(*c)) {
1179 *c++ = '\0';
1180 if (*c && *c != '\n') {
1181 if (ac + 1 == i) {
1182 new = NEW(CHAR*, i + MEM_INC);
1183 if (new == NULL) {
1184 p[ac] = NULL;
1185 return ac;
1187 COPYFROMTO(new, p, i * sizeof (char **));
1188 i += MEM_INC;
1189 DISPOSE(p);
1190 *avp = p = new;
1192 p[ac++] = c;
1195 else
1196 c++;
1198 *c = '\0';
1199 p[ac] = NULL;
1200 return ac;
1203 STATIC STATUS
1204 last_argument()
1206 CHAR **av;
1207 CHAR *p;
1208 STATUS s;
1209 int ac;
1211 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1212 return ring_bell();
1214 if ((p = (CHAR *)strdup((char *)p)) == NULL)
1215 return CSstay;
1216 ac = argify(p, &av);
1218 if (Repeat != NO_ARG)
1219 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1220 else
1221 s = ac ? insert_string(av[ac - 1]) : CSstay;
1223 if (ac)
1224 DISPOSE(av);
1225 DISPOSE(p);
1226 return s;
1229 STATIC KEYMAP Map[33] = {
1230 { CTL('@'), ring_bell },
1231 { CTL('A'), beg_line },
1232 { CTL('B'), bk_char },
1233 { CTL('D'), del_char },
1234 { CTL('E'), end_line },
1235 { CTL('F'), fd_char },
1236 { CTL('G'), ring_bell },
1237 { CTL('H'), bk_del_char },
1238 { CTL('I'), ring_bell },
1239 { CTL('J'), accept_line },
1240 { CTL('K'), kill_line },
1241 { CTL('L'), redisplay },
1242 { CTL('M'), accept_line },
1243 { CTL('N'), h_next },
1244 { CTL('O'), ring_bell },
1245 { CTL('P'), h_prev },
1246 { CTL('Q'), ring_bell },
1247 { CTL('R'), h_search },
1248 { CTL('S'), ring_bell },
1249 { CTL('T'), transpose },
1250 { CTL('U'), ring_bell },
1251 { CTL('V'), quote },
1252 { CTL('W'), wipe },
1253 { CTL('X'), exchange },
1254 { CTL('Y'), yank },
1255 { CTL('Z'), ring_bell },
1256 { CTL('['), meta },
1257 { CTL(']'), move_to_char },
1258 { CTL('^'), ring_bell },
1259 { CTL('_'), ring_bell },
1260 { 0, NULL }
1263 STATIC KEYMAP MetaMap[16]= {
1264 { CTL('H'), bk_kill_word },
1265 { DEL, bk_kill_word },
1266 { ' ', mk_set },
1267 { '.', last_argument },
1268 { '<', h_first },
1269 { '>', h_last },
1270 { '?', ring_bell },
1271 { 'b', bk_word },
1272 { 'd', fd_kill_word },
1273 { 'f', fd_word },
1274 { 'l', case_down_word },
1275 { 'u', case_up_word },
1276 { 'y', yank },
1277 { 'w', copy_region },
1278 { 0, NULL }