source: trunk/minix/lib/editline/editline.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 23.6 KB
Line 
1/* $Revision: 1.1.1.1 $
2**
3** Main editing routines for editline library.
4*/
5#include "editline.h"
6#include <signal.h>
7#include <ctype.h>
8
9/*
10** Manifest constants.
11*/
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) */
25
26/*
27** Command status codes.
28*/
29typedef enum _STATUS {
30 CSdone, CSeof, CSmove, CSdispatch, CSstay, CSsignal
31} STATUS;
32
33/*
34** The type of case-changing to perform.
35*/
36typedef enum _CASE {
37 TOupper, TOlower
38} CASE;
39
40/*
41** Key to command mapping.
42*/
43typedef struct _KEYMAP {
44 CHAR Key;
45 STATUS (*Function)();
46} KEYMAP;
47
48/*
49** Command history structure.
50*/
51typedef struct _HISTORY {
52 int Size;
53 int Pos;
54 CHAR *Lines[HIST_SIZE];
55} HISTORY;
56
57/*
58** Globals.
59*/
60int rl_eof;
61int rl_erase;
62int rl_intr;
63int rl_kill;
64int rl_quit;
65
66STATIC CHAR NIL[] = "";
67STATIC CONST CHAR *Input = NIL;
68STATIC CHAR *Line;
69STATIC CONST char *Prompt;
70STATIC CHAR *Yanked;
71STATIC char *Screen;
72STATIC char NEWLINE[]= CRLF;
73STATIC HISTORY H;
74STATIC int Repeat;
75STATIC int End;
76STATIC int Mark;
77STATIC int OldPoint;
78STATIC int Point;
79STATIC int PushBack;
80STATIC int Pushed;
81STATIC int Signal;
82FORWARD KEYMAP Map[33];
83FORWARD KEYMAP MetaMap[17];
84STATIC SIZE_T Length;
85STATIC SIZE_T ScreenCount;
86STATIC SIZE_T ScreenSize;
87STATIC char *backspace;
88STATIC int TTYwidth;
89STATIC int TTYrows;
90
91/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
92int rl_meta_chars = 0;
93
94/*
95** Declarations.
96*/
97STATIC CHAR *editinput();
98extern int read();
99extern int write();
100#if defined(USE_TERMCAP)
101extern char *getenv();
102extern char *tgetstr();
103extern int tgetent();
104#endif /* defined(USE_TERMCAP) */
105
106
107/*
108** TTY input/output functions.
109*/
110
111STATIC void
112TTYflush()
113{
114 if (ScreenCount) {
115 (void)write(1, Screen, ScreenCount);
116 ScreenCount = 0;
117 }
118}
119
120STATIC void
121TTYput(c)
122 CHAR c;
123{
124 Screen[ScreenCount] = c;
125 if (++ScreenCount >= ScreenSize - 1) {
126 ScreenSize += SCREEN_INC;
127 RENEW(Screen, char, ScreenSize);
128 }
129}
130
131STATIC void
132TTYputs(p)
133 CHAR *p;
134{
135 while (*p)
136 TTYput(*p++);
137}
138
139STATIC void
140TTYshow(c)
141 CHAR c;
142{
143 if (c == DEL) {
144 TTYput('^');
145 TTYput('?');
146 }
147 else if (ISCTL(c)) {
148 TTYput('^');
149 TTYput(UNCTL(c));
150 }
151 else if (rl_meta_chars && ISMETA(c)) {
152 TTYput('M');
153 TTYput('-');
154 TTYput(UNMETA(c));
155 }
156 else
157 TTYput(c);
158}
159
160STATIC void
161TTYstring(p)
162 CHAR *p;
163{
164 while (*p)
165 TTYshow(*p++);
166}
167
168STATIC unsigned int
169TTYget()
170{
171 CHAR c;
172
173 TTYflush();
174 if (Pushed) {
175 Pushed = 0;
176 return PushBack;
177 }
178 if (*Input)
179 return *Input++;
180 return read(0, &c, (SIZE_T)1) == 1 ? c : EOF;
181}
182
183#define TTYback() (backspace ? TTYputs((CHAR *)backspace) : TTYput('\b'))
184
185STATIC void
186TTYbackn(n)
187 int n;
188{
189 while (--n >= 0)
190 TTYback();
191}
192
193STATIC void
194TTYinfo()
195{
196 static int init;
197#if defined(USE_TERMCAP)
198 char *term;
199 char buff[2048];
200 char *bp;
201#endif /* defined(USE_TERMCAP) */
202#if defined(TIOCGWINSZ)
203 struct winsize W;
204#endif /* defined(TIOCGWINSZ) */
205
206 if (init) {
207#if defined(TIOCGWINSZ)
208 /* Perhaps we got resized. */
209 if (ioctl(0, TIOCGWINSZ, &W) >= 0
210 && W.ws_col > 0 && W.ws_row > 0) {
211 TTYwidth = (int)W.ws_col;
212 TTYrows = (int)W.ws_row;
213 }
214#endif /* defined(TIOCGWINSZ) */
215 return;
216 }
217 init++;
218
219 TTYwidth = TTYrows = 0;
220#if defined(USE_TERMCAP)
221 bp = &buff[0];
222 if ((term = getenv("TERM")) == NULL)
223 term = "dumb";
224 if (tgetent(buff, term) < 0) {
225 TTYwidth = SCREEN_WIDTH;
226 TTYrows = SCREEN_ROWS;
227 return;
228 }
229 if ((backspace = tgetstr("le", &bp)) != NULL)
230 backspace = strdup(backspace);
231 TTYwidth = tgetnum("co");
232 TTYrows = tgetnum("li");
233#endif /* defined(USE_TERMCAP) */
234
235#if defined(TIOCGWINSZ)
236 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
237 TTYwidth = (int)W.ws_col;
238 TTYrows = (int)W.ws_row;
239 }
240#endif /* defined(TIOCGWINSZ) */
241
242 if (TTYwidth <= 0 || TTYrows <= 0) {
243 TTYwidth = SCREEN_WIDTH;
244 TTYrows = SCREEN_ROWS;
245 }
246}
247
248
249
250/*
251** Print an array of words in columns.
252*/
253STATIC void
254columns(ac, av)
255 int ac;
256 CHAR **av;
257{
258 CHAR *p;
259 int i;
260 int j;
261 int k;
262 int len;
263 int skip;
264 int longest;
265 int cols;
266
267 /* Find longest name, determine column count from that. */
268 for (longest = 0, i = 0; i < ac; i++)
269 if ((j = strlen((char *)av[i])) > longest)
270 longest = j;
271 cols = TTYwidth / (longest + 3);
272
273 TTYputs((CHAR *)NEWLINE);
274 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
275 for (j = i; j < ac; j += skip) {
276 for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
277 TTYput(*p);
278 if (j + skip < ac)
279 while (++len < longest + 3)
280 TTYput(' ');
281 }
282 TTYputs((CHAR *)NEWLINE);
283 }
284}
285
286STATIC void
287reposition()
288{
289 int i;
290 CHAR *p;
291
292 TTYput('\r');
293 TTYputs((CONST CHAR *)Prompt);
294 for (i = Point, p = Line; --i >= 0; p++)
295 TTYshow(*p);
296}
297
298STATIC void
299left(Change)
300 STATUS Change;
301{
302 TTYback();
303 if (Point) {
304 if (ISCTL(Line[Point - 1]))
305 TTYback();
306 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
307 TTYback();
308 TTYback();
309 }
310 }
311 if (Change == CSmove)
312 Point--;
313}
314
315STATIC void
316right(Change)
317 STATUS Change;
318{
319 TTYshow(Line[Point]);
320 if (Change == CSmove)
321 Point++;
322}
323
324STATIC STATUS
325ring_bell()
326{
327 TTYput('\07');
328 TTYflush();
329 return CSstay;
330}
331
332STATIC STATUS
333do_macro(c)
334 unsigned int c;
335{
336 CHAR name[4];
337
338 name[0] = '_';
339 name[1] = c;
340 name[2] = '_';
341 name[3] = '\0';
342
343 if ((Input = (CHAR *)getenv((char *)name)) == NULL) {
344 Input = NIL;
345 return ring_bell();
346 }
347 return CSstay;
348}
349
350STATIC STATUS
351do_forward(move)
352 STATUS move;
353{
354 int i;
355 CHAR *p;
356
357 i = 0;
358 do {
359 p = &Line[Point];
360 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
361 if (move == CSmove)
362 right(CSstay);
363
364 for (; Point < End && isalnum(*p); Point++, p++)
365 if (move == CSmove)
366 right(CSstay);
367
368 if (Point == End)
369 break;
370 } while (++i < Repeat);
371
372 return CSstay;
373}
374
375STATIC STATUS
376do_case(type)
377 CASE type;
378{
379 int i;
380 int end;
381 int count;
382 CHAR *p;
383
384 (void)do_forward(CSstay);
385 if (OldPoint != Point) {
386 if ((count = Point - OldPoint) < 0)
387 count = -count;
388 Point = OldPoint;
389 if ((end = Point + count) > End)
390 end = End;
391 for (i = Point, p = &Line[i]; i < end; i++, p++) {
392 if (type == TOupper) {
393 if (islower(*p))
394 *p = toupper(*p);
395 }
396 else if (isupper(*p))
397 *p = tolower(*p);
398 right(CSmove);
399 }
400 }
401 return CSstay;
402}
403
404STATIC STATUS
405case_down_word()
406{
407 return do_case(TOlower);
408}
409
410STATIC STATUS
411case_up_word()
412{
413 return do_case(TOupper);
414}
415
416STATIC void
417ceol()
418{
419 int extras;
420 int i;
421 CHAR *p;
422
423 for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
424 TTYput(' ');
425 if (ISCTL(*p)) {
426 TTYput(' ');
427 extras++;
428 }
429 else if (rl_meta_chars && ISMETA(*p)) {
430 TTYput(' ');
431 TTYput(' ');
432 extras += 2;
433 }
434 }
435
436 for (i += extras; i > Point; i--)
437 TTYback();
438}
439
440STATIC void
441clear_line()
442{
443 Point = -strlen(Prompt);
444 TTYput('\r');
445 ceol();
446 Point = 0;
447 End = 0;
448 Line[0] = '\0';
449}
450
451STATIC STATUS
452insert_string(p)
453 CHAR *p;
454{
455 SIZE_T len;
456 int i;
457 CHAR *new;
458 CHAR *q;
459
460 len = strlen((char *)p);
461 if (End + len >= Length) {
462 if ((new = NEW(CHAR, Length + len + MEM_INC)) == NULL)
463 return CSstay;
464 if (Length) {
465 COPYFROMTO(new, Line, Length);
466 DISPOSE(Line);
467 }
468 Line = new;
469 Length += len + MEM_INC;
470 }
471
472 for (q = &Line[Point], i = End - Point; --i >= 0; )
473 q[len + i] = q[i];
474 COPYFROMTO(&Line[Point], p, len);
475 End += len;
476 Line[End] = '\0';
477 TTYstring(&Line[Point]);
478 Point += len;
479
480 return Point == End ? CSstay : CSmove;
481}
482
483STATIC STATUS
484redisplay()
485{
486 TTYputs((CONST CHAR *)NEWLINE);
487 TTYputs((CONST CHAR *)Prompt);
488 TTYstring(Line);
489 return CSmove;
490}
491
492STATIC STATUS
493toggle_meta_mode()
494{
495 rl_meta_chars = ! rl_meta_chars;
496 return redisplay();
497}
498
499
500
501STATIC CHAR *
502next_hist()
503{
504 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
505}
506
507STATIC CHAR *
508prev_hist()
509{
510 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
511}
512
513STATIC STATUS
514do_insert_hist(p)
515 CHAR *p;
516{
517 if (p == NULL)
518 return ring_bell();
519 Point = 0;
520 reposition();
521 ceol();
522 End = 0;
523 return insert_string(p);
524}
525
526STATIC STATUS
527do_hist(move)
528 CHAR *(*move)();
529{
530 CHAR *p;
531 int i;
532
533 i = 0;
534 do {
535 if ((p = (*move)()) == NULL)
536 return ring_bell();
537 } while (++i < Repeat);
538 return do_insert_hist(p);
539}
540
541STATIC STATUS
542h_next()
543{
544 return do_hist(next_hist);
545}
546
547STATIC STATUS
548h_prev()
549{
550 return do_hist(prev_hist);
551}
552
553STATIC STATUS
554h_first()
555{
556 return do_insert_hist(H.Lines[H.Pos = 0]);
557}
558
559STATIC STATUS
560h_last()
561{
562 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
563}
564
565/*
566** Return zero if pat appears as a substring in text.
567*/
568STATIC int
569substrcmp(text, pat, len)
570 char *text;
571 char *pat;
572 int len;
573{
574 char c;
575
576 if ((c = *pat) == '\0')
577 return *text == '\0';
578 for ( ; *text; text++)
579 if (*text == c && strncmp(text, pat, len) == 0)
580 return 0;
581 return 1;
582}
583
584STATIC CHAR *
585search_hist(search, move)
586 CHAR *search;
587 CHAR *(*move)();
588{
589 static CHAR *old_search;
590 int len;
591 int pos;
592 int (*match)();
593 char *pat;
594
595 /* Save or get remembered search pattern. */
596 if (search && *search) {
597 if (old_search)
598 DISPOSE(old_search);
599 old_search = (CHAR *)strdup((char *)search);
600 }
601 else {
602 if (old_search == NULL || *old_search == '\0')
603 return NULL;
604 search = old_search;
605 }
606
607 /* Set up pattern-finder. */
608 if (*search == '^') {
609 match = strncmp;
610 pat = (char *)(search + 1);
611 }
612 else {
613 match = substrcmp;
614 pat = (char *)search;
615 }
616 len = strlen(pat);
617
618 for (pos = H.Pos; (*move)() != NULL; )
619 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
620 return H.Lines[H.Pos];
621 H.Pos = pos;
622 return NULL;
623}
624
625STATIC STATUS
626h_search()
627{
628 static int Searching;
629 CONST char *old_prompt;
630 CHAR *(*move)();
631 CHAR *p;
632
633 if (Searching)
634 return ring_bell();
635 Searching = 1;
636
637 clear_line();
638 old_prompt = Prompt;
639 Prompt = "Search: ";
640 TTYputs((CONST CHAR *)Prompt);
641 move = Repeat == NO_ARG ? prev_hist : next_hist;
642 p = editinput();
643 Prompt = old_prompt;
644 Searching = 0;
645 TTYputs((CONST CHAR *)Prompt);
646 if (p == NULL && Signal > 0) {
647 Signal = 0;
648 clear_line();
649 return redisplay();
650 }
651 p = search_hist(p, move);
652 clear_line();
653 if (p == NULL) {
654 (void)ring_bell();
655 return redisplay();
656 }
657 return do_insert_hist(p);
658}
659
660STATIC STATUS
661fd_char()
662{
663 int i;
664
665 i = 0;
666 do {
667 if (Point >= End)
668 break;
669 right(CSmove);
670 } while (++i < Repeat);
671 return CSstay;
672}
673
674STATIC void
675save_yank(begin, i)
676 int begin;
677 int i;
678{
679 if (Yanked) {
680 DISPOSE(Yanked);
681 Yanked = NULL;
682 }
683
684 if (i < 1)
685 return;
686
687 if ((Yanked = NEW(CHAR, (SIZE_T)i + 1)) != NULL) {
688 COPYFROMTO(Yanked, &Line[begin], i);
689 Yanked[i] = '\0';
690 }
691}
692
693STATIC STATUS
694delete_string(count)
695 int count;
696{
697 int i;
698 CHAR *p;
699
700 if (count <= 0 || End == Point)
701 return ring_bell();
702
703 if (count == 1 && Point == End - 1) {
704 /* Optimize common case of delete at end of line. */
705 End--;
706 p = &Line[Point];
707 i = 1;
708 TTYput(' ');
709 if (ISCTL(*p)) {
710 i = 2;
711 TTYput(' ');
712 }
713 else if (rl_meta_chars && ISMETA(*p)) {
714 i = 3;
715 TTYput(' ');
716 TTYput(' ');
717 }
718 TTYbackn(i);
719 *p = '\0';
720 return CSmove;
721 }
722 if (Point + count > End && (count = End - Point) <= 0)
723 return CSstay;
724
725 if (count > 1)
726 save_yank(Point, count);
727
728 for (p = &Line[Point], i = End - (Point + count) + 1; --i >= 0; p++)
729 p[0] = p[count];
730 ceol();
731 End -= count;
732 TTYstring(&Line[Point]);
733 return CSmove;
734}
735
736STATIC STATUS
737bk_char()
738{
739 int i;
740
741 i = 0;
742 do {
743 if (Point == 0)
744 break;
745 left(CSmove);
746 } while (++i < Repeat);
747
748 return CSstay;
749}
750
751STATIC STATUS
752bk_del_char()
753{
754 int i;
755
756 i = 0;
757 do {
758 if (Point == 0)
759 break;
760 left(CSmove);
761 } while (++i < Repeat);
762
763 return delete_string(i);
764}
765
766STATIC STATUS
767kill_line()
768{
769 int i;
770
771 if (Repeat != NO_ARG) {
772 if (Repeat < Point) {
773 i = Point;
774 Point = Repeat;
775 reposition();
776 (void)delete_string(i - Point);
777 }
778 else if (Repeat > Point) {
779 right(CSmove);
780 (void)delete_string(Repeat - Point - 1);
781 }
782 return CSmove;
783 }
784
785 save_yank(Point, End - Point);
786 Line[Point] = '\0';
787 ceol();
788 End = Point;
789 return CSstay;
790}
791
792STATIC STATUS
793insert_char(c)
794 int c;
795{
796 STATUS s;
797 CHAR buff[2];
798 CHAR *p;
799 CHAR *q;
800 int i;
801
802 if (Repeat == NO_ARG || Repeat < 2) {
803 buff[0] = c;
804 buff[1] = '\0';
805 return insert_string(buff);
806 }
807
808 if ((p = NEW(CHAR, Repeat + 1)) == NULL)
809 return CSstay;
810 for (i = Repeat, q = p; --i >= 0; )
811 *q++ = c;
812 *q = '\0';
813 Repeat = 0;
814 s = insert_string(p);
815 DISPOSE(p);
816 return s;
817}
818
819STATIC STATUS
820meta()
821{
822 unsigned int c;
823 KEYMAP *kp;
824
825 if ((c = TTYget()) == EOF)
826 return CSeof;
827#if defined(ANSI_ARROWS)
828 /* Also include VT-100 arrows. */
829 if (c == '[' || c == 'O')
830 switch (c = TTYget()) {
831 default: return ring_bell();
832 case EOF: return CSeof;
833 case 'A': return h_prev();
834 case 'B': return h_next();
835 case 'C': return fd_char();
836 case 'D': return bk_char();
837 }
838#endif /* defined(ANSI_ARROWS) */
839
840 if (isdigit(c)) {
841 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
842 Repeat = Repeat * 10 + c - '0';
843 Pushed = 1;
844 PushBack = c;
845 return CSstay;
846 }
847
848 if (isupper(c))
849 return do_macro(c);
850 for (kp = MetaMap; kp->Function; kp++)
851 if (kp->Key == c)
852 return (*kp->Function)();
853
854 return ring_bell();
855}
856
857STATIC STATUS
858emacs(c)
859 unsigned int c;
860{
861 STATUS s;
862 KEYMAP *kp;
863
864 OldPoint = Point;
865 if (rl_meta_chars && ISMETA(c)) {
866 Pushed = 1;
867 PushBack = UNMETA(c);
868 return meta();
869 }
870 for (kp = Map; kp->Function; kp++)
871 if (kp->Key == c)
872 break;
873 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
874 if (!Pushed)
875 /* No pushback means no repeat count; hacky, but true. */
876 Repeat = NO_ARG;
877 return s;
878}
879
880STATIC STATUS
881TTYspecial(c)
882 unsigned int c;
883{
884 if (ISMETA(c))
885 return CSdispatch;
886
887 if (c == rl_erase || c == DEL)
888 return bk_del_char();
889 if (c == rl_kill) {
890 if (Point != 0) {
891 Point = 0;
892 reposition();
893 }
894 Repeat = NO_ARG;
895 return kill_line();
896 }
897 if (c == rl_eof && Point == 0 && End == 0)
898 return CSeof;
899 if (c == rl_intr) {
900 Signal = SIGINT;
901 return CSsignal;
902 }
903 if (c == rl_quit) {
904 Signal = SIGQUIT;
905 return CSeof;
906 }
907
908 return CSdispatch;
909}
910
911STATIC CHAR *
912editinput()
913{
914 unsigned int c;
915
916 Repeat = NO_ARG;
917 OldPoint = Point = Mark = End = 0;
918 Line[0] = '\0';
919
920 Signal = -1;
921 while ((c = TTYget()) != EOF)
922 switch (TTYspecial(c)) {
923 case CSdone:
924 return Line;
925 case CSeof:
926 return NULL;
927 case CSsignal:
928 return (CHAR *)"";
929 case CSmove:
930 reposition();
931 break;
932 case CSdispatch:
933 switch (emacs(c)) {
934 case CSdone:
935 return Line;
936 case CSeof:
937 return NULL;
938 case CSsignal:
939 return (CHAR *)"";
940 case CSmove:
941 reposition();
942 break;
943 case CSdispatch:
944 case CSstay:
945 break;
946 }
947 break;
948 case CSstay:
949 break;
950 }
951 return NULL;
952}
953
954STATIC void
955hist_add(p)
956 CHAR *p;
957{
958 int i;
959
960 if ((p = (CHAR *)strdup((char *)p)) == NULL)
961 return;
962 if (H.Size < HIST_SIZE)
963 H.Lines[H.Size++] = p;
964 else {
965 DISPOSE(H.Lines[0]);
966 for (i = 0; i < HIST_SIZE - 1; i++)
967 H.Lines[i] = H.Lines[i + 1];
968 H.Lines[i] = p;
969 }
970 H.Pos = H.Size - 1;
971}
972
973/*
974** For compatibility with FSF readline.
975*/
976/* ARGSUSED0 */
977void
978rl_reset_terminal(p)
979 char *p;
980{
981}
982
983void
984rl_initialize()
985{
986}
987
988char *
989readline(prompt)
990 CONST char *prompt;
991{
992 CHAR *line;
993 int s;
994
995 if (Line == NULL) {
996 Length = MEM_INC;
997 if ((Line = NEW(CHAR, Length)) == NULL)
998 return NULL;
999 }
1000
1001 TTYinfo();
1002 rl_ttyset(0);
1003 hist_add(NIL);
1004 ScreenSize = SCREEN_INC;
1005 Screen = NEW(char, ScreenSize);
1006 Prompt = prompt ? prompt : (char *)NIL;
1007 TTYputs((CONST CHAR *)Prompt);
1008 if ((line = editinput()) != NULL) {
1009 line = (CHAR *)strdup((char *)line);
1010 TTYputs((CHAR *)NEWLINE);
1011 TTYflush();
1012 }
1013 rl_ttyset(1);
1014 DISPOSE(Screen);
1015 DISPOSE(H.Lines[--H.Size]);
1016
1017 if (line != NULL && *line != '\0'
1018#if defined(UNIQUE_HISTORY)
1019 && !(H.Pos && strcmp((char *) line, (char *) H.Lines[H.Pos - 1]) == 0)
1020#endif /* defined(UNIQUE_HISTORY) */
1021 && !(H.Size && strcmp((char *) line, (char *) H.Lines[H.Size - 1]) == 0)
1022 ) {
1023 hist_add(line);
1024 }
1025
1026 if (Signal > 0) {
1027 s = Signal;
1028 Signal = 0;
1029 (void)kill(getpid(), s);
1030 }
1031 return (char *)line;
1032}
1033
1034void
1035add_history(p)
1036 char *p;
1037{
1038#ifdef obsolete /* Made part of readline(). -- kjb */
1039 if (p == NULL || *p == '\0')
1040 return;
1041
1042#if defined(UNIQUE_HISTORY)
1043 if (H.Pos && strcmp(p, (char *) H.Lines[H.Pos - 1]) == 0)
1044 return;
1045#endif /* defined(UNIQUE_HISTORY) */
1046 if (H.Size && strcmp(p, (char *) H.Lines[H.Size - 1]) == 0)
1047 return;
1048 hist_add((CHAR *)p);
1049#endif
1050}
1051
1052
1053
1054STATIC STATUS
1055beg_line()
1056{
1057 if (Point) {
1058 Point = 0;
1059 return CSmove;
1060 }
1061 return CSstay;
1062}
1063
1064STATIC STATUS
1065del_char()
1066{
1067 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1068}
1069
1070STATIC STATUS
1071end_line()
1072{
1073 if (Point != End) {
1074 Point = End;
1075 return CSmove;
1076 }
1077 return CSstay;
1078}
1079
1080STATIC char SEPS[] = "\"#$&'()*:;<=>?[\\]^`{|}~\n\t ";
1081
1082/*
1083** Move back to the beginning of the current word and return an
1084** allocated copy of it.
1085*/
1086STATIC CHAR *
1087find_word()
1088{
1089 CHAR *p, *q;
1090 CHAR *new;
1091 SIZE_T len;
1092
1093 p = &Line[Point];
1094 while (p > Line) {
1095 p--;
1096 if (p > Line && p[-1] == '\\') {
1097 p--;
1098 } else {
1099 if (strchr(SEPS, (char) *p) != NULL) {
1100 p++;
1101 break;
1102 }
1103 }
1104 }
1105 len = Point - (p - Line) + 1;
1106 if ((new = NEW(CHAR, len)) == NULL)
1107 return NULL;
1108 q = new;
1109 while (p < &Line[Point]) {
1110 if (*p == '\\') {
1111 if (++p == &Line[Point]) break;
1112 }
1113 *q++ = *p++;
1114 }
1115 *q = '\0';
1116 return new;
1117}
1118
1119STATIC STATUS
1120c_possible()
1121{
1122 CHAR **av;
1123 CHAR *word;
1124 int ac;
1125
1126 word = find_word();
1127 ac = rl_list_possib((char *)word, (char ***)&av);
1128 if (word)
1129 DISPOSE(word);
1130 if (ac) {
1131 columns(ac, av);
1132 while (--ac >= 0)
1133 DISPOSE(av[ac]);
1134 DISPOSE(av);
1135 return CSmove;
1136 }
1137 return ring_bell();
1138}
1139
1140STATIC STATUS
1141c_complete()
1142{
1143 CHAR *p, *q;
1144 CHAR *word, *new;
1145 SIZE_T len;
1146 int unique;
1147 STATUS s;
1148
1149 word = find_word();
1150 p = (CHAR *)rl_complete((char *)word, &unique);
1151 if (word)
1152 DISPOSE(word);
1153 if (p) {
1154 len = strlen((char *)p);
1155 word = p;
1156 new = q = NEW(CHAR, 2 * len + 1);
1157 while (*p) {
1158 if ((*p < ' ' || strchr(SEPS, (char) *p) != NULL)
1159 && (!unique || p[1] != 0)) {
1160 *q++ = '\\';
1161 }
1162 *q++ = *p++;
1163 }
1164 *q = '\0';
1165 DISPOSE(word);
1166 if (len > 0) {
1167 s = insert_string(new);
1168#if ANNOYING_NOISE
1169 if (!unique)
1170 (void)ring_bell();
1171#endif
1172 }
1173 DISPOSE(new);
1174 if (len > 0) return s;
1175 }
1176 return c_possible();
1177}
1178
1179STATIC STATUS
1180accept_line()
1181{
1182 Line[End] = '\0';
1183 return CSdone;
1184}
1185
1186STATIC STATUS
1187transpose()
1188{
1189 CHAR c;
1190
1191 if (Point) {
1192 if (Point == End)
1193 left(CSmove);
1194 c = Line[Point - 1];
1195 left(CSstay);
1196 Line[Point - 1] = Line[Point];
1197 TTYshow(Line[Point - 1]);
1198 Line[Point++] = c;
1199 TTYshow(c);
1200 }
1201 return CSstay;
1202}
1203
1204STATIC STATUS
1205quote()
1206{
1207 unsigned int c;
1208
1209 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1210}
1211
1212STATIC STATUS
1213wipe()
1214{
1215 int i;
1216
1217 if (Mark > End)
1218 return ring_bell();
1219
1220 if (Point > Mark) {
1221 i = Point;
1222 Point = Mark;
1223 Mark = i;
1224 reposition();
1225 }
1226
1227 return delete_string(Mark - Point);
1228}
1229
1230STATIC STATUS
1231mk_set()
1232{
1233 Mark = Point;
1234 return CSstay;
1235}
1236
1237STATIC STATUS
1238exchange()
1239{
1240 unsigned int c;
1241
1242 if ((c = TTYget()) != CTL('X'))
1243 return c == EOF ? CSeof : ring_bell();
1244
1245 if ((c = Mark) <= End) {
1246 Mark = Point;
1247 Point = c;
1248 return CSmove;
1249 }
1250 return CSstay;
1251}
1252
1253STATIC STATUS
1254yank()
1255{
1256 if (Yanked && *Yanked)
1257 return insert_string(Yanked);
1258 return CSstay;
1259}
1260
1261STATIC STATUS
1262copy_region()
1263{
1264 if (Mark > End)
1265 return ring_bell();
1266
1267 if (Point > Mark)
1268 save_yank(Mark, Point - Mark);
1269 else
1270 save_yank(Point, Mark - Point);
1271
1272 return CSstay;
1273}
1274
1275STATIC STATUS
1276move_to_char()
1277{
1278 unsigned int c;
1279 int i;
1280 CHAR *p;
1281
1282 if ((c = TTYget()) == EOF)
1283 return CSeof;
1284 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1285 if (*p == c) {
1286 Point = i;
1287 return CSmove;
1288 }
1289 return CSstay;
1290}
1291
1292STATIC STATUS
1293fd_word()
1294{
1295 return do_forward(CSmove);
1296}
1297
1298STATIC STATUS
1299fd_kill_word()
1300{
1301 int i;
1302
1303 (void)do_forward(CSstay);
1304 if (OldPoint != Point) {
1305 i = Point - OldPoint;
1306 Point = OldPoint;
1307 return delete_string(i);
1308 }
1309 return CSstay;
1310}
1311
1312STATIC STATUS
1313bk_word()
1314{
1315 int i;
1316 CHAR *p;
1317
1318 i = 0;
1319 do {
1320 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1321 left(CSmove);
1322
1323 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1324 left(CSmove);
1325
1326 if (Point == 0)
1327 break;
1328 } while (++i < Repeat);
1329
1330 return CSstay;
1331}
1332
1333STATIC STATUS
1334bk_kill_word()
1335{
1336 (void)bk_word();
1337 if (OldPoint != Point)
1338 return delete_string(OldPoint - Point);
1339 return CSstay;
1340}
1341
1342STATIC int
1343argify(line, avp)
1344 CHAR *line;
1345 CHAR ***avp;
1346{
1347 CHAR *c;
1348 CHAR **p;
1349 CHAR **new;
1350 int ac;
1351 int i;
1352
1353 i = MEM_INC;
1354 if ((*avp = p = NEW(CHAR*, i))== NULL)
1355 return 0;
1356
1357 for (c = line; isspace(*c); c++)
1358 continue;
1359 if (*c == '\n' || *c == '\0')
1360 return 0;
1361
1362 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1363 if (isspace(*c)) {
1364 *c++ = '\0';
1365 if (*c && *c != '\n') {
1366 if (ac + 1 == i) {
1367 new = NEW(CHAR*, i + MEM_INC);
1368 if (new == NULL) {
1369 p[ac] = NULL;
1370 return ac;
1371 }
1372 COPYFROMTO(new, p, i * sizeof (char **));
1373 i += MEM_INC;
1374 DISPOSE(p);
1375 *avp = p = new;
1376 }
1377 p[ac++] = c;
1378 }
1379 }
1380 else
1381 c++;
1382 }
1383 *c = '\0';
1384 p[ac] = NULL;
1385 return ac;
1386}
1387
1388STATIC STATUS
1389last_argument()
1390{
1391 CHAR **av;
1392 CHAR *p;
1393 STATUS s;
1394 int ac;
1395
1396 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1397 return ring_bell();
1398
1399 if ((p = (CHAR *)strdup((char *)p)) == NULL)
1400 return CSstay;
1401 ac = argify(p, &av);
1402
1403 if (Repeat != NO_ARG)
1404 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1405 else
1406 s = ac ? insert_string(av[ac - 1]) : CSstay;
1407
1408 if (ac)
1409 DISPOSE(av);
1410 DISPOSE(p);
1411 return s;
1412}
1413
1414STATIC KEYMAP Map[33] = {
1415 { CTL('@'), mk_set },
1416 { CTL('A'), beg_line },
1417 { CTL('B'), bk_char },
1418 { CTL('D'), del_char },
1419 { CTL('E'), end_line },
1420 { CTL('F'), fd_char },
1421 { CTL('G'), ring_bell },
1422 { CTL('H'), bk_del_char },
1423 { CTL('I'), c_complete },
1424 { CTL('J'), accept_line },
1425 { CTL('K'), kill_line },
1426 { CTL('L'), redisplay },
1427 { CTL('M'), accept_line },
1428 { CTL('N'), h_next },
1429 { CTL('O'), ring_bell },
1430 { CTL('P'), h_prev },
1431 { CTL('Q'), ring_bell },
1432 { CTL('R'), h_search },
1433 { CTL('S'), ring_bell },
1434 { CTL('T'), transpose },
1435 { CTL('U'), ring_bell },
1436 { CTL('V'), quote },
1437 { CTL('W'), bk_kill_word },
1438 { CTL('X'), exchange },
1439 { CTL('Y'), yank },
1440 { CTL('Z'), end_line },
1441 { CTL('['), meta },
1442 { CTL(']'), move_to_char },
1443 { CTL('^'), ring_bell },
1444 { CTL('_'), ring_bell },
1445 { 0, NULL }
1446};
1447
1448STATIC KEYMAP MetaMap[17]= {
1449 { CTL('H'), wipe },
1450 { DEL, wipe },
1451 { ' ', mk_set },
1452 { '.', last_argument },
1453 { '<', h_first },
1454 { '>', h_last },
1455 { '?', c_possible },
1456 { 'b', bk_word },
1457 { 'd', fd_kill_word },
1458 { 'f', fd_word },
1459 { 'l', case_down_word },
1460 { 'm', toggle_meta_mode },
1461 { 'u', case_up_word },
1462 { 'y', yank },
1463 { 'w', copy_region },
1464 { 0, NULL }
1465};
1466
1467/*
1468 * $PchId: editline.c,v 1.4 1996/02/22 21:16:56 philip Exp $
1469 */
Note: See TracBrowser for help on using the repository browser.