Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
editline.c
1/****************************************************************************/
2/* */
3/* Copyright 1992 Simmule Turner and Rich Salz. All rights reserved. */
4/* */
5/* This software is not subject to any license of the American Telephone */
6/* and Telegraph Company or of the Regents of the University of California. */
7/* */
8/* Permission is granted to anyone to use this software for any purpose on */
9/* any computer system, and to alter it and redistribute it freely, subject */
10/* to the following restrictions: */
11/* 1. The authors are not responsible for the consequences of use of this */
12/* software, no matter how awful, even if they arise from flaws in it. */
13/* 2. The origin of this software must not be misrepresented, either by */
14/* explicit claim or by omission. Since few users ever read sources, */
15/* credits must appear in the documentation. */
16/* 3. Altered versions must be plainly marked as such, and must not be */
17/* misrepresented as being the original software. Since few users */
18/* ever read sources, credits must appear in the documentation. */
19/* 4. This notice may not be removed or altered. */
20/* */
21/****************************************************************************/
22/* */
23/* This is a line-editing library, it can be linked into almost any */
24/* program to provide command-line editing and recall. */
25/* */
26/* Posted to comp.sources.misc Sun, 2 Aug 1992 03:05:27 GMT */
27/* by rsalz@osf.org (Rich $alz) */
28/* */
29/****************************************************************************/
30/* */
31/* The version contained here has some modifications by awb@cstr.ed.ac.uk */
32/* (Alan W Black) in order to integrate it with the Edinburgh Speech Tools */
33/* library and Scheme-in-one-defun in particular, though these changes */
34/* have a much more general use that just us. All modifications to */
35/* to this work are continued with the same copyright above. That is */
36/* this version of editline does not have the the "no commercial use" */
37/* restriction that some of the rest of the EST library may have */
38/* awb Dec 30 1998 */
39/* */
40/* Specific additions (there are other smaller ones too, all marked): */
41/* some ansificiation and prototypes added */
42/* storage and retrieval of history over sessions */
43/* user definable history completion */
44/* possibles listing in completion */
45/* reverse incremental search */
46/* lines longer than window width (mostly) */
47/* reasonable support for 8 bit chars in languages other than English */
48/* */
49/****************************************************************************/
50
51/* $Revision: 1.6 $
52**
53** Main editing routines for editline library.
54*/
55#include "editline.h"
56#include "EST_unix.h"
57#include <ctype.h>
58
59/*
60** Manifest constants.
61*/
62#define SCREEN_WIDTH 80
63#define SCREEN_ROWS 24
64#define NO_ARG (-1)
65#define DEL 127
66#define ESC 0x1b
67#define CTL(x) (char)((x) & 0x1F)
68#define ISCTL(x) ((x) && (x) < ' ')
69#define UNCTL(x) (char)((x) + 64)
70#define META(x) (char)((x) | 0x80)
71#define ISMETA(x) ((x) & 0x80)
72#define UNMETA(x) (char)((x) & 0x7F)
73/* modified by awb to allow specifcation of history size at run time */
74/* (though only once) */
75int editline_histsize=256;
76/* If this is defined it'll be called for completion first, before the */
77/* internal file name completion will be */
78EL_USER_COMPLETION_FUNCTION_TYPE*el_user_completion_function = NULL;
79
80/*
81** The type of case-changing to perform.
82*/
83typedef enum _CASE {
84 TOupper, TOlower, TOcapitalize
85} CASE;
86
87/*
88** Key to command mapping.
89*/
90typedef struct _KEYMAP {
91 ECHAR Key;
92 STATUS (*Function)();
93} KEYMAP;
94
95/*
96** Command history structure.
97*/
98typedef struct _HISTORY {
99 int Size;
100 int Pos;
101 ECHAR **Lines;
102} HISTORY;
103
104/*
105** Globals.
106*/
107int rl_eof;
108int rl_erase;
109int rl_intr;
110int rl_kill;
111
112ECHAR el_NIL[] = "";
113extern CONST ECHAR *el_Input;
114STATIC ECHAR *Line = NULL;
115STATIC CONST char *Prompt = NULL;
116STATIC ECHAR *Yanked = NULL;
117STATIC char *Screen = NULL;
118/* STATIC char NEWLINE[]= CRLF; */
119STATIC HISTORY H;
120int rl_quit;
121STATIC int Repeat;
122STATIC int End;
123STATIC int Mark;
124STATIC int OldPoint;
125STATIC int Point;
126extern int el_PushBack;
127extern int el_Pushed;
128FORWARD KEYMAP Map[33];
129FORWARD KEYMAP MetaMap[64];
130STATIC ESIZE_T Length;
131STATIC ESIZE_T ScreenCount;
132STATIC ESIZE_T ScreenSize;
133STATIC ECHAR *backspace = NULL;
134STATIC ECHAR *upline = NULL;
135STATIC ECHAR *clrpage = NULL;
136STATIC ECHAR *downline = NULL;
137STATIC ECHAR *move_right = NULL;
138STATIC ECHAR *newline = NULL;
139STATIC ECHAR *bol = NULL;
140STATIC ECHAR *nextline = NULL;
141STATIC int TTYwidth;
142STATIC int TTYrows;
143STATIC int RequireNLforWrap = 1;
144STATIC int el_intr_pending = 0;
145int el_no_echo = 0; /* e.g under emacs */
146
147/* A little ansification with prototypes -- awb */
148extern void TTYflush();
149STATIC void TTYput(ECHAR c);
150STATIC void TTYputs(ECHAR *p);
151STATIC void TTYshow(ECHAR c);
152STATIC void TTYstring(ECHAR *p);
153extern unsigned int TTYget();
154STATIC void TTYinfo();
155STATIC void print_columns(int ac, char **av);
156STATIC void reposition(int reset);
157STATIC void left(STATUS Change);
158STATIC void right(STATUS Change);
159STATIC STATUS ring_bell();
160#if 0
161STATIC STATUS do_macro(unsigned int c);
162#endif
163STATIC STATUS do_forward(STATUS move);
164STATIC STATUS do_case(ECHAR type);
165STATIC STATUS case_down_word();
166STATIC STATUS case_up_word();
167STATIC void ceol();
168STATIC void clear_line();
169STATIC STATUS insert_string(ECHAR *p);
170STATIC ECHAR *next_hist();
171STATIC ECHAR *prev_hist();
172STATIC STATUS do_insert_hist(ECHAR *p);
173STATIC STATUS do_hist(ECHAR *(*move)());
174STATIC STATUS h_next();
175STATIC STATUS h_prev();
176STATIC STATUS h_first();
177STATIC STATUS h_last();
178STATIC int substrcmp(char *text, char *pat, int len);
179STATIC ECHAR *search_hist(ECHAR *search, ECHAR *(*move)());
180STATIC STATUS h_search();
181STATIC STATUS fd_char();
182STATIC void save_yank(int begin, int i);
183STATIC STATUS delete_string(int count);
184STATIC STATUS bk_char();
185STATIC STATUS bk_del_char();
186STATIC STATUS redisplay();
187STATIC STATUS kill_line();
188STATIC char *rsearch_hist(char *patt, int *lpos,int *cpos);
189STATIC STATUS h_risearch();
190STATIC STATUS insert_char(int c);
191STATIC STATUS meta();
192STATIC STATUS emacs(unsigned int c);
193STATIC STATUS TTYspecial(unsigned int c);
194STATIC ECHAR *editinput();
195STATIC void hist_add(ECHAR *p);
196STATIC STATUS beg_line();
197STATIC STATUS del_char();
198STATIC STATUS end_line();
199STATIC ECHAR *find_word();
200STATIC STATUS c_complete();
201STATIC STATUS c_possible();
202STATIC STATUS accept_line();
203STATIC STATUS transpose();
204STATIC STATUS quote();
205STATIC STATUS wipe();
206STATIC STATUS mk_set();
207STATIC STATUS exchange();
208STATIC STATUS yank();
209STATIC STATUS copy_region();
210STATIC STATUS move_to_char();
211STATIC STATUS fd_word();
212STATIC STATUS fd_kill_word();
213STATIC STATUS bk_word();
214STATIC STATUS bk_kill_word();
215STATIC int argify(ECHAR *line, ECHAR ***avp);
216STATIC STATUS last_argument();
217
218/* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
219int rl_meta_chars = 0;
220
221/*
222** Declarations.
223*/
224STATIC ECHAR *editinput();
225#if defined(USE_TERMCAP)
226extern char *getenv();
227extern char *tgetstr();
228extern int tgetent();
229extern int tgetnum();
230#endif /* defined(USE_TERMCAP) */
231
232/*
233** TTY input/output functions.
234*/
235
236void TTYflush()
237{
238 if (ScreenCount) {
239 if (el_no_echo == 0)
240 (void)write(1, Screen, ScreenCount);
241 ScreenCount = 0;
242 }
243}
244
245STATIC void TTYput(ECHAR c)
246{
247 Screen[ScreenCount] = c;
248 if (++ScreenCount >= ScreenSize - 1) {
249 ScreenSize += SCREEN_INC;
250 RENEW(Screen, char, ScreenSize);
251 }
252}
253
254STATIC void TTYputs(ECHAR *p)
255{
256 while (*p)
257 TTYput(*p++);
258}
259
260STATIC void TTYshow(ECHAR c)
261{
262 if (c == DEL) {
263 TTYput('^');
264 TTYput('?');
265 }
266 else if (ISCTL(c)) {
267 TTYput('^');
268 TTYput(UNCTL(c));
269 }
270 else if (rl_meta_chars && ISMETA(c)) {
271 TTYput('M');
272 TTYput('-');
273 TTYput(UNMETA(c));
274 }
275 else
276 TTYput(c);
277}
278
279STATIC void TTYstring(ECHAR *p)
280{
281 while (*p)
282 TTYshow(*p++);
283}
284
285#if 0
286/* Old one line version */
287#define TTYback() (backspace ? TTYputs((ECHAR *)backspace) : TTYput('\b'))
288#endif
289
290STATIC int printlen(CONST char *p)
291{
292 int len = 0;
293
294 for (len=0; *p; p++)
295 if ((*p == DEL) || (ISCTL(*p)))
296 len += 2;
297 else if (rl_meta_chars && ISMETA(*p))
298 len += 3;
299 else
300 len += 1;
301
302 return len;
303}
304
305STATIC int screen_pos()
306{
307 /* Returns the number of characters printed from beginning of line */
308 /* includes the size of the prompt and and meta/ctl char expansions */
309 int p = strlen(Prompt);
310 int i;
311
312 for (i=0; i < Point; i++)
313 if ((Line[i] == DEL) ||
314 (ISCTL(Line[i])))
315 p += 2;
316 else if (rl_meta_chars && ISMETA(Line[i]))
317 p += 3;
318 else
319 p += 1;
320
321 return p;
322}
323
324STATIC void TTYback()
325{
326 /* awb: added upline (if supported) when back goes over line boundary */
327 int i;
328 int sp = screen_pos();
329
330 if (upline && sp && (sp%TTYwidth == 0))
331 { /* move up a line and move to the end */
332 TTYputs(upline);
333 TTYputs(bol);
334 for (i=0; i < TTYwidth; i++)
335 TTYputs(move_right);
336 }
337 else if (backspace)
338 TTYputs((ECHAR *)backspace);
339 else
340 TTYput('\b');
341}
342
343STATIC void TTYinfo()
344{
345 static int init;
346#if defined(USE_TERMCAP)
347 char *term;
348 char *buff;
349 char *buff2;
350 char *bp;
351#endif /* defined(USE_TERMCAP) */
352#if defined(TIOCGWINSZ)
353 struct winsize W;
354#endif /* defined(TIOCGWINSZ) */
355
356 if (init) {
357#if defined(TIOCGWINSZ)
358 /* Perhaps we got resized. */
359 if (ioctl(0, TIOCGWINSZ, &W) >= 0
360 && W.ws_col > 0 && W.ws_row > 0) {
361 TTYwidth = (int)W.ws_col;
362 TTYrows = (int)W.ws_row;
363 }
364#endif /* defined(TIOCGWINSZ) */
365 return;
366 }
367 init++;
368
369 TTYwidth = TTYrows = 0;
370#if defined(USE_TERMCAP)
371 buff = walloc(char,2048);
372 buff2 = walloc(char,2048);
373 bp = &buff2[0];
374 if ((term = getenv("TERM")) == NULL)
375 term = "dumb";
376 if (tgetent(buff, term) < 0) {
377 TTYwidth = SCREEN_WIDTH;
378 TTYrows = SCREEN_ROWS;
379 return;
380 }
381 backspace = (ECHAR *)tgetstr("le", &bp);
382 upline = (ECHAR *)tgetstr("up", &bp);
383 clrpage = (ECHAR *)tgetstr("cl", &bp);
384 nextline = (ECHAR *)tgetstr("nl", &bp);
385 if (nextline==NULL)
386 nextline = (ECHAR *)"\n";
387 if (strncmp(term, "pcansi", 6)==0 || strncmp(term, "cygwin", 6)==0)
388 {
389 bol = (ECHAR *)"\033[0G";
390 RequireNLforWrap = 0; /* doesn't require nl to get to next line */
391 }
392 else
393 bol = (ECHAR *)tgetstr("cr", &bp);
394 if (bol==NULL)
395 bol = (ECHAR *)"\r";
396
397 newline= walloc(ECHAR, 20);
398 strcpy((char *)newline,(char *)bol);
399 strcat((char *)newline,(char *)nextline);
400
401 downline = (ECHAR *)newline;
402 move_right = (ECHAR *)tgetstr("nd", &bp);
403 if (!move_right || !downline)
404 upline = NULL; /* terminal doesn't support enough so fall back */
405 TTYwidth = tgetnum("co");
406 TTYrows = tgetnum("li");
407#endif /* defined(USE_TERMCAP) */
408
409#if defined(TIOCGWINSZ)
410 if (ioctl(0, TIOCGWINSZ, &W) >= 0) {
411 TTYwidth = (int)W.ws_col;
412 TTYrows = (int)W.ws_row;
413 }
414#endif /* defined(TIOCGWINSZ) */
415
416 if (TTYwidth <= 0 || TTYrows <= 0) {
417 TTYwidth = SCREEN_WIDTH;
418 TTYrows = SCREEN_ROWS;
419 }
420}
421
422
423/*
424** Print an array of words in columns.
425*/
426STATIC void print_columns(int ac, char **av)
427{
428 ECHAR *p;
429 int i,c;
430 int j;
431 int k;
432 int len;
433 int skip;
434 int longest;
435 int cols;
436 char info1[1024];
437
438 if (ac > 99)
439 {
440 TTYputs((ECHAR *)newline);
441 sprintf(info1,"There are %d possibilities. Do you really \n",ac);
442 TTYputs((ECHAR *)info1);
443 TTYputs((ECHAR *)"want to see them all (y/n) ? ");
444 while (((c = TTYget()) != EOF) && ((strchr("YyNn ",c) == NULL)))
445 ring_bell();
446 if (strchr("Nn",c) != NULL)
447 {
448 TTYputs((ECHAR *)newline);
449 return;
450 }
451 }
452
453 /* Find longest name, determine column count from that. */
454 for (longest = 0, i = 0; i < ac; i++)
455 if ((j = strlen((char *)av[i])) > longest)
456 longest = j;
457 cols = TTYwidth / (longest + 3);
458 if (cols < 1) cols = 1;
459
460 TTYputs((ECHAR *)newline);
461 for (skip = ac / cols + 1, i = 0; i < skip; i++) {
462 for (j = i; j < ac; j += skip) {
463 for (p = (ECHAR *)av[j], len = strlen((char *)p), k = len;
464 --k >= 0; p++)
465 TTYput(*p);
466 if (j + skip < ac)
467 while (++len < longest + 3)
468 TTYput(' ');
469 }
470 TTYputs((ECHAR *)newline);
471 }
472}
473
474STATIC void reposition(int reset)
475{
476 int i,PPoint;
477 int pos;
478 char ppp[2];
479
480 if (reset)
481 {
482 TTYputs(bol);
483 for (i=screen_pos()/TTYwidth; i > 0; i--)
484 if (upline) TTYputs(upline);
485 }
486 TTYputs((ECHAR *)Prompt);
487 pos = printlen(Prompt);
488 ppp[1] = '\0';
489 for (i = 0; i < End; i++)
490 {
491 ppp[0] = Line[i];
492 TTYshow(Line[i]);
493 pos += printlen(ppp);
494 if ((pos%TTYwidth) == 0)
495 if (RequireNLforWrap && downline) TTYputs(downline);
496 }
497 PPoint = Point;
498 for (Point = End;
499 Point > PPoint;
500 Point--)
501 {
502 if (rl_meta_chars && ISMETA(Line[Point]))
503 {
504 TTYback();
505 TTYback();
506 }
507 else if (ISCTL(Line[Point]))
508 TTYback();
509 TTYback();
510 }
511 Point = PPoint;
512}
513
514STATIC void left(STATUS Change)
515{
516 TTYback();
517 if (Point) {
518 if (ISCTL(Line[Point - 1]))
519 TTYback();
520 else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
521 TTYback();
522 TTYback();
523 }
524 }
525 if (Change == CSmove)
526 Point--;
527}
528
529STATIC void right(STATUS Change)
530{
531 TTYshow(Line[Point]);
532 if (Change == CSmove)
533 Point++;
534 if ((screen_pos())%TTYwidth == 0)
535 if (downline && RequireNLforWrap) TTYputs(downline);
536}
537
538STATIC STATUS ring_bell()
539{
540 TTYput('\07');
541 TTYflush();
542 return CSstay;
543}
544
545#if 0
546STATIC STATUS do_macro(unsigned int c)
547{
548 ECHAR name[4];
549
550 name[0] = '_';
551 name[1] = c;
552 name[2] = '_';
553 name[3] = '\0';
554
555 if ((el_Input = (ECHAR *)getenv((char *)name)) == NULL) {
556 el_Input = el_NIL;
557 return ring_bell();
558 }
559 return CSstay;
560}
561#endif
562
563STATIC STATUS do_forward(STATUS move)
564{
565 int i;
566 ECHAR *p;
567 (void) move;
568
569 i = 0;
570 do {
571 p = &Line[Point];
572 for ( ; Point < End && (*p == ' ' || !isalnum(*p)); p++)
573 right(CSmove);
574
575 for (; Point < End && isalnum(*p); p++)
576 right(CSmove);
577
578 if (Point == End)
579 break;
580 } while (++i < Repeat);
581
582 return CSstay;
583}
584
585STATIC STATUS do_case(ECHAR type)
586{
587 int i;
588 int end;
589 int count;
590 ECHAR *p;
591 int OP;
592
593 OP = Point;
594 (void)do_forward(CSstay);
595 if (OP != Point) {
596 if ((count = Point - OP) < 0)
597 count = -count;
598 for ( ; Point > OP; Point --)
599 TTYback();
600 if ((end = Point + count) > End)
601 end = End;
602 for (i = Point, p = &Line[Point]; Point < end; p++) {
603 if ((type == TOupper) ||
604 ((type == TOcapitalize) && (Point == i)))
605 {
606 if (islower(*p))
607 *p = toupper(*p);
608 }
609 else if (isupper(*p))
610 *p = tolower(*p);
611 right(CSmove);
612 }
613 }
614 return CSstay;
615}
616
617STATIC STATUS case_down_word()
618{
619 return do_case(TOlower);
620}
621
622STATIC STATUS case_up_word()
623{
624 return do_case(TOupper);
625}
626
627STATIC STATUS case_cap_word()
628{
629 return do_case(TOcapitalize);
630}
631
632STATIC void ceol()
633{
634 int extras;
635 int i, PPoint;
636 ECHAR *p;
637
638 PPoint = Point;
639 for (extras = 0, i = Point, p = &Line[i]; i < End; i++, p++) {
640 Point++;
641 TTYput(' ');
642 if (ISCTL(*p)) {
643 TTYput(' ');
644 extras++;
645 }
646 else if (rl_meta_chars && ISMETA(*p)) {
647 TTYput(' ');
648 TTYput(' ');
649 extras += 2;
650 }
651 else if ((screen_pos())%TTYwidth == 0)
652 if (downline && RequireNLforWrap) TTYputs(downline);
653 }
654
655 Point = End;
656 for (Point = End;
657 Point > PPoint;
658 Point--)
659 {
660 if (rl_meta_chars && ISMETA(Line[Point-1]))
661 {
662 TTYback();
663 TTYback();
664 }
665 else if (ISCTL(Line[Point-1]))
666 TTYback();
667 TTYback();
668 }
669 Point = PPoint;
670
671}
672
673STATIC void clear_line()
674{
675 int i;
676 TTYputs(bol);
677 for (i=screen_pos()/TTYwidth; i > 0; i--)
678 if (upline) TTYputs(upline);
679 for (i=0; i < strlen(Prompt); i++)
680 TTYput(' ');
681 Point = 0;
682 ceol();
683 TTYputs(bol);
684 /* In case the prompt is more than one line long */
685 for (i=screen_pos()/TTYwidth; i > 0; i--)
686 if (upline) TTYputs(upline);
687 Point = 0;
688 End = 0;
689 Line[0] = '\0';
690}
691
692STATIC STATUS insert_string(ECHAR *p)
693{
694 ESIZE_T len;
695 int i,pos0,pos1;
696 ECHAR *new;
697 ECHAR *q;
698
699 len = strlen((char *)p);
700 if (End + len >= Length) {
701 if ((new = NEW(ECHAR, Length + len + MEM_INC)) == NULL)
702 return CSstay;
703 if (Length) {
704 COPYFROMTO(new, Line, Length);
705 DISPOSE(Line);
706 }
707 Line = new;
708 Length += len + MEM_INC;
709 }
710
711 for (q = &Line[Point], i = End - Point; --i >= 0; )
712 q[len + i] = q[i];
713 COPYFROMTO(&Line[Point], p, len);
714 End += len;
715 Line[End] = '\0';
716 pos0 = screen_pos();
717 pos1 = printlen((char *)&Line[Point]);
718 TTYstring(&Line[Point]);
719 Point += len;
720 if ((pos0+pos1)%TTYwidth == 0)
721 if (downline && RequireNLforWrap) TTYputs(downline);
722 /* if the line is longer than TTYwidth this may put the cursor */
723 /* on the next line and confuse some other parts, so put it back */
724 /* at Point */
725 if (upline && (Point != End))
726 {
727 pos0 = screen_pos();
728 pos1 = printlen((char *)&Line[Point]);
729 for (i=((pos0%TTYwidth)+pos1)/TTYwidth; i > 0; i--)
730 if (upline) TTYputs(upline);
731 TTYputs(bol);
732 for (i=0 ; i < (pos0%TTYwidth); i++)
733 TTYputs(move_right);
734 }
735
736 return Point == End ? CSstay : CSmove;
737}
738
739
740STATIC ECHAR *next_hist()
741{
742 return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
743}
744
745STATIC ECHAR *prev_hist()
746{
747 return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
748}
749
750STATIC STATUS do_insert_hist(ECHAR *p)
751{
752 int i;
753 if (p == NULL)
754 return ring_bell();
755 for (i=screen_pos()/TTYwidth; i > 0; i--)
756 if (upline) TTYputs(upline);
757 Point = 0;
758 reposition(1);
759 ceol();
760 End = 0;
761 return insert_string(p);
762}
763
764STATIC STATUS do_hist(ECHAR *(*move)())
765{
766 ECHAR *p;
767 int i;
768
769 i = 0;
770 do {
771 if ((p = (*move)()) == NULL)
772 return ring_bell();
773 } while (++i < Repeat);
774 return do_insert_hist(p);
775}
776
777STATIC STATUS h_next()
778{
779 return do_hist(next_hist);
780}
781
782STATIC STATUS h_prev()
783{
784 return do_hist(prev_hist);
785}
786
787STATIC STATUS h_first()
788{
789 return do_insert_hist(H.Lines[H.Pos = 0]);
790}
791
792STATIC STATUS h_last()
793{
794 return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
795}
796
797/*
798** Return zero if pat appears as a substring in text.
799*/
800STATIC int substrcmp(char *text, char *pat, int len)
801{
802 ECHAR c;
803
804 if ((c = *pat) == '\0')
805 return *text == '\0';
806 for ( ; *text; text++)
807 if (*text == c && strncmp(text, pat, len) == 0)
808 return 0;
809 return 1;
810}
811
812STATIC ECHAR *search_hist(ECHAR *search, ECHAR *(*move)())
813{
814 static ECHAR *old_search;
815 int len;
816 int pos;
817 int (*match)();
818 char *pat;
819
820 /* Save or get remembered search pattern. */
821 if (search && *search) {
822 if (old_search)
823 DISPOSE(old_search);
824 old_search = (ECHAR *)STRDUP((const char *)search);
825 }
826 else {
827 if (old_search == NULL || *old_search == '\0')
828 return NULL;
829 search = old_search;
830 }
831
832 /* Set up pattern-finder. */
833 if (*search == '^') {
834 match = strncmp;
835 pat = (char *)(search + 1);
836 }
837 else {
838 match = substrcmp;
839 pat = (char *)search;
840 }
841 len = strlen(pat);
842
843 for (pos = H.Pos; (*move)() != NULL; )
844 if ((*match)((char *)H.Lines[H.Pos], pat, len) == 0)
845 return H.Lines[H.Pos];
846 H.Pos = pos;
847 return NULL;
848}
849
850STATIC STATUS h_search()
851{
852 static int Searching;
853 CONST char *old_prompt;
854 ECHAR *(*move)();
855 ECHAR *p;
856
857 if (Searching)
858 return ring_bell();
859 Searching = 1;
860
861 clear_line();
862 old_prompt = Prompt;
863 Prompt = "Search: ";
864 TTYputs((ECHAR *)Prompt);
865 move = Repeat == NO_ARG ? prev_hist : next_hist;
866 p = search_hist(editinput(), move);
867 clear_line();
868 Prompt = old_prompt;
869 TTYputs((ECHAR *)Prompt);
870
871 Searching = 0;
872 return do_insert_hist(p);
873}
874
875STATIC STATUS fd_char()
876{
877 int i;
878
879 i = 0;
880 do {
881 if (Point >= End)
882 break;
883 right(CSmove);
884 } while (++i < Repeat);
885 return CSstay;
886}
887
888STATIC void save_yank(int begin, int i)
889{
890 if (Yanked) {
891 DISPOSE(Yanked);
892 Yanked = NULL;
893 }
894
895 if (i < 1)
896 return;
897
898 if ((Yanked = NEW(ECHAR, (ESIZE_T)i + 1)) != NULL) {
899 COPYFROMTO(Yanked, &Line[begin], i);
900 Yanked[i] = '\0';
901 }
902}
903
904STATIC STATUS delete_string(int count)
905{
906 int i;
907 int pos0,pos1,q;
908 char *tLine;
909
910 if (count <= 0 || End == Point)
911 return ring_bell();
912
913 if (Point + count > End && (count = End - Point) <= 0)
914 return CSstay;
915
916 if (count > 1)
917 save_yank(Point, count);
918
919 tLine = STRDUP((char *)Line);
920 ceol();
921 for (q = Point, i = End - (Point + count) + 1; --i >= 0; q++)
922 Line[q] = tLine[q+count];
923 wfree(tLine);
924 End -= count;
925 pos0 = screen_pos();
926 pos1 = printlen((char *)&Line[Point]);
927 TTYstring(&Line[Point]);
928 if ((pos1 > 0) && (pos0+pos1)%TTYwidth == 0)
929 if (downline && RequireNLforWrap) TTYputs(downline);
930 /* if the line is longer than TTYwidth this may put the cursor */
931 /* on the next line and confuse some other parts, so put it back */
932 /* at Point */
933 if (upline)
934 {
935 for (i=((pos0%TTYwidth)+pos1)/TTYwidth; i > 0; i--)
936 if (upline) TTYputs(upline);
937 TTYputs(bol);
938 for (i=0 ; i < (pos0%TTYwidth); i++)
939 TTYputs(move_right);
940 }
941
942 return CSmove;
943}
944
945STATIC STATUS bk_char()
946{
947 int i;
948
949 i = 0;
950 do {
951 if (Point == 0)
952 break;
953 left(CSmove);
954 } while (++i < Repeat);
955
956 return CSstay;
957}
958
959STATIC STATUS bk_del_char()
960{
961 int i;
962
963 i = 0;
964 do {
965 if (Point == 0)
966 break;
967 left(CSmove);
968 } while (++i < Repeat);
969
970 return delete_string(i);
971}
972
973STATIC STATUS redisplay()
974{
975 if (clrpage) TTYputs(clrpage);
976 else
977 TTYputs((ECHAR *)newline);
978/* TTYputs((ECHAR *)Prompt);
979 TTYstring(Line); */
980 return CSmove;
981}
982
983STATIC STATUS kill_line()
984{
985 int i;
986
987 if (Repeat != NO_ARG) {
988 if (Repeat < Point) {
989 i = Point;
990 Point = Repeat;
991 reposition(1);
992 (void)delete_string(i - Point);
993 }
994 else if (Repeat > Point) {
995 right(CSmove);
996 (void)delete_string(Repeat - Point - 1);
997 }
998 return CSmove;
999 }
1000
1001 save_yank(Point, End - Point);
1002 ceol();
1003 Line[Point] = '\0';
1004 End = Point;
1005 return CSstay;
1006}
1007
1008STATIC char *rsearch_hist(char *patt, int *lpos,int *cpos)
1009{
1010 /* Extension by awb to do reverse incremental searches */
1011
1012 for (; *lpos > 0; (*lpos)--)
1013 {
1014 for ( ; (*cpos) >= 0 ; (*cpos)--)
1015 {
1016/* fprintf(stderr,"comparing %d %s %s\n",*lpos,patt,H.Lines[*lpos]+*cpos); */
1017 if (strncmp(patt,(char *)H.Lines[*lpos]+*cpos,strlen(patt)) == 0)
1018 { /* found a match */
1019 return (char *)H.Lines[*lpos];
1020 }
1021 }
1022 if ((*lpos) > 0)
1023 *cpos = strlen((char *)H.Lines[(*lpos)-1]);
1024 }
1025 return NULL; /* no match found */
1026}
1027
1028STATIC STATUS h_risearch()
1029{
1030 STATUS s;
1031 CONST char *old_prompt;
1032 char *pat, *hist, *nhist;
1033 char *nprompt;
1034 int patend, i;
1035 ECHAR c;
1036 int lpos,cpos;
1037
1038 old_prompt = Prompt;
1039
1040 nprompt = walloc(char,80+160);
1041 pat = walloc(char,80);
1042 patend=0;
1043 pat[0] = '\0';
1044 hist = "";
1045 lpos = H.Pos; /* where the search has to start from */
1046 cpos = strlen((char *)H.Lines[lpos]);
1047 do
1048 {
1049 sprintf(nprompt,"(reverse-i-search)`%s': ",pat);
1050 Prompt = nprompt;
1051 kill_line();
1052 do_insert_hist((ECHAR *)hist);
1053 if (patend != 0)
1054 for (i=strlen((char *)H.Lines[lpos]); i>cpos; i--) bk_char();
1055 c = TTYget();
1056 if ((c >= ' ') || (c == CTL('R')))
1057 {
1058 if (c == CTL('R'))
1059 cpos--;
1060 else if (patend < 79)
1061 {
1062 pat[patend]=c;
1063 patend++;
1064 pat[patend]='\0';
1065 }
1066 else /* too long */
1067 {
1068 ring_bell();
1069 continue;
1070 }
1071 nhist = rsearch_hist(pat,&lpos,&cpos);
1072 if (nhist != NULL)
1073 {
1074 hist = nhist;
1075 H.Pos = lpos;
1076 }
1077 else
1078 { /* oops, no match */
1079 ring_bell();
1080 if (c != CTL('R'))
1081 {
1082 patend--;
1083 pat[patend] = '\0';
1084 }
1085 }
1086 }
1087 } while ((c >= ' ') || (c == CTL('R')));
1088
1089 /* Tidy up */
1090 clear_line();
1091 Prompt = old_prompt;
1092 TTYputs((ECHAR *)Prompt);
1093 wfree(nprompt);
1094
1095 kill_line();
1096 s = do_insert_hist((ECHAR *)hist);
1097 if (patend != 0)
1098 for (i=strlen((char *)H.Lines[lpos]); i>cpos; i--) s = bk_char();
1099 if (c != ESC)
1100 return emacs(c);
1101 else
1102 return s;
1103}
1104
1105STATIC STATUS insert_char(int c)
1106{
1107 STATUS s;
1108 ECHAR buff[2];
1109 ECHAR *p;
1110 ECHAR *q;
1111 int i;
1112
1113 if (Repeat == NO_ARG || Repeat < 2) {
1114 buff[0] = c;
1115 buff[1] = '\0';
1116 return insert_string(buff);
1117 }
1118
1119 if ((p = NEW(ECHAR, Repeat + 1)) == NULL)
1120 return CSstay;
1121 for (i = Repeat, q = p; --i >= 0; )
1122 *q++ = c;
1123 *q = '\0';
1124 Repeat = 0;
1125 s = insert_string(p);
1126 DISPOSE(p);
1127 return s;
1128}
1129
1130STATIC STATUS meta()
1131{
1132 unsigned int c;
1133 KEYMAP *kp;
1134
1135 if ((c = TTYget()) == EOF)
1136 return CSeof;
1137#if defined(ANSI_ARROWS)
1138 /* Also include VT-100 arrows. */
1139 if (c == '[' || c == 'O')
1140 switch (c = TTYget()) {
1141 default: return ring_bell();
1142 case EOF: return CSeof;
1143 case 'A': return h_prev();
1144 case 'B': return h_next();
1145 case 'C': return fd_char();
1146 case 'D': return bk_char();
1147 }
1148#endif /* defined(ANSI_ARROWS) */
1149
1150 if (isdigit(c)) {
1151 for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c); )
1152 Repeat = Repeat * 10 + c - '0';
1153 el_Pushed = 1;
1154 el_PushBack = c;
1155 return CSstay;
1156 }
1157
1158/* if (isupper(c))
1159 return do_macro(c); */
1160 for (OldPoint = Point, kp = MetaMap; kp->Function; kp++)
1161 if (kp->Key == c)
1162 return (*kp->Function)();
1163 if (rl_meta_chars == 0)
1164 {
1165 insert_char(META(c));
1166 return CSmove;
1167 }
1168
1169 return ring_bell();
1170}
1171
1172STATIC STATUS emacs(unsigned int c)
1173{
1174 STATUS s;
1175 KEYMAP *kp;
1176
1177 if (ISMETA(c) && rl_meta_chars)
1178 {
1179 el_Pushed = 1;
1180 el_PushBack = UNMETA(c);
1181 return meta();
1182 }
1183 for (kp = Map; kp->Function; kp++)
1184 if (kp->Key == c)
1185 break;
1186 s = kp->Function ? (*kp->Function)() : insert_char((int)c);
1187 if (!el_Pushed)
1188 /* No pushback means no repeat count; hacky, but true. */
1189 Repeat = NO_ARG;
1190 return s;
1191}
1192
1193STATIC STATUS TTYspecial(unsigned int c)
1194{
1195 int i;
1196
1197 if (ISMETA(c))
1198 return CSdispatch;
1199
1200 if (c == rl_erase || c == DEL)
1201 return bk_del_char();
1202 if (c == rl_kill) {
1203 if (Point != 0) {
1204 for (i=screen_pos()/TTYwidth; i > 0; i--)
1205 if (upline) TTYputs(upline);
1206 Point = 0;
1207 reposition(1);
1208 }
1209 Repeat = NO_ARG;
1210 return kill_line();
1211 }
1212 if (c == rl_intr || c == rl_quit) {
1213 Point = End = 0;
1214 Line[0] = '\0';
1215 if (c == rl_intr)
1216 {
1217 el_intr_pending = 1;
1218 return CSdone;
1219 }
1220 else
1221 return redisplay();
1222 }
1223 if (c == rl_eof && Point == 0 && End == 0)
1224 return CSeof;
1225
1226 return CSdispatch;
1227}
1228
1229STATIC ECHAR *editinput()
1230{
1231 unsigned int c;
1232
1233 Repeat = NO_ARG;
1234 OldPoint = Point = Mark = End = 0;
1235 Line[0] = '\0';
1236
1237 while ((c = TTYget()) != EOF)
1238 {
1239 switch (TTYspecial(c)) {
1240 case CSdone:
1241 return Line;
1242 case CSeof:
1243 return NULL;
1244 case CSmove:
1245 reposition(1);
1246 break;
1247 case CSstay:
1248 break;
1249 case CSdispatch:
1250 switch (emacs(c)) {
1251 case CSdone:
1252 return Line;
1253 case CSeof:
1254 return NULL;
1255 case CSmove:
1256 reposition(1);
1257 break;
1258 case CSstay:
1259 case CSdispatch:
1260 break;
1261 }
1262 break;
1263 }
1264 }
1265 return NULL;
1266}
1267
1268STATIC void hist_add(ECHAR *p)
1269{
1270 int i;
1271
1272 if ((p = (ECHAR *)STRDUP((char *)p)) == NULL)
1273 return;
1274 if (H.Size < editline_histsize)
1275 H.Lines[H.Size++] = p;
1276 else {
1277 DISPOSE(H.Lines[0]);
1278 for (i = 0; i < editline_histsize - 1; i++)
1279 H.Lines[i] = H.Lines[i + 1];
1280 H.Lines[i] = p;
1281 }
1282 H.Pos = H.Size - 1;
1283}
1284
1285/* Added by awb 29/12/98 to get saved history file */
1286void write_history(const char *history_file)
1287{
1288 FILE *fd;
1289 int i;
1290
1291 if ((fd = fopen(history_file,"wb")) == NULL)
1292 {
1293 fprintf(stderr,"editline: can't access history file \"%s\"\n",
1294 history_file);
1295 return;
1296 }
1297
1298 for (i=0; i < H.Size; i++)
1299 fprintf(fd,"%s\n",H.Lines[i]);
1300 fclose(fd);
1301}
1302
1303void read_history(const char *history_file)
1304{
1305 FILE *fd;
1306 char buff[2048];
1307 int c,i;
1308
1309 H.Lines = NEW(ECHAR *,editline_histsize);
1310 H.Size = 0;
1311 H.Pos = 0;
1312
1313 if ((fd = fopen(history_file,"rb")) == NULL)
1314 return; /* doesn't have a history file yet */
1315
1316 while ((c=getc(fd)) != EOF)
1317 {
1318 ungetc(c,fd);
1319 for (i=0; ((c=getc(fd)) != '\n') && (c != EOF); i++)
1320 if (i < 2047)
1321 buff[i] = c;
1322 buff[i] = '\0';
1323 add_history(buff);
1324 }
1325
1326 fclose(fd);
1327}
1328
1329/*
1330** For compatibility with FSF readline.
1331*/
1332/* ARGSUSED0 */
1333void
1334rl_reset_terminal(char *p)
1335{
1336}
1337
1338void
1339rl_initialize()
1340{
1341}
1342
1343char *readline(CONST char *prompt)
1344{
1345 ECHAR *line;
1346
1347 if (Line == NULL) {
1348 Length = MEM_INC;
1349 if ((Line = NEW(ECHAR, Length)) == NULL)
1350 return NULL;
1351 }
1352
1353 TTYinfo();
1354 rl_ttyset(0);
1355 hist_add(el_NIL);
1356 ScreenSize = SCREEN_INC;
1357 Screen = NEW(char, ScreenSize);
1358 Prompt = prompt ? prompt : (char *)el_NIL;
1359 el_intr_pending = 0;
1360 if (el_no_echo == 1)
1361 {
1362 el_no_echo = 0;
1363 TTYputs((ECHAR *)Prompt);
1364 TTYflush();
1365 el_no_echo = 1;
1366 }
1367 else
1368 TTYputs((ECHAR *)Prompt);
1369 line = editinput();
1370 if (line != NULL) {
1371 line = (ECHAR *)STRDUP((char *)line);
1372 TTYputs((ECHAR *)newline);
1373 TTYflush();
1374 }
1375 rl_ttyset(1);
1376 DISPOSE(Screen);
1377 DISPOSE(H.Lines[--H.Size]);
1378 if (el_intr_pending)
1379 do_user_intr();
1380 return (char *)line;
1381}
1382
1383void
1384add_history(p)
1385 char *p;
1386{
1387 if (p == NULL || *p == '\0')
1388 return;
1389
1390#if defined(UNIQUE_HISTORY)
1391 if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
1392 return;
1393#endif /* defined(UNIQUE_HISTORY) */
1394 hist_add((ECHAR *)p);
1395}
1396
1397
1398STATIC STATUS beg_line()
1399{
1400 int i;
1401 if (Point) {
1402 for (i=screen_pos()/TTYwidth; i > 0; i--)
1403 if (upline) TTYputs(upline);
1404 Point = 0;
1405 return CSmove;
1406 }
1407 return CSstay;
1408}
1409
1410STATIC STATUS del_char()
1411{
1412 return delete_string(Repeat == NO_ARG ? 1 : Repeat);
1413}
1414
1415STATIC STATUS end_line()
1416{
1417 if (Point != End) {
1418 while (Point < End)
1419 {
1420 TTYput(Line[Point]);
1421 Point++;
1422 }
1423 return CSmove;
1424 }
1425 return CSstay;
1426}
1427
1428/*
1429** Move back to the beginning of the current word and return an
1430** allocated copy of it.
1431*/
1432STATIC ECHAR *find_word()
1433{
1434 static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
1435 ECHAR *p;
1436 ECHAR *new;
1437 ESIZE_T len;
1438
1439 for (p = &Line[Point]; p > Line && strchr(SEPS, (char)p[-1]) == NULL; p--)
1440 continue;
1441 len = Point - (p - Line) + 1;
1442 if ((new = NEW(ECHAR, len)) == NULL)
1443 return NULL;
1444 COPYFROMTO(new, p, len);
1445 new[len - 1] = '\0';
1446 return new;
1447}
1448
1449void el_redisplay()
1450{
1451 reposition(0); /* redisplay assuming already on newline */
1452}
1453
1454char *el_current_sym()
1455{
1456 /* Get current symbol at point -- awb*/
1457 char *symbol = NULL;
1458 int i,j;
1459
1460 if (End == 0)
1461 return NULL;
1462 if (Point == End)
1463 i=Point-1;
1464 else
1465 i=Point;
1466
1467 for ( ;
1468 ((i >= 0) &&
1469 (strchr("()' \t\n\r",Line[i]) != NULL));
1470 i--);
1471 /* i will be on final or before final character */
1472 if (i < 0)
1473 return NULL;
1474 /* But if its not at the end of the current symbol move it there */
1475 for (; i < End; i++)
1476 if (strchr("()' \t\n\r\"",Line[i]) != NULL)
1477 break;
1478 for (j=i-1; j >=0; j--)
1479 if (strchr("()' \t\n\r\"",Line[j]) != NULL)
1480 break;
1481
1482 symbol = walloc(char,i-j);
1483 strncpy(symbol,(char *)&Line[j+1],i-(j+1));
1484 symbol[i-(j+1)] = '\0';
1485
1486 return symbol;
1487}
1488
1489static char *completion_to_ambiguity(int index,char **possibles)
1490{
1491 /* Find the string that extends from index in possibles until an */
1492 /* ambiguity is found -- awb */
1493 char *p;
1494 int e,i;
1495 int extending;
1496
1497 extending = 1;
1498 e = index;
1499
1500 for ( ; extending; e++)
1501 {
1502 for (i=0; possibles[i] != NULL; i++)
1503 if (possibles[i][e] != possibles[0][e])
1504 {
1505 extending = 0;
1506 e--;
1507 break;
1508 }
1509 }
1510
1511 if (e==index)
1512 return NULL; /* already at ambiguity */
1513 else
1514 {
1515 p = walloc(char,(e-index)+1);
1516 strncpy(p,possibles[0]+index,e-index);
1517 p[e-index] = '\0';
1518 return p;
1519 }
1520}
1521
1522static char **el_file_completion_function(char * text, int start, int end)
1523{
1524 /* Interface to editline rl_list_possib which looks up possible */
1525 /* file name completions. */
1526 char *word;
1527 char **matches1;
1528 char **matches2;
1529 int ac,i;
1530
1531 word = walloc(char,(end-start)+1);
1532 strncpy(word,text+start,end-start);
1533 word[end-start]='\0';
1534
1535 ac = rl_list_possib(word,&matches1);
1536 wfree(word);
1537 if (ac == 0)
1538 return NULL;
1539 else
1540 {
1541 matches2 = walloc(char *,ac+1);
1542 for (i=0; i < ac; i++)
1543 matches2[i] = matches1[i];
1544 matches2[i] = NULL;
1545 wfree(matches1);
1546 return matches2;
1547 }
1548}
1549
1550STATIC STATUS c_complete()
1551{
1552 /* Modified by awb 30/12/98 to allow listing of possibles and */
1553 /* a user definable completion method */
1554 char *p;
1555 char *word;
1556 int start;
1557 char **possibles=NULL;
1558 int possiblesc=0;
1559 int started_with_quote = 0;
1560 STATUS s;
1561 int i;
1562
1563 for (start=Point; start > 0; start--)
1564 if (strchr("()' \t\n\r\"",Line[start-1]) != NULL)
1565 break;
1566 word = walloc(char,(Point-start)+1);
1567 strncpy(word,(char *)(Line+start),Point-start);
1568 word[Point-start]='\0';
1569 if ((start > 0) && (Line[start-1] == '"'))
1571
1572 if (el_user_completion_function)
1573 /* May need to look at previous char so pass in Line */
1574 possibles = el_user_completion_function((char *)Line,start,Point);
1575 if (possibles == NULL)
1576 {
1577 possibles = el_file_completion_function((char *)Line,start,Point);
1578 /* As filename completions only complete the final file name */
1579 /* not the full path we need to set a new start position */
1580 for (start=Point; start > 0; start--)
1581 if (strchr("()' \t\n\r\"/",Line[start-1]) != NULL)
1582 break;
1583 }
1584 if (possibles)
1585 for (possiblesc=0; possibles[possiblesc] != NULL; possiblesc++);
1586
1587 if ((!possibles) || (possiblesc == 0)) /* none or none at all */
1588 s = ring_bell();
1589 else if (possiblesc == 1) /* a single expansion */
1590 {
1591 p = walloc(char,strlen(possibles[0])-(Point-start)+2);
1592 sprintf(p,"%s ",possibles[0]+(Point-start));
1593 if ((strlen(p) > 1) && (p[strlen(p)-2] == '/'))
1594 p[strlen(p)-1] = '\0';
1595 else if (started_with_quote)
1596 p[strlen(p)-1] = '"';
1597
1598 s = insert_string((ECHAR *)p);
1599 wfree(p);
1600 }
1601 else if ((p = completion_to_ambiguity(Point-start,possibles)) != NULL)
1602 { /* an expansion to a later ambiguity */
1603 s = insert_string((ECHAR *)p);
1604 wfree(p);
1605 ring_bell();
1606 }
1607 else /* list of possibilities and we can't expand any further */
1608 {
1609 print_columns(possiblesc,possibles); /* display options */
1610 reposition(0); /* display whole line again */
1611 s = CSmove;
1612 }
1613
1614 for (i=0; possibles && possibles[i] != NULL; i++)
1615 wfree(possibles[i]);
1616 wfree(possibles);
1617 wfree(word);
1618
1619 return s;
1620}
1621
1622#if 0
1623/* Original version without automatic listing of possible completions */
1624STATIC STATUS c_complete_old()
1625{
1626 ECHAR *p;
1627 ECHAR *word;
1628 int unique;
1629 STATUS s;
1630
1631 word = find_word();
1632 p = (ECHAR *)rl_complete((char *)word, &unique);
1633 if (word)
1634 DISPOSE(word);
1635 if (p && *p) {
1636 s = insert_string(p);
1637 if (!unique)
1638 (void)ring_bell();
1639 DISPOSE(p);
1640 return s;
1641 }
1642 return ring_bell();
1643}
1644#endif
1645
1646STATIC STATUS c_possible()
1647{
1648 ECHAR **av;
1649 ECHAR *word;
1650 int ac;
1651
1652 word = find_word();
1653 /* The (char ***) ((void *) &av) below is to avoid a warning
1654 * from GCC about casting an unsigned char *** to char ***
1655 */
1656 ac = rl_list_possib((char *)word, (char ***) ((void *) &av));
1657 if (word)
1658 DISPOSE(word);
1659 if (ac) {
1660 print_columns(ac, (char **)av);
1661 reposition(0);
1662 while (--ac >= 0)
1663 DISPOSE(av[ac]);
1664 DISPOSE(av);
1665 return CSmove;
1666 }
1667 return ring_bell();
1668}
1669
1670STATIC STATUS accept_line()
1671{
1672 Line[End] = '\0';
1673 return CSdone;
1674}
1675
1676#ifdef SYSTEM_IS_WIN32
1677STATIC STATUS end_of_input()
1678{
1679 Line[End] = '\0';
1680 return CSeof;
1681}
1682#endif
1683
1684STATIC STATUS transpose()
1685{
1686 ECHAR c;
1687
1688 if (Point) {
1689 if (Point == End)
1690 left(CSmove);
1691 c = Line[Point - 1];
1692 left(CSstay);
1693 Line[Point - 1] = Line[Point];
1694 TTYshow(Line[Point - 1]);
1695 Line[Point++] = c;
1696 TTYshow(c);
1697 }
1698 return CSstay;
1699}
1700
1701STATIC STATUS quote()
1702{
1703 unsigned int c;
1704
1705 return (c = TTYget()) == EOF ? CSeof : insert_char((int)c);
1706}
1707
1708STATIC STATUS wipe()
1709{
1710 int i;
1711
1712 if (Mark > End)
1713 return ring_bell();
1714
1715 if (Point > Mark) {
1716 i = Point;
1717 Point = Mark;
1718 Mark = i;
1719 reposition(1);
1720 }
1721
1722 return delete_string(Mark - Point);
1723}
1724
1725STATIC STATUS mk_set()
1726{
1727 Mark = Point;
1728 return CSstay;
1729}
1730
1731STATIC STATUS exchange()
1732{
1733 unsigned int c;
1734
1735 if ((c = TTYget()) != CTL('X'))
1736 return c == EOF ? CSeof : ring_bell();
1737
1738 if ((c = Mark) <= End) {
1739 Mark = Point;
1740 Point = c;
1741 return CSmove;
1742 }
1743 return CSstay;
1744}
1745
1746STATIC STATUS yank()
1747{
1748 if (Yanked && *Yanked)
1749 return insert_string(Yanked);
1750 return CSstay;
1751}
1752
1753STATIC STATUS copy_region()
1754{
1755 if (Mark > End)
1756 return ring_bell();
1757
1758 if (Point > Mark)
1759 save_yank(Mark, Point - Mark);
1760 else
1761 save_yank(Point, Mark - Point);
1762
1763 return CSstay;
1764}
1765
1766STATIC STATUS move_to_char()
1767{
1768 unsigned int c;
1769 int i;
1770 ECHAR *p;
1771
1772 if ((c = TTYget()) == EOF)
1773 return CSeof;
1774 for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1775 if (*p == c) {
1776 Point = i;
1777 return CSmove;
1778 }
1779 return CSstay;
1780}
1781
1782STATIC STATUS fd_word()
1783{
1784 return do_forward(CSmove);
1785}
1786
1787STATIC STATUS fd_kill_word()
1788{
1789 int i;
1790 int OP;
1791
1792 OP = Point;
1793 (void)do_forward(CSmove);
1794 if (OP != Point) {
1795 i = Point - OP;
1796 for ( ; Point > OP; Point --)
1797 TTYback();
1798 return delete_string(i);
1799 }
1800 return CSmove;
1801}
1802
1803STATIC STATUS bk_word()
1804{
1805 int i;
1806 ECHAR *p;
1807
1808 i = 0;
1809 do {
1810 for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1811 left(CSmove);
1812
1813 for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1814 left(CSmove);
1815
1816 if (Point == 0)
1817 break;
1818 } while (++i < Repeat);
1819
1820 return CSstay;
1821}
1822
1823STATIC STATUS bk_kill_word()
1824{
1825 (void)bk_word();
1826 if (OldPoint != Point)
1827 return delete_string(OldPoint - Point);
1828 return CSstay;
1829}
1830
1831STATIC int argify(ECHAR *line, ECHAR ***avp)
1832{
1833 ECHAR *c;
1834 ECHAR **p;
1835 ECHAR **new;
1836 int ac;
1837 int i;
1838
1839 i = MEM_INC;
1840 if ((*avp = p = NEW(ECHAR*, i))== NULL)
1841 return 0;
1842
1843 for (c = line; isspace(*c); c++)
1844 continue;
1845 if (*c == '\n' || *c == '\0')
1846 return 0;
1847
1848 for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
1849 if (isspace(*c)) {
1850 *c++ = '\0';
1851 if (*c && *c != '\n') {
1852 if (ac + 1 == i) {
1853 new = NEW(ECHAR*, i + MEM_INC);
1854 if (new == NULL) {
1855 p[ac] = NULL;
1856 return ac;
1857 }
1858 COPYFROMTO(new, p, i * sizeof (char **));
1859 i += MEM_INC;
1860 DISPOSE(p);
1861 *avp = p = new;
1862 }
1863 p[ac++] = c;
1864 }
1865 }
1866 else
1867 c++;
1868 }
1869 *c = '\0';
1870 p[ac] = NULL;
1871 return ac;
1872}
1873
1874STATIC STATUS last_argument()
1875{
1876 ECHAR **av;
1877 ECHAR *p;
1878 STATUS s;
1879 int ac;
1880
1881 if (H.Size == 1 || (p = H.Lines[H.Size - 2]) == NULL)
1882 return ring_bell();
1883
1884 if ((p = (ECHAR *)STRDUP((char *)p)) == NULL)
1885 return CSstay;
1886 ac = argify(p, &av);
1887
1888 if (Repeat != NO_ARG)
1889 s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1890 else
1891 s = ac ? insert_string(av[ac - 1]) : CSstay;
1892
1893 if (ac)
1894 DISPOSE(av);
1895 DISPOSE(p);
1896 return s;
1897}
1898
1899STATIC KEYMAP Map[33] = {
1900 { CTL('@'), ring_bell },
1901 { CTL('A'), beg_line },
1902 { CTL('B'), bk_char },
1903 { CTL('D'), del_char },
1904 { CTL('E'), end_line },
1905 { CTL('F'), fd_char },
1906 { CTL('G'), ring_bell },
1907 { CTL('H'), bk_del_char },
1908 { CTL('I'), c_complete },
1909 { CTL('J'), accept_line },
1910 { CTL('K'), kill_line },
1911 { CTL('L'), redisplay },
1912 { CTL('M'), accept_line },
1913 { CTL('N'), h_next },
1914 { CTL('O'), ring_bell },
1915 { CTL('P'), h_prev },
1916 { CTL('Q'), ring_bell },
1917 { CTL('R'), h_risearch },
1918 { CTL('S'), h_search },
1919 { CTL('T'), transpose },
1920 { CTL('U'), ring_bell },
1921 { CTL('V'), quote },
1922 { CTL('W'), wipe },
1923 { CTL('X'), exchange },
1924 { CTL('Y'), yank },
1925#ifdef SYSTEM_IS_WIN32
1926 { CTL('Z'), end_of_input },
1927#else
1928 { CTL('Z'), ring_bell },
1929#endif
1930 { CTL('['), meta },
1931 { CTL(']'), move_to_char },
1932 { CTL('^'), ring_bell },
1933 { CTL('_'), ring_bell },
1934 { 0, NULL }
1935};
1936
1937STATIC KEYMAP MetaMap[64]= {
1938 { CTL('H'), bk_kill_word },
1939 { DEL, bk_kill_word },
1940 { ' ', mk_set },
1941 { '.', last_argument },
1942 { '<', h_first },
1943 { '>', h_last },
1944 { '?', c_possible },
1945 { 'b', bk_word },
1946 { 'c', case_cap_word },
1947 { 'd', fd_kill_word },
1948 { 'f', fd_word },
1949 { 'l', case_down_word },
1950 { 'u', case_up_word },
1951 { 'y', yank },
1952 { 'w', copy_region },
1953 { 0, NULL }
1954};
1955
1956void el_bind_key_in_metamap(char c, Keymap_Function func)
1957{
1958 /* Add given function to key map for META keys */
1959 int i;
1960
1961 for (i=0; MetaMap[i].Key != 0; i++)
1962 {
1963 if (MetaMap[i].Key == c)
1964 {
1965 MetaMap[i].Function = func;
1966 return;
1967 }
1968 }
1969
1970 /* A new key so have to add it to end */
1971 if (i == 63)
1972 {
1973 fprintf(stderr,"editline: MetaMap table full, requires increase\n");
1974 return;
1975 }
1976
1977 MetaMap[i].Function = func;
1978 MetaMap[i].Key = c;
1979 MetaMap[i+1].Function = 0; /* Zero the last location */
1980 MetaMap[i+1].Key = 0; /* Zero the last location */
1981
1982}
1983
1984
K k
The key.
Definition EST_THash.h:78