1 /*
2 **
3 **  Main editing routines for editline library.
4 */
5 #include <ctype.h>
6 #include "editline.h"
7 #include "edlproto.h"
8 #include "reader.h"
9 #include "readlib.h"
10 
11 /*
12    **  Manifest constants.
13  */
14 
15 #if 0
16 #define SCREEN_WIDTH    80
17 #define SCREEN_ROWS     24
18 #else
19 #define SCREEN_WIDTH SCREEN_COLS
20 #endif
21 
22 #define NO_ARG          (-1)
23 #define DEL             127
24 #define CTL(x)          ((x) & 0x1F)
25 #define ISCTL(x)        ((x) && (x) < ' ')
26 #define UNCTL(x)        ((x) + 64)
27 #define META(x)         ((x) | 0x80)
28 
29 #ifdef NOMETA
30 #define ISMETA(x)       ((x) & 0x80)
31 #else
32 #define ISMETA(x)       (0)
33 #endif
34 
35 #define UNMETA(x)       ((x) & 0x7F)
36 
37 #if !defined(HIST_SIZE)
38 #define HIST_SIZE 20
39 #endif
40 
41 #ifndef ALVOID
42 #define ALVOID void
43 #endif
44 
45 /*
46    **  Key to command mapping.
47  */
48 typedef struct _KEYMAP {
49     char Key;
50      STATUS(*Func) (ALVOID);
51 } KEYMAP;
52 
53 STATIC KEYMAP MetaMap[16];
54 STATIC KEYMAP Map[33];
55 
56 /*
57    **  Command history structure.
58  */
59 typedef struct _HISTORY {
60     int Size;
61     int Pos;
62     char *Lines[HIST_SIZE];
63 } HISTORY;
64 
65 /*
66  * Globals.
67  */
68 static int rl_eof  = 0x04 ; /* ^D  */
69 static int rl_erase= 0x7f ; /* DEL */
70 static int rl_intr = 0x03 ; /* ^C  */
71 static int rl_kill = 0x15 ; /* ^U  */
72 static int rl_quit = 0x1c ; /* ^\  */
73 
74 STATIC char NilStr[] = "";
75 STATIC char *Input = NilStr;
76 STATIC char *Line = NULL;
77 STATIC const char *Prompt = NULL;
78 STATIC char *Yanked = NULL;
79 STATIC char *Screen;
80 STATIC char NEWLINE[] = CRLF;
81 STATIC HISTORY H;
82 STATIC int Repeat;
83 STATIC int End;
84 STATIC int Mark;
85 STATIC int OldPoint;
86 STATIC int Point;
87 STATIC int PushBack;
88 STATIC int Pushed;
89 STATIC size_t Length;
90 STATIC size_t ScreenCount;
91 STATIC size_t ScreenSize;
92 static char *backspace = NULL;
93 /* NOTE: these MUST be NilStr and *not* NULL */
94 #if defined(HAVE_LIBTERMCAP)
95 char *rev_on = NilStr;
96 char *rev_off = NilStr;
97 char *blink_on = NilStr;
98 char *clear_attr = NilStr;
99 char *bold_on = NilStr;
100 char *clear_scr = NilStr;
101 static char *home = NilStr;
102 char *cur_right = NilStr;
103 char *del_eol = NilStr;
104 #endif
105 
106 #if 0
107 STATIC int TTYwidth;
108 STATIC int TTYrows;
109 #endif
110 
111 /* Display print 8-bit chars as `M-x' or as the actual 8-bit char? */
112 #ifdef NOMETA
113 STATIC int rl_meta_chars = 0;
114 #endif
115 
116 /*
117    **  Declarations.
118  */
119 #if defined(_OS2) || defined(__MSDOS__)
120 STATIC int getakey(char *chr);
121 #endif
122 
123 STATIC char *editinput(ALVOID);
124 
125 /*
126    **  TTY input/output functions.
127  */
128 
129 static void
TTYflush(void)130 TTYflush(void)
131 {
132     if (ScreenCount) {
133 	(void) write(STDOUT_FILENO, Screen, ScreenCount);
134 	ScreenCount = 0;
135     }
136 }
137 
138 STATIC void
TTYput(const int c)139 TTYput(const int c)
140 {
141     Screen[ScreenCount] = (char)c;
142     if (++ScreenCount >= ScreenSize - 1) {
143 	ScreenSize += SCREEN_INC;
144 	Screen = (char *) realloc(Screen, (sizeof(char) * ScreenSize));
145     }
146 }
147 
148 STATIC void
TTYputs(const char * p)149 TTYputs(const char *p)
150 {
151     fflush(stdout);
152     while (*p)
153 	TTYput(*p++);
154 }
155 
156 STATIC void
TTYshow(int c)157 TTYshow(int c)
158 {
159     if (c == DEL) {
160 	TTYput('^');
161 	TTYput('?');
162     } else if (ISCTL(c)) {
163 	TTYput('^');
164 	TTYput(UNCTL(c));
165     }
166 #ifdef NOMETA
167     else if (rl_meta_chars && ISMETA(c)) {
168 	TTYput('M');
169 	TTYput('-');
170 	TTYput(UNMETA(c));
171     }
172 #endif
173     else
174 	TTYput(c);
175 }
176 
177 STATIC void
TTYstring(char * p)178 TTYstring(char *p)
179 {
180     while (*p)
181 	TTYshow(*p++);
182 }
183 
184 STATIC UNSI
TTYget(void)185 TTYget(void)
186 {
187     char c;
188 
189     TTYflush();
190     if (Pushed) {
191 	Pushed = 0;
192 	return PushBack;
193     }
194     if (*Input)
195 	return *Input++;
196 #if defined(_OS2) || defined(__MSDOS__)
197     return getakey(&c) == 1 ? c : EOF;
198 #else
199     return read(0, &c, (size_t) 1) == 1 ? c : EOF;
200 #endif
201 }
202 
203 #define TTYback() ((backspace != NULL) ? TTYputs((char *)backspace) : TTYput('\b'))
204 
205 STATIC void
TTYbackn(int n)206 TTYbackn(int n)
207 {
208     while (--n >= 0)
209 	TTYback();
210 }
211 
212 #ifdef HAVE_LIBTERMCAP
213 static char attr_buf[1024];
214 #endif
215 
216 void
TTYinfo(void)217 TTYinfo(void)
218 {
219     static int init = FALSE;
220 
221 #if defined(HAVE_LIBTERMCAP)
222     char *tttmp, *stand_out, *stand_end;
223     const char *term;
224     static char ebuff[2048];	/* !!!!! */
225     char *bp;
226     const int old_row = get_ScrnRows();
227     const int old_col = get_ScrnCols();
228     int tmp_row = 0, tmp_col = 0;
229 #endif
230 
231     if (init)
232 	return;
233     init = TRUE;
234 #if defined(TIOCGWINSZ) && defined(SIGWINCH)
235     getwinders(0);
236 #endif
237 
238 #if defined(HAVE_LIBTERMCAP)
239     bp = attr_buf;
240     if ((term = getenv("TERM")) == NULL)
241 	term = "dumb";
242 
243     if (0 < tgetent(ebuff, term)) {
244 	tmp_row = tgetnum("li");
245 	tmp_col = tgetnum("co");
246 	blink_on = tgetstr("mb", &bp);
247 	rev_on = tgetstr("mr", &bp);
248 	clear_attr = tgetstr("me", &bp);
249 	bold_on = tgetstr("md", &bp);
250 	clear_scr = tgetstr("cl", &bp);
251 	home = tgetstr("ho", &bp);
252 	backspace = tgetstr("le", &bp);
253 	cur_right = tgetstr("nd", &bp);
254 	del_eol = tgetstr("ce", &bp);
255 	tttmp = tgetstr("pc", &bp);
256 	stand_out = tgetstr("so", &bp);
257 	stand_end = tgetstr("se", &bp);
258 	PC = tttmp ? *tttmp : 0;
259 	rev_off = clear_attr;
260 	if (rev_on == NULL && stand_out != NULL) {
261 	    rev_on = stand_out;
262 	    rev_off = stand_end;
263 	}
264     }
265 #ifdef TIOCGWINSZ
266     if (get_ScrnCols() < 1 || get_ScrnRows() < 1)	/* invalid call to getwinders() */
267 #endif
268     {
269 	set_ScrnCols((tmp_col < 2 ? old_col : tmp_col), ss_TTYinfo);
270 	set_ScrnRows((tmp_row < 2 ? old_row : tmp_row), ss_TTYinfo);
271     }
272 #endif
273 /* default behavior for everyone */
274     if (get_ScrnCols() < 1 || get_ScrnRows() < 1) {
275 	set_ScrnCols(SCREEN_COLS, ss_TTYinfo);
276 	set_ScrnRows(SCREEN_ROWS, ss_TTYinfo);
277     }
278 }
279 
280 /*
281    **  Print an array of words in columns.
282  */
283 static void
columns(int ac,char ** av)284 columns(int ac, char **av)
285 {
286     char *p;
287     int i;
288     int j;
289     int k;
290     int len;
291     int skip;
292     int longest;
293     int cols;
294 
295     /* Find longest name, determine column count from that. */
296     for (longest = 0, i = 0; i < ac; i++)
297 	if ((j = strlen((char *) av[i])) > longest)
298 	    longest = j;
299 #if 0
300     cols = TTYwidth / (longest + 3);
301 #endif
302     cols = get_ScrnCols() / (longest + 3);
303     TTYputs((char *) NEWLINE);
304     for (skip = ac / cols + 1, i = 0; i < skip; i++) {
305 	for (j = i; j < ac; j += skip) {
306 	    for (p = av[j], len = strlen((char *) p), k = len - 1; k >= 0; k--, p++)
307 		TTYput(*p);
308 	    if (j + skip < ac)
309 		while (++len < longest + 3)
310 		    TTYput(' ');
311 	}
312 	TTYputs((char *) NEWLINE);
313     }
314 }
315 
316 STATIC void
reposition(void)317 reposition(void)
318 {
319     int i;
320     char *p;
321 
322     TTYput('\r');
323     TTYputs(Prompt);
324     for (i = Point - 1, p = Line; i >= 0; i--, p++)
325 	TTYshow(*p);
326 }
327 
328 STATIC void
left(STATUS Change)329 left(STATUS Change)
330 {
331     TTYback();
332     if (Point) {
333 	if (ISCTL(Line[Point - 1]))
334 	    TTYback();
335 #ifdef NOMETA
336 	else if (rl_meta_chars && ISMETA(Line[Point - 1])) {
337 	    TTYback();
338 	    TTYback();
339 	}
340 #endif
341     }
342     if (Change == CSmove)
343 	Point--;
344 }
345 
346 STATIC void
right(STATUS Change)347 right(STATUS Change)
348 {
349     TTYshow(Line[Point]);
350     if (Change == CSmove)
351 	Point++;
352 }
353 
354 STATIC STATUS
ring_bell(void)355 ring_bell(void)
356 {
357 /* extern int silent ; */
358 
359     if (!silent) {
360 	TTYput('\07');
361 	TTYflush();
362     }
363     return CSstay;
364 }
365 
366 STATIC STATUS
do_macro(int c)367 do_macro(int c)
368 {
369     char name[4];
370 
371     name[0] = '_';
372     name[1] = (char) c;
373     name[2] = '_';
374     name[3] = '\0';
375 
376     if ((Input = (char *) getenv((char *) name)) == NULL) {
377 	Input = NilStr;
378 	return ring_bell();
379     }
380     return CSstay;
381 }
382 
383 STATIC STATUS
do_forward(STATUS move)384 do_forward(STATUS move)
385 {
386     int i;
387     char *p;
388 
389     i = 0;
390     do {
391 	p = &Line[Point];
392 	for (; Point < End && (*p == ' ' || !isalnum(*p)); Point++, p++)
393 	    if (move == CSmove)
394 		right(CSstay);
395 
396 	for (; Point < End && isalnum(*p); Point++, p++)
397 	    if (move == CSmove)
398 		right(CSstay);
399 
400 	if (Point == End)
401 	    break;
402     } while (++i < Repeat);
403 
404     return CSstay;
405 }
406 
407 STATIC STATUS
do_case(CASE type)408 do_case(CASE type)
409 {
410     int i;
411     int end;
412     int count;
413     char *p;
414 
415     (void) do_forward(CSstay);
416     if (OldPoint != Point) {
417 	if ((count = Point - OldPoint) < 0)
418 	    count = -count;
419 	Point = OldPoint;
420 	if ((end = Point + count) > End)
421 	    end = End;
422 	for (i = Point, p = &Line[i]; i < end; i++, p++) {
423 	    if (type == TOupper) {
424 		if (islower(*p))
425 		    *p = toupper(*p);
426 	    } else if (isupper(*p))
427 		*p = tolower(*p);
428 	    right(CSmove);
429 	}
430     }
431     return CSstay;
432 }
433 
434 STATIC STATUS
case_down_word(void)435 case_down_word(void)
436 {
437     return do_case(TOlower);
438 }
439 
440 STATIC STATUS
case_up_word(void)441 case_up_word(void)
442 {
443     return do_case(TOupper);
444 }
445 
446 STATIC void
ceol(void)447 ceol(void)
448 {
449     int extras;
450     int i;
451     char *p;
452 
453     for (extras = 0, i = Point, p = &Line[i]; i <= End; i++, p++) {
454 	TTYput(' ');
455 	if (ISCTL(*p)) {
456 	    TTYput(' ');
457 	    extras++;
458 	}
459 #ifdef NOMETA
460 	else if (rl_meta_chars && ISMETA(*p)) {
461 	    TTYput(' ');
462 	    TTYput(' ');
463 	    extras += 2;
464 	}
465 #endif
466     }
467 
468     for (i += extras; i > Point; i--)
469 	TTYback();
470 }
471 
472 STATIC void
clear_line(void)473 clear_line(void)
474 {
475     Point = (0 - strlen(Prompt));
476     TTYput('\r');
477     ceol();
478     Point = 0;
479     End = 0;
480     Line[0] = '\0';
481 }
482 
483 STATIC STATUS
insert_string(char * p)484 insert_string(char *p)
485 {
486     size_t len;
487     int i;
488     char *snew;
489     char *q;
490 
491     len = strlen((char *) p);
492     if (End + len >= Length) {
493 	if ((snew = (char *) malloc((Length + len + MEM_INC))) == NULL)
494 	    return CSstay;
495 	if (Length) {
496 	    COPYFROMTO(snew, Line, Length);
497 	    free(Line);
498 	}
499 	Line = snew;
500 	Length += len + MEM_INC;
501     }
502     for (q = &Line[Point], i = (End - Point) - 1; i >= 0; i--)
503 	q[len + i] = q[i];
504     COPYFROMTO(&Line[Point], p, len);
505     End += len;
506     Line[End] = '\0';
507     TTYstring(&Line[Point]);
508     Point += len;
509 
510     if (Point == End)
511 	return CSstay;
512     else
513 	return CSmove;
514 }
515 
516 
517 STATIC char *
next_hist(void)518 next_hist(void)
519 {
520     return H.Pos >= H.Size - 1 ? (char *) 0 : H.Lines[++H.Pos];
521 }
522 
523 STATIC char *
prev_hist(void)524 prev_hist(void)
525 {
526     return H.Pos == 0 ? (char *) 0 : H.Lines[--H.Pos];
527 }
528 
529 STATIC STATUS
do_insert_hist(char * p)530 do_insert_hist(char *p)
531 {
532     if (p == NULL)
533 	return ring_bell();
534     Point = 0;
535     reposition();
536     ceol();
537     End = 0;
538     return insert_string(p);
539 }
540 
541 STATIC STATUS
do_hist(char * (* move)(ALVOID))542 do_hist(char *(*move) (ALVOID))
543 {
544     char *p;
545     int i;
546 
547     i = 0;
548     do {
549 	if ((p = (*move) ()) == NULL)
550 	    return ring_bell();
551     } while (++i < Repeat);
552     return do_insert_hist(p);
553 }
554 
555 STATIC STATUS
h_next(void)556 h_next(void)
557 {
558     return do_hist(next_hist);
559 }
560 
561 STATIC STATUS
h_prev(void)562 h_prev(void)
563 {
564     return do_hist(prev_hist);
565 }
566 
567 STATIC STATUS
h_first(void)568 h_first(void)
569 {
570     return do_insert_hist(H.Lines[H.Pos = 0]);
571 }
572 
573 STATIC STATUS
h_last(void)574 h_last(void)
575 {
576     return do_insert_hist(H.Lines[H.Pos = H.Size - 1]);
577 }
578 
579 /*
580    **  Return zero if pat appears as a substring in text.
581  */
582 STATIC int
substrcmp(const char * text,const char * pat,size_t len)583 substrcmp(const char *text, const char *pat, size_t len)
584 {
585     char c;
586 
587     if ((c = *pat) == '\0')
588 	return *text == '\0';
589     for (; *text; text++)
590 	if ((char) *text == c && strncmp(text, pat, len) == 0)
591 	    return 0;
592     return 1;
593 }
594 
595 STATIC char *
search_hist(char * search,char * (* move)(ALVOID))596 search_hist(char *search, char *(*move) (ALVOID))
597 {
598     static char *old_search = NULL;
599     size_t len;
600     int pos;
601 #ifdef no_proto
602     int (*match) ();
603 #else
604     int (*match) (const char *, const char *, size_t);
605 #endif
606     char *pat;
607 
608     /* Save or get remembered search pattern. */
609     if (search && *search) {
610 	if (old_search)
611 	    free(old_search);
612 	old_search = (char *) strdup(search);
613     } else {
614 	if (old_search == NULL || *old_search == '\0')
615 	    return NULL;
616 	search = old_search;
617     }
618 
619     /* Set up pattern-finder. */
620     if (*search == '^') {
621 	match = strncmp;
622 	pat = (char *) (search + 1);
623     } else {
624 	match = substrcmp;
625 	pat = (char *) search;
626     }
627     len = strlen(pat);
628 
629     for (pos = H.Pos; (*move) () != NULL;)
630 	if ((*match) ((char *) H.Lines[H.Pos], pat, len) == 0)
631 	    return H.Lines[H.Pos];
632     H.Pos = pos;
633     return NULL;
634 }
635 
636 STATIC STATUS
h_search(void)637 h_search(void)
638 {
639     static int Searching = FALSE;
640     const char *old_prompt;
641     char *(*move) (ALVOID);
642     char *p;
643 
644     if (Searching)
645 	return ring_bell();
646     Searching = TRUE;
647 
648     clear_line();
649     old_prompt = Prompt;
650     Prompt = "Search: ";
651     TTYputs(Prompt);
652 #ifdef no_proto
653     move = Repeat == NO_ARG ? prev_hist : next_hist;
654 #else
655     move = Repeat == NO_ARG ? (char *(*)(void)) prev_hist : (char *(*)(void)) next_hist;
656 #endif
657     p = search_hist(editinput(), move);
658     clear_line();
659     Prompt = old_prompt;
660     TTYputs(Prompt);
661 
662     Searching = 0;
663     return do_insert_hist(p);
664 }
665 
666 STATIC STATUS
fd_char(void)667 fd_char(void)
668 {
669     int i;
670 
671     i = 0;
672     do {
673 	if (Point >= End)
674 	    break;
675 	right(CSmove);
676     } while (++i < Repeat);
677     return CSstay;
678 }
679 
680 STATIC void
save_yank(int begin,int i)681 save_yank(int begin, int i)
682 {
683     if (Yanked) {
684 	free(Yanked);
685 	Yanked = NULL;
686     }
687     if (i < 1)
688 	return;
689 
690     if ((Yanked = (char *) malloc((size_t) (i + 1))) != NULL) {
691 	COPYFROMTO(Yanked, &Line[begin], (size_t) i);
692 	Yanked[i] = '\0';
693     }
694 }
695 
696 STATIC STATUS
delete_string(int count)697 delete_string(int count)
698 {
699     int i;
700     char *p;
701 
702     if (count <= 0 || End == Point)
703 	return ring_bell();
704 
705     if (count == 1 && Point == End - 1) {
706 	/* Optimize common case of delete at end of line. */
707 	End--;
708 	p = &Line[Point];
709 	i = 1;
710 	TTYput(' ');
711 	if (ISCTL(*p)) {
712 	    i = 2;
713 	    TTYput(' ');
714 	}
715 #ifdef NOMETA
716 	else if (rl_meta_chars && ISMETA(*p)) {
717 	    i = 3;
718 	    TTYput(' ');
719 	    TTYput(' ');
720 	}
721 #endif
722 	TTYbackn(i);
723 	*p = '\0';
724 	return CSmove;
725     }
726     if (Point + count > End && (count = End - Point) <= 0)
727 	return CSstay;
728 
729     if (count > 1)
730 	save_yank(Point, count);
731 
732     for (p = &Line[Point], i = End - (Point + count); i >= 0; i--, p++)
733 	p[0] = p[count];
734     ceol();
735     End -= count;
736     TTYstring(&Line[Point]);
737     return CSmove;
738 }
739 
740 STATIC STATUS
bk_char(void)741 bk_char(void)
742 {
743     int i;
744 
745     i = 0;
746     do {
747 	if (Point == 0)
748 	    break;
749 	left(CSmove);
750     } while (++i < Repeat);
751 
752     return CSstay;
753 }
754 
755 STATIC STATUS
bk_del_char(void)756 bk_del_char(void)
757 {
758     int i;
759 
760     i = 0;
761     do {
762 	if (Point == 0)
763 	    break;
764 	left(CSmove);
765     } while (++i < Repeat);
766 
767     return delete_string(i);
768 }
769 
770 STATIC STATUS
del_char(void)771 del_char(void)
772 {
773     return delete_string(Repeat == NO_ARG ? 1 : Repeat);
774 }
775 
776 STATIC STATUS
redisplay(void)777 redisplay(void)
778 {
779     TTYputs((char *) NEWLINE);
780     TTYputs(Prompt);
781     TTYstring(Line);
782     return CSmove;
783 }
784 
785 STATIC STATUS
kill_line(void)786 kill_line(void)
787 {
788     int i;
789 
790     if (Repeat != NO_ARG) {
791 	if (Repeat < Point) {
792 	    i = Point;
793 	    Point = Repeat;
794 	    reposition();
795 	    (void) delete_string(i - Point);
796 	} else if (Repeat > Point) {
797 	    right(CSmove);
798 	    (void) delete_string(Repeat - Point - 1);
799 	}
800 	return CSmove;
801     }
802     save_yank(Point, End - Point);
803     Line[Point] = '\0';
804     ceol();
805     End = Point;
806     return CSstay;
807 }
808 
809 STATIC STATUS
insert_char(int c)810 insert_char(int c)
811 {
812     STATUS s;
813     static char buff[2];
814     char *p;
815     char *q;
816     int i;
817 
818     if (Repeat == NO_ARG || Repeat < 2) {
819 	buff[0] = (char) c;
820 	buff[1] = '\0';
821 	return insert_string(buff);
822     }
823     if ((p = (char *) malloc((size_t) (Repeat + 1))) == NULL)
824 	return CSstay;
825     for (i = Repeat - 1, q = p; i >= 0; i--)
826 	*q++ = (char) c;
827     *q = '\0';
828     Repeat = 0;
829     s = insert_string(p);
830     free(p);
831     return s;
832 }
833 
834 STATIC STATUS
meta(void)835 meta(void)
836 {
837     UNSI c;
838     KEYMAP *kp;
839 
840     if ((c = TTYget()) == EOF)
841 	return CSeof;
842 #if     defined(ANSI_ARROWS)
843     /* Also include VT-100 arrows. */
844     if (c == '[' || c == 'O')
845 	switch (c = TTYget()) {
846 	default:
847 	    return ring_bell();
848 	case EOF:
849 	    return CSeof;
850 	case KUP:
851 	    return h_prev();	/* ansi arrow keys */
852 	case KDN:
853 	    return h_next();
854 	case KRT:
855 	    return fd_char();
856 	case KLT:
857 	    return bk_char();
858 	case KCE:
859 	    strcpy((char *) Line, "N");		/* center of keypad */
860 	    return CSdone;
861 	case KF1:
862 	    strcpy((char *) Line, "help");	/* vt100 function keys f1 */
863 	    return CSdone;
864 	case KF2:
865 	    strcpy((char *) Line, "tag help");	/* f2 */
866 	    return CSdone;
867 	case KF3:
868 	    strcpy((char *) Line, "tag list");	/* f3 */
869 	    return CSdone;
870 	case KF4:
871 	    strcpy((char *) Line, "qlist");	/* f4 */
872 	    return CSdone;
873 	case KF5:
874 	    strcpy((char *) Line, "show terms");	/* f5 */
875 	    return CSdone;
876 	case KF0:
877 	    strcpy((char *) Line, "next");	/* f10 */
878 	    return CSdone;
879 #ifndef SYS_UNIX  /* non-unix */
880 	case KPU:
881 	    strcpy((char *) Line, "-");		/* page up */
882 	    return CSdone;
883 	case KPD:
884 	    strcpy((char *) Line, "+");		/* page down */
885 	    return CSdone;
886 	case KHM:
887 	    strcpy((char *) Line, "1");		/* home */
888 	    return CSdone;
889 	case KEN:
890 	    strcpy((char *) Line, "last");	/* end  */
891 	    return CSdone;
892 	case KIN:
893 	    return ring_bell();
894 	case KDL:
895 	    return del_char();
896 #else	/* linux, ibcs2, some other unixes */
897 	case '2':
898 	    if ((c = TTYget()) != '1')
899 		break;
900 	    if ((c = TTYget()) != '~')
901 		break;
902 	    strcpy((char *) Line, "next");	/* f10 */
903 	    return CSdone;
904 	case '3':
905 	    if ((c = TTYget()) != '\176')	/* delete  */
906 		break;
907 	    return del_char();
908 	case '5':
909 	    if ((c = TTYget()) != '\176')	/* page up */
910 		break;
911 	    strcpy(Line, "-");
912 	    return CSdone;
913 	case '6':
914 	    if ((c = TTYget()) != '\176')	/* page down */
915 		break;
916 	    strcpy(Line, "+");
917 	    return CSdone;
918 	case '1':
919 	    if ((c = TTYget()) != '\176')	/* home */
920 		break;
921 	    strcpy(Line, "1");
922 	    return CSdone;
923 	case '4':
924 	    if ((c = TTYget()) != '\176')	/* end */
925 		break;
926 	    strcpy(Line, "last");
927 	    return CSdone;
928 	case '[':
929 	    switch (c = TTYget()) {	/* ansi function keys */
930 	    case 'A':
931 		strcpy(Line, "help");	/* f1 */
932 		return CSdone;
933 	    case 'B':
934 		strcpy(Line, "tag help");	/* f2 */
935 		return CSdone;
936 	    case 'C':
937 		strcpy(Line, "tag list");	/* f3 */
938 		return CSdone;
939 	    case 'D':
940 		strcpy(Line, "qlist");	/* f4 */
941 		return CSdone;
942 	    case 'E':
943 		strcpy(Line, "show terms");	/* f5 */
944 		return CSdone;
945 	    case 'J':
946 		strcpy(Line, "next");	/* f10 */
947 		return CSdone;
948 	    }
949 #endif
950 	}
951 #endif				/* defined(ANSI_ARROWS) */
952 
953     if (isdigit(c)) {
954 	for (Repeat = c - '0'; (c = TTYget()) != EOF && isdigit(c);)
955 	    Repeat = Repeat * 10 + c - '0';
956 	Pushed = 1;
957 	PushBack = c;
958 	return CSstay;
959     }
960     if (isupper(c))
961 	return do_macro(c);
962     for (OldPoint = Point, kp = MetaMap; kp->Func; kp++)
963 	if (kp->Key == (char) c)
964 	    return (*kp->Func) ();
965 
966     return ring_bell();
967 }
968 
969 STATIC STATUS
emacs(int c)970 emacs(int c)
971 {
972     STATUS s;
973     KEYMAP *kp;
974 #ifdef NOMETA
975     if (ISMETA(c)) {
976 	Pushed = 1;
977 	PushBack = UNMETA(c);
978 	return meta();
979     }
980 #endif
981     for (kp = Map; kp->Func; kp++)
982 	if (kp->Key == (char) c)
983 	    break;
984     s = kp->Func ? (*kp->Func) () : insert_char(c);
985     if (!Pushed)
986 	/* No pushback means no repeat count; hacky, but true. */
987 	Repeat = NO_ARG;
988     return s;
989 }
990 
991 STATIC STATUS
TTYspecial(int c)992 TTYspecial(int c)
993 {
994 #ifdef NOMETA
995     if (ISMETA(c))
996 	return CSdispatch;
997 #endif
998     if (c == rl_erase || c == DEL)
999 	return bk_del_char();
1000     if (c == rl_kill) {
1001 	if (Point != 0) {
1002 	    Point = 0;
1003 	    reposition();
1004 	}
1005 	Repeat = NO_ARG;
1006 	return kill_line();
1007     }
1008     if (c == rl_intr || c == rl_quit) {
1009 	Point = End = 0;
1010 	Line[0] = '\0';
1011 	return redisplay();
1012     }
1013     if (c == rl_eof && Point == 0 && End == 0)
1014 	return CSeof;
1015 
1016     return CSdispatch;
1017 }
1018 
1019 STATIC char *
editinput(void)1020 editinput(void)
1021 {
1022     /* extern const char *luxptr ; */
1023     UNSI c;
1024 
1025     Repeat = NO_ARG;
1026     OldPoint = Point = Mark = End = 0;
1027     Line[0] = '\0';
1028     if (luxptr != NULL) {	/* pre-load edit buffer with text */
1029 	strcpy((char *) Line, luxptr);
1030 	End = strlen((char *) Line);
1031 	Point = End;
1032 	reposition();
1033 	Point = 0;
1034 	reposition();
1035     }
1036     while ((c = TTYget()) != EOF)
1037 	switch (TTYspecial(c)) {
1038 	case CSdone:
1039 	    return Line;
1040 	case CSeof:
1041 	    return NULL;
1042 	case CSmove:
1043 	    reposition();
1044 	    break;
1045 	case CSdispatch:
1046 	    switch (emacs(c)) {
1047 	    case CSdone:
1048 		return Line;
1049 	    case CSeof:
1050 		return NULL;
1051 	    case CSmove:
1052 		reposition();
1053 		break;
1054 	    case CSdispatch:
1055 	    case CSstay:
1056 		break;
1057 	    }
1058 	    break;
1059 	case CSstay:
1060 	    break;
1061 	}
1062     return NULL;
1063 }
1064 
1065 STATIC void
hist_add(const char * p)1066 hist_add(const char *p)
1067 {
1068     int i;
1069     char *tpr;
1070 
1071     if ((tpr = strdup(p)) == NULL)
1072 	return;
1073     if (H.Size < HIST_SIZE)
1074 	H.Lines[H.Size++] = tpr;
1075     else {
1076 	free(H.Lines[0]);
1077 	for (i = 0; i < HIST_SIZE - 1; i++)
1078 	    H.Lines[i] = H.Lines[i + 1];
1079 	H.Lines[i] = tpr;
1080     }
1081     H.Pos = H.Size - 1;
1082 }
1083 
1084 /*
1085    **  For compatibility with FSF readline.
1086  */
1087 #if 0
1088 /* ARGSUSED0 */
1089 void
1090 rl_reset_terminal(char *p)
1091 {
1092 }
1093 
1094 #endif
1095 
1096 char *
readline(const char * prompt,scroll_command_t scrollflag)1097 readline(const char *prompt, scroll_command_t scrollflag)
1098 {
1099     char *line;
1100 
1101     if (Line == NULL) {
1102 	Length = MEM_INC;
1103 	if ((Line = (char *) malloc(Length)) == NULL)
1104 	    return NULL;
1105     }
1106     TTYinfo();
1107     rl_ttyset(0);
1108     hist_add(NilStr);
1109     ScreenSize = SCREEN_INC;
1110     Screen = (char *) malloc(ScreenSize);
1111     if (prompt != NULL)
1112 	Prompt = prompt;
1113     else
1114 	Prompt = (char *) NilStr;
1115     /*   Prompt = ((prompt != NULL) ? prompt : (char *) NilStr ) ; */
1116     TTYputs(Prompt);
1117     line = editinput();
1118     if (line != NULL) {
1119 	line = (char *) strdup(line);	/*???? */
1120 	if (scrollflag == do_scroll)
1121 	    TTYputs((char *) NEWLINE);
1122 	else if (scrollflag == no_scroll)
1123 	    TTYputs("\r");
1124 #ifdef ATPDBG
1125 	else
1126 	    assert(scrollflag == no_scroll || scrollflag == do_scroll);
1127 #endif
1128 	TTYflush();
1129     }
1130     rl_ttyset(1);
1131     free(Screen);
1132     free(H.Lines[--H.Size]);
1133     return (char *) line;
1134 }
1135 
1136 void
add_history(const char * p)1137 add_history(const char *p)
1138 {
1139     if (p == NULL || *p == '\0')
1140 	return;
1141 
1142 #if     defined(UNIQUE_HISTORY)
1143     if (H.Pos && strcmp(p, (char *) (H.Lines[H.Pos - 1])) == 0)
1144 	return;
1145 #endif				/* defined(UNIQUE_HISTORY) */
1146     hist_add( /* (char *) */ p);
1147 }
1148 
1149 
1150 STATIC STATUS
beg_line(void)1151 beg_line(void)
1152 {
1153     if (Point) {
1154 	Point = 0;
1155 	return CSmove;
1156     }
1157     return CSstay;
1158 }
1159 
1160 STATIC STATUS
end_line(void)1161 end_line(void)
1162 {
1163     if (Point != End) {
1164 	Point = End;
1165 	return CSmove;
1166     }
1167     return CSstay;
1168 }
1169 
1170 /*
1171    **  Move back to the beginning of the current word and return an
1172    **  allocated copy of it.
1173  */
1174 STATIC char *
find_word(void)1175 find_word(void)
1176 {
1177     static char SEPS[] = "#;&|^$=`'{}()<>\n\t ";
1178     char *p;
1179     char *mnew;
1180     size_t len;
1181 
1182     for (p = &Line[Point]; p > Line && strchr(SEPS, (char) p[-1]) == NULL; p--)
1183 	continue;
1184     len = (Point - (p - Line)) + 1;
1185     if ((mnew = (char *) malloc((len + 3))) == NULL)	/* we add 3 for wild cards used by ms-dos */
1186 	return NULL;
1187     COPYFROMTO(mnew, p, len);
1188     mnew[len - 1] = '\0';
1189     return mnew;
1190 }
1191 
1192 STATIC STATUS
c_complete(void)1193 c_complete(void)
1194 {
1195     char *p;
1196     char *word;
1197     int unique;
1198     STATUS s;
1199 
1200     word = find_word();
1201     p = (char *) rl_complete((char *) word, &unique);
1202     if (word)
1203 	free(word);
1204     if (p && *p) {
1205 	s = insert_string(p);
1206 	if (!unique)
1207 	    (void) ring_bell();
1208 	free(p);
1209 	return s;
1210     }
1211     return ring_bell();
1212 }
1213 
1214 STATIC STATUS
c_possible(void)1215 c_possible(void)
1216 {
1217     char **av;
1218     char *word;
1219     int ac;
1220 
1221     word = find_word();
1222     ac = rl_list_possib((char *) word, (char ***) &av);
1223     if (word)
1224 	free(word);
1225     if (ac) {
1226 	columns(ac, av);
1227 	while (--ac >= 0)
1228 	    free(av[ac]);
1229 	free(av);
1230 	return CSmove;
1231     }
1232     return ring_bell();
1233 }
1234 
1235 STATIC STATUS
accept_line(void)1236 accept_line(void)
1237 {
1238     Line[End] = '\0';
1239     return CSdone;
1240 }
1241 
1242 STATIC STATUS
transpose(void)1243 transpose(void)
1244 {
1245     char c;
1246 
1247     if (Point) {
1248 	if (Point == End)
1249 	    left(CSmove);
1250 	c = Line[Point - 1];
1251 	left(CSstay);
1252 	Line[Point - 1] = Line[Point];
1253 	TTYshow(Line[Point - 1]);
1254 	Line[Point++] = c;
1255 	TTYshow(c);
1256     }
1257     return CSstay;
1258 }
1259 
1260 STATIC STATUS
quote(void)1261 quote(void)
1262 {
1263     UNSI c;
1264 
1265     c = TTYget();
1266 
1267     if (c == EOF)
1268 	return CSeof;
1269     else
1270 	return insert_char((int) c);
1271 }
1272 
1273 STATIC STATUS
wipe(void)1274 wipe(void)
1275 {
1276     int i;
1277 
1278     if (Mark > End)
1279 	return ring_bell();
1280 
1281     if (Point > Mark) {
1282 	i = Point;
1283 	Point = Mark;
1284 	Mark = i;
1285 	reposition();
1286     }
1287     return delete_string(Mark - Point);
1288 }
1289 
1290 STATIC STATUS
mk_set(void)1291 mk_set(void)
1292 {
1293     Mark = Point;
1294     return CSstay;
1295 }
1296 
1297 STATIC STATUS
exchange(void)1298 exchange(void)
1299 {
1300     UNSI c;
1301 
1302     if ((c = TTYget()) != CTL('X')) {
1303 	if (c == EOF)
1304 	    return CSeof;
1305 	else
1306 	    return ring_bell();
1307     }
1308     if ((c = Mark) <= End) {
1309 	Mark = Point;
1310 	Point = c;
1311 	return CSmove;
1312     }
1313     return CSstay;
1314 }
1315 
1316 STATIC STATUS
yank(void)1317 yank(void)
1318 {
1319     if (Yanked && *Yanked)
1320 	return insert_string(Yanked);
1321     return CSstay;
1322 }
1323 
1324 STATIC STATUS
copy_region(void)1325 copy_region(void)
1326 {
1327     if (Mark > End)
1328 	return ring_bell();
1329 
1330     if (Point > Mark)
1331 	save_yank(Mark, Point - Mark);
1332     else
1333 	save_yank(Point, Mark - Point);
1334 
1335     return CSstay;
1336 }
1337 
1338 STATIC STATUS
move_to_char(void)1339 move_to_char(void)
1340 {
1341     UNSI c;
1342     int i;
1343     char *p;
1344 
1345     if ((c = TTYget()) == EOF)
1346 	return CSeof;
1347     for (i = Point + 1, p = &Line[i]; i < End; i++, p++)
1348 	if (*p == (char) c) {
1349 	    Point = i;
1350 	    return CSmove;
1351 	}
1352     return CSstay;
1353 }
1354 
1355 STATIC STATUS
fd_word(void)1356 fd_word(void)
1357 {
1358     return do_forward(CSmove);
1359 }
1360 
1361 STATIC STATUS
fd_kill_word(void)1362 fd_kill_word(void)
1363 {
1364     int i;
1365 
1366     (void) do_forward(CSstay);
1367     if (OldPoint != Point) {
1368 	i = Point - OldPoint;
1369 	Point = OldPoint;
1370 	return delete_string(i);
1371     }
1372     return CSstay;
1373 }
1374 
1375 STATIC STATUS
bk_word(void)1376 bk_word(void)
1377 {
1378     int i;
1379     char *p;
1380 
1381     i = 0;
1382     do {
1383 	for (p = &Line[Point]; p > Line && !isalnum(p[-1]); p--)
1384 	    left(CSmove);
1385 
1386 	for (; p > Line && p[-1] != ' ' && isalnum(p[-1]); p--)
1387 	    left(CSmove);
1388 
1389 	if (Point == 0)
1390 	    break;
1391     } while (++i < Repeat);
1392 
1393     return CSstay;
1394 }
1395 
1396 STATIC STATUS
bk_kill_word(void)1397 bk_kill_word(void)
1398 {
1399     (void) bk_word();
1400     if (OldPoint != Point)
1401 	return delete_string(OldPoint - Point);
1402     return CSstay;
1403 }
1404 
1405 STATIC int
argify(char * line,char *** avp)1406 argify(char *line, char ***avp)
1407 {
1408     char *c;
1409     char **p;
1410     char **snew;
1411     int ac;
1412     int i;
1413 
1414     i = MEM_INC;
1415     /* if ((*avp = p = NEW(char*, i))== NULL) */
1416     if ((*avp = p = (char **) malloc((i * sizeof(c)))) == NULL)
1417 	return 0;
1418 
1419     for (c = line; isspace(*c); c++)
1420 	continue;
1421     if (*c == '\n' || *c == '\0')
1422 	return 0;
1423 
1424     for (ac = 0, p[ac++] = c; *c && *c != '\n';) {
1425 	if (isspace(*c)) {
1426 	    *c++ = '\0';
1427 	    if (*c && *c != '\n') {
1428 		if (ac + 1 == i) {
1429 		    /* snew = NEW(char*, i + MEM_INC); */
1430 		    snew = (char **) malloc((i + MEM_INC) * sizeof(c));
1431 		    if (snew == NULL) {
1432 			p[ac] = NULL;
1433 			return ac;
1434 		    }
1435 		    COPYFROMTO(snew, p, i * sizeof(char **));
1436 		    i += MEM_INC;
1437 		    free(p);
1438 		    *avp = p = snew;
1439 		}
1440 		p[ac++] = c;
1441 	    }
1442 	} else
1443 	    c++;
1444     }
1445     *c = '\0';
1446     p[ac] = NULL;
1447     return ac;
1448 }
1449 
1450 STATIC STATUS
last_argument(void)1451 last_argument(void)
1452 {
1453     char **av;
1454     char *p;
1455     STATUS s;
1456     int ac;
1457 
1458     if (H.Size == 1)
1459 	return ring_bell();
1460 
1461     p = H.Lines[H.Size - 2];
1462     if (p == NULL)
1463 	return ring_bell();
1464 
1465     if ((p = (char *) strdup((char *) p)) == NULL)
1466 	return CSstay;
1467     ac = argify(p, &av);
1468 
1469     if (Repeat != NO_ARG)
1470 	s = Repeat < ac ? insert_string(av[Repeat]) : ring_bell();
1471     else
1472 	s = ac ? insert_string(av[ac - 1]) : CSstay;
1473 
1474     if (ac)
1475 	free(av);
1476     free(p);
1477     return s;
1478 }
1479 
1480 /*
1481 
1482  * getakey() is primarily for reading the keyboard on non-unix systems
1483  * that don't understand termios or sgtty for setting raw key strokes mode.
1484  * Additionally, getakey() gets the raw keycode and builds the ANSI escape
1485  * sequences for special keys such as the arrow keys.
1486  *
1487  */
1488 
1489 #if defined(_OS2) || defined(__MSDOS__)
1490 
1491 STATIC int
getakey(char * chr)1492 getakey(char *chr)
1493 {
1494 
1495     static int pushed = 0;
1496     static char c = 0;
1497     int t;
1498 
1499     if (pushed > 1) {
1500 	pushed--;
1501 	*chr = '[';
1502 	return 1;
1503     }
1504     if (pushed) {
1505 	pushed = 0;
1506 	*chr = c;
1507 	return 1;
1508     }
1509 #if defined(DJGPP)
1510     t = getkey();
1511     if (t < 256) {
1512 	*chr = (char) t;
1513 	return 1;
1514     }
1515     t &= 0xFF;			/* mask out high bits */
1516 #else
1517 #ifndef __EMX__
1518     while (!kbhit())
1519 	A_DVPAUZ;
1520 #endif
1521     t = getch();
1522     if (t) {
1523 	*chr = (char) t;
1524 	return 1;
1525     }
1526     /* else extended character */
1527     t = getch();
1528 #endif
1529 
1530     switch (t) {
1531     case 0x3b:
1532 	c = KF1;
1533 	break;
1534     case 0x3c:
1535 	c = KF2;
1536 	break;
1537     case 0x3d:
1538 	c = KF3;
1539 	break;
1540     case 0x3e:
1541 	c = KF4;
1542 	break;
1543     case 0x3f:
1544 	c = KF5;
1545 	break;
1546     case 0x40:
1547 	c = KF6;
1548 	break;
1549     case 0x41:
1550 	c = KF7;
1551 	break;
1552     case 0x42:
1553 	c = KF8;
1554 	break;
1555     case 0x43:
1556 	c = KF9;
1557 	break;
1558     case 0x44:
1559 	c = KF0;
1560 	break;
1561     case 0x47:
1562 	c = KHM;
1563 	break;
1564     case 0x48:
1565 	c = KUP;
1566 	break;
1567     case 0x49:
1568 	c = KPU;
1569 	break;
1570     case 0x4b:
1571 	c = KLT;
1572 	break;
1573     case 0x4c:
1574 	c = KCE;
1575 	break;
1576     case 0x4d:
1577 	c = KRT;
1578 	break;
1579     case 0x4f:
1580 	c = KEN;
1581 	break;
1582     case 0x50:
1583 	c = KDN;
1584 	break;
1585     case 0x51:
1586 	c = KPD;
1587 	break;
1588     case 0x52:
1589 	c = KIN;
1590 	break;
1591     case 0x53:
1592 	c = KDL;
1593 	break;
1594     default:
1595 	c = 0;
1596     }
1597     if (c) {
1598 	pushed = 2;
1599 	*chr = ESC;
1600 	return 1;
1601     } else
1602 	return 0;
1603 }
1604 #endif
1605 
1606 void
rl_initialize(void)1607 rl_initialize(void)
1608 {
1609     MetaMap[0].Key = CTL('H');
1610     MetaMap[0].Func = bk_kill_word;
1611     MetaMap[1].Key = DEL;
1612     MetaMap[1].Func = bk_kill_word;
1613     MetaMap[2].Key = ' ';
1614     MetaMap[2].Func = mk_set;
1615     MetaMap[3].Key = '.';
1616     MetaMap[3].Func = last_argument;
1617     MetaMap[4].Key = '<';
1618     MetaMap[4].Func = h_first;
1619     MetaMap[5].Key = '>';
1620     MetaMap[5].Func = h_last;
1621     MetaMap[6].Key = '?';
1622     MetaMap[6].Func = c_possible;
1623     MetaMap[7].Key = 'b';
1624     MetaMap[7].Func = bk_word;
1625     MetaMap[8].Key = 'd';
1626     MetaMap[8].Func = fd_kill_word;
1627     MetaMap[9].Key = 'f';
1628     MetaMap[9].Func = fd_word;
1629     MetaMap[10].Key = 'l';
1630     MetaMap[10].Func = case_down_word;
1631     MetaMap[11].Key = 'u';
1632     MetaMap[11].Func = case_up_word;
1633     MetaMap[12].Key = 'y';
1634     MetaMap[12].Func = yank;
1635     MetaMap[13].Key = 'w';
1636     MetaMap[13].Func = copy_region;
1637     MetaMap[14].Key = '\0';
1638     MetaMap[14].Func = 0; /* null pointer */
1639 
1640     Map[0].Key = CTL('@');
1641     Map[0].Func = ring_bell;
1642     Map[1].Key = CTL('A');
1643     Map[1].Func = beg_line;
1644     Map[2].Key = CTL('B');
1645     Map[2].Func = bk_char;
1646     Map[3].Key = CTL('D');
1647     Map[3].Func = del_char;
1648     Map[4].Key = CTL('E');
1649     Map[4].Func = end_line;
1650     Map[5].Key = CTL('F');
1651     Map[5].Func = fd_char;
1652     Map[6].Key = CTL('G');
1653     Map[6].Func = ring_bell;
1654     Map[7].Key = CTL('H');
1655     Map[7].Func = bk_del_char;
1656     Map[8].Key = CTL('I');
1657     Map[8].Func = c_complete;
1658     Map[9].Key = CTL('J');
1659     Map[9].Func = accept_line;
1660     Map[10].Key = CTL('K');
1661     Map[10].Func = kill_line;
1662     Map[11].Key = CTL('L');
1663     Map[11].Func = redisplay;
1664     Map[12].Key = CTL('M');
1665     Map[12].Func = accept_line;
1666     Map[13].Key = CTL('N');
1667     Map[13].Func = h_next;
1668     Map[14].Key = CTL('O');
1669     Map[14].Func = ring_bell;
1670     Map[15].Key = CTL('P');
1671     Map[15].Func = h_prev;
1672     Map[16].Key = CTL('Q');
1673     Map[16].Func = ring_bell;
1674     Map[17].Key = CTL('R');
1675     Map[17].Func = h_search;
1676     Map[18].Key = CTL('S');
1677     Map[18].Func = ring_bell;
1678     Map[19].Key = CTL('T');
1679     Map[19].Func = transpose;
1680     Map[20].Key = CTL('U');
1681     Map[20].Func = ring_bell;
1682     Map[21].Key = CTL('V');
1683     Map[21].Func = quote;
1684     Map[22].Key = CTL('W');
1685     Map[22].Func = wipe;
1686     Map[23].Key = CTL('X');
1687     Map[23].Func = exchange;
1688     Map[24].Key = CTL('Y');
1689     Map[24].Func = yank;
1690     Map[25].Key = CTL('Z');
1691     Map[25].Func = ring_bell;
1692     Map[26].Key = CTL('[');
1693     Map[26].Func = meta;
1694     Map[27].Key = CTL(']');
1695     Map[27].Func = move_to_char;
1696     Map[28].Key = CTL('^');
1697     Map[28].Func = ring_bell;
1698     Map[29].Key = CTL('_');
1699     Map[29].Func = ring_bell;
1700     Map[30].Key = '\0';
1701     Map[30].Func = 0;  /* null pointer */
1702 }
1703 
1704 
1705 /* call this before exit */
1706 void
rl_cleanup()1707 rl_cleanup()
1708 {
1709     int i = 0;
1710 
1711     free(Line);
1712     while (i < H.Size) {
1713 	free(H.Lines[i]);
1714 	i++;
1715     }
1716     if (Yanked)
1717 	free(Yanked);
1718 }
1719 
1720 
1721 #if !defined(_OS2) && !defined(__MSDOS__)
1722 void
rl_set_cntrl_char(int cquit,int cerase,int ceof,int cintr,int ckill)1723 rl_set_cntrl_char(int cquit, int cerase, int ceof, int cintr, int ckill)
1724 {
1725     rl_quit = cquit;
1726     rl_erase = cerase;
1727     rl_eof = ceof;
1728     rl_intr = cintr;
1729     rl_kill = ckill;
1730 }
1731 #endif
1732 
1733