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