1 /* GNUPLOT - readline.c */
2
3 /*[
4 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
5 *
6 * Permission to use, copy, and distribute this software and its
7 * documentation for any purpose with or without fee is hereby granted,
8 * provided that the above copyright notice appear in all copies and
9 * that both that copyright notice and this permission notice appear
10 * in supporting documentation.
11 *
12 * Permission to modify the software is granted, but not the right to
13 * distribute the complete modified source code. Modifications are to
14 * be distributed as patches to the released version. Permission to
15 * distribute binaries produced by compiling modified sources is granted,
16 * provided you
17 * 1. distribute the corresponding source modifications from the
18 * released version in the form of a patch file along with the binaries,
19 * 2. add special version identification to distinguish your version
20 * in addition to the base release version number,
21 * 3. provide your name and address as the primary contact for the
22 * support of your modified version, and
23 * 4. retain our contact information in regard to use of the base
24 * software.
25 * Permission to distribute the released version of the source code along
26 * with corresponding source modifications in the form of a patch file is
27 * granted with same provisions 2 through 4 for binary distributions.
28 *
29 * This software is provided "as is" without express or implied warranty
30 * to the extent permitted by applicable law.
31 ]*/
32
33
34 /*
35 * AUTHORS
36 *
37 * Original Software:
38 * Tom Tkacik
39 *
40 * Msdos port and some enhancements:
41 * Gershon Elber and many others.
42 *
43 * Adapted to work with UTF-8 enconding.
44 * Ethan A Merritt April 2011
45 */
46
47 #include <signal.h>
48
49 #include "stdfn.h"
50 #include "readline.h"
51
52 #include "alloc.h"
53 #include "gp_hist.h"
54 #include "plot.h"
55 #include "util.h"
56 #include "term_api.h"
57 #ifdef HAVE_WCHAR_H
58 #include <wchar.h>
59 #endif
60 #ifdef WGP_CONSOLE
61 #include "win/winmain.h"
62 #endif
63
64 /*
65 * adaptor routine for gnu libreadline
66 * to allow multiplexing terminal and mouse input
67 */
68 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
69 int
getc_wrapper(FILE * fp)70 getc_wrapper(FILE* fp)
71 {
72 int c;
73
74 while (1) {
75 errno = 0;
76 #ifdef USE_MOUSE
77 if (term && term->waitforinput && interactive) {
78 c = term->waitforinput(0);
79 }
80 else
81 #endif
82 #if defined(WGP_CONSOLE)
83 c = ConsoleGetch();
84 #else
85 if (fp)
86 c = getc(fp);
87 else
88 c = getchar(); /* HAVE_LIBEDITLINE */
89 if (c == EOF && errno == EINTR)
90 continue;
91 #endif
92 return c;
93 }
94 }
95 #endif /* HAVE_LIBREADLINE || HAVE_LIBEDITLINE */
96
97 #if defined(HAVE_LIBREADLINE) && defined(HAVE_READLINE_SIGNAL_HANDLER)
98 /*
99 * The signal handler of libreadline sets a flag when SIGTSTP is received
100 * but does not suspend until this flag is checked by other library
101 * routines. Since gnuplot's term->waitforinput() + getc_wrapper()
102 * replace these other routines, we must do the test and suspend ourselves.
103 */
104 void
wrap_readline_signal_handler()105 wrap_readline_signal_handler()
106 {
107 int sig;
108
109 /* FIXME: At the moment, there is no portable way to invoke the
110 signal handler. */
111 extern void _rl_signal_handler(int);
112
113 # ifdef HAVE_READLINE_PENDING_SIGNAL
114 sig = rl_pending_signal();
115 # else
116 /* XXX: We assume all versions of readline have this... */
117 extern int volatile _rl_caught_signal;
118 sig = _rl_caught_signal;
119 # endif
120
121 if (sig) _rl_signal_handler(sig);
122 }
123
124 #endif /* defined(HAVE_LIBREADLINE) && defined(HAVE_READLINE_SIGNAL_HANDLER) */
125
126
127 #ifdef READLINE
128
129 /* This is a small portable version of GNU's readline that does not require
130 * any terminal capabilities except backspace and space overwrites a character.
131 * It is not the BASH or GNU EMACS version of READLINE due to Copyleft
132 * restrictions.
133 * Configuration option: ./configure --with-readline=builtin
134 */
135
136 /* NANO-EMACS line editing facility
137 * printable characters print as themselves (insert not overwrite)
138 * ^A moves to the beginning of the line
139 * ^B moves back a single character
140 * ^E moves to the end of the line
141 * ^F moves forward a single character
142 * ^K kills from current position to the end of line
143 * ^P moves back through history
144 * ^N moves forward through history
145 * ^H deletes the previous character
146 * ^D deletes the current character, or EOF if line is empty
147 * ^L redraw line in case it gets trashed
148 * ^U kills the entire line
149 * ^W deletes previous full or partial word
150 * ^V disables interpretation of the following key
151 * LF and CR return the entire line regardless of the cursor postition
152 * DEL deletes previous or current character (configuration dependent)
153 * TAB will perform filename completion
154 * ^R start a backward-search of the history
155 * EOF with an empty line returns (char *)NULL
156 *
157 * all other characters are ignored
158 */
159
160 #ifdef HAVE_SYS_IOCTL_H
161 /* For ioctl() prototype under Linux (and BeOS?) */
162 # include <sys/ioctl.h>
163 #endif
164
165 /* replaces the previous klugde in configure */
166 #if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR)
167 # define TERMIOS
168 #else /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
169 # ifdef HAVE_SGTTY_H
170 # define SGTTY
171 # endif
172 #endif /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
173
174 #if !defined(MSDOS) && !defined(_WIN32)
175
176 /*
177 * Set up structures using the proper include file
178 */
179 # if defined(_IBMR2) || defined(alliant)
180 # define SGTTY
181 # endif
182
183 /* submitted by Francois.Dagorn@cicb.fr */
184 # ifdef SGTTY
185 # include <sgtty.h>
186 static struct sgttyb orig_termio, rl_termio;
187 /* define terminal control characters */
188 static struct tchars s_tchars;
189 # ifndef VERASE
190 # define VERASE 0
191 # endif /* not VERASE */
192 # ifndef VEOF
193 # define VEOF 1
194 # endif /* not VEOF */
195 # ifndef VKILL
196 # define VKILL 2
197 # endif /* not VKILL */
198 # ifdef TIOCGLTC /* available only with the 'new' line discipline */
199 static struct ltchars s_ltchars;
200 # ifndef VWERASE
201 # define VWERASE 3
202 # endif /* not VWERASE */
203 # ifndef VREPRINT
204 # define VREPRINT 4
205 # endif /* not VREPRINT */
206 # ifndef VSUSP
207 # define VSUSP 5
208 # endif /* not VSUP */
209 # endif /* TIOCGLTC */
210 # ifndef NCCS
211 # define NCCS 6
212 # endif /* not NCCS */
213
214 # else /* not SGTTY */
215
216 /* SIGTSTP defines job control
217 * if there is job control then we need termios.h instead of termio.h
218 * (Are there any systems with job control that use termio.h? I hope not.)
219 */
220 # if defined(SIGTSTP) || defined(TERMIOS)
221 # ifndef TERMIOS
222 # define TERMIOS
223 # endif /* not TERMIOS */
224 # include <termios.h>
225 /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
226 # ifdef ISC22
227 # ifndef ONOCR /* taken from sys/termio.h */
228 # define ONOCR 0000020 /* true at least for ISC 2.2 */
229 # endif /* not ONOCR */
230 # ifndef IUCLC
231 # define IUCLC 0001000
232 # endif /* not IUCLC */
233 # endif /* ISC22 */
234 # if !defined(IUCLC)
235 /* translate upper to lower case not supported */
236 # define IUCLC 0
237 # endif /* not IUCLC */
238
239 static struct termios orig_termio, rl_termio;
240 # else /* not SIGSTP || TERMIOS */
241 # include <termio.h>
242 static struct termio orig_termio, rl_termio;
243 /* termio defines NCC instead of NCCS */
244 # define NCCS NCC
245 # endif /* not SIGTSTP || TERMIOS */
246 # endif /* SGTTY */
247
248 /* ULTRIX defines VRPRNT instead of VREPRINT */
249 # if defined(VRPRNT) && !defined(VREPRINT)
250 # define VREPRINT VRPRNT
251 # endif /* VRPRNT */
252
253 /* define characters to use with our input character handler */
254 static char term_chars[NCCS];
255
256 static int term_set = 0; /* =1 if rl_termio set */
257
258 #define special_getc() ansi_getc()
259 static int ansi_getc __PROTO((void));
260 #define DEL_ERASES_CURRENT_CHAR
261
262 #else /* MSDOS or _WIN32 */
263
264 # ifdef _WIN32
265 # include <windows.h>
266 # include "win/winmain.h"
267 # include "win/wcommon.h"
268 # define TEXTUSER 0xf1
269 # define TEXTGNUPLOT 0xf0
270 # ifdef WGP_CONSOLE
271 # define special_getc() win_getch()
272 static int win_getch(void);
273 # else
274 /* The wgnuplot text window will suppress intermediate
275 screen updates in 'suspend' mode and only redraw the
276 input line after 'resume'. */
277 # define SUSPENDOUTPUT TextSuspend(&textwin)
278 # define RESUMEOUTPUT TextResume(&textwin)
279 # define special_getc() msdos_getch()
280 static int msdos_getch(void);
281 # endif /* WGP_CONSOLE */
282 # define DEL_ERASES_CURRENT_CHAR
283 # endif /* _WIN32 */
284
285 # if defined(MSDOS)
286 /* MSDOS specific stuff */
287 # ifdef DJGPP
288 # include <pc.h>
289 # endif /* DJGPP */
290 # if defined(__EMX__) || defined (__WATCOMC__)
291 # include <conio.h>
292 # endif /* __EMX__ */
293 # define special_getc() msdos_getch()
294 static int msdos_getch();
295 # define DEL_ERASES_CURRENT_CHAR
296 # endif /* MSDOS */
297
298 #endif /* MSDOS or _WIN32 */
299
300 #ifdef OS2
301 # if defined( special_getc )
302 # undef special_getc()
303 # endif /* special_getc */
304 # define special_getc() os2_getch()
305 static int msdos_getch(void);
306 static int os2_getch(void);
307 # define DEL_ERASES_CURRENT_CHAR
308 #endif /* OS2 */
309
310
311 /* initial size and increment of input line length */
312 #define MAXBUF 1024
313 #define BACKSPACE '\b' /* ^H */
314 #define SPACE ' '
315 #define NEWLINE '\n'
316
317 #define MAX_COMPLETIONS 50
318
319 #ifndef SUSPENDOUTPUT
320 #define SUSPENDOUTPUT
321 #define RESUMEOUTPUT
322 #endif
323
324 static char *cur_line; /* current contents of the line */
325 static size_t line_len = 0;
326 static size_t cur_pos = 0; /* current position of the cursor */
327 static size_t max_pos = 0; /* maximum character position */
328
329 static TBOOLEAN search_mode = FALSE;
330 static const char search_prompt[] = "search '";
331 static const char search_prompt2[] = "': ";
332 static struct hist * search_result = NULL;
333 static int search_result_width = 0; /* on-screen width of the search result */
334
335 static void fix_line __PROTO((void));
336 static void redraw_line __PROTO((const char *prompt));
337 static void clear_line __PROTO((const char *prompt));
338 static void clear_eoline __PROTO((const char *prompt));
339 static void delete_previous_word __PROTO((void));
340 static void copy_line __PROTO((char *line));
341 static void set_termio __PROTO((void));
342 static void reset_termio __PROTO((void));
343 static int user_putc __PROTO((int ch));
344 static int user_puts __PROTO((char *str));
345 static int backspace __PROTO((void));
346 static void extend_cur_line __PROTO((void));
347 static void step_forward __PROTO((void));
348 static void delete_forward __PROTO((void));
349 static void delete_backward __PROTO((void));
350 static int char_seqlen __PROTO((void));
351 #if defined(HAVE_DIRENT_H) || defined(_WIN32)
352 static char *fn_completion(size_t anchor_pos, int direction);
353 static void tab_completion(TBOOLEAN forward);
354 #endif
355 static void switch_prompt(const char * old_prompt, const char * new_prompt);
356 static int do_search(int dir);
357 static void print_search_result(const struct hist * result);
358
359 #ifndef _WIN32
360 static int mbwidth(const char *c);
361 #endif
362 static int strwidth(const char * str);
363
364 /* user_putc and user_puts should be used in the place of
365 * fputc(ch,stderr) and fputs(str,stderr) for all output
366 * of user typed characters. This allows MS-Windows to
367 * display user input in a different color.
368 */
369 static int
user_putc(int ch)370 user_putc(int ch)
371 {
372 int rv;
373 #if defined(_WIN32) && !defined(WGP_CONSOLE)
374 TextAttr(&textwin, TEXTUSER);
375 #endif
376 rv = fputc(ch, stderr);
377 #if defined(_WIN32) && !defined(WGP_CONSOLE)
378 TextAttr(&textwin, TEXTGNUPLOT);
379 #endif
380 return rv;
381 }
382
383 static int
user_puts(char * str)384 user_puts(char *str)
385 {
386 int rv;
387 #if defined(_WIN32) && !defined(WGP_CONSOLE)
388 TextAttr(&textwin, TEXTUSER);
389 #endif
390 rv = fputs(str, stderr);
391 #if defined(_WIN32) && !defined(WGP_CONSOLE)
392 TextAttr(&textwin, TEXTGNUPLOT);
393 #endif
394 return rv;
395 }
396
397
398 #if !defined(_WIN32)
399 /* EAM FIXME
400 * This test is intended to determine if the current character, of which
401 * we have only seen the first byte so far, will require twice the width
402 * of an ascii character. The test catches glyphs above unicode 0x3000,
403 * which is roughly the set of CJK characters.
404 * It should be replaced with a more accurate test.
405 */
406 static int
mbwidth(const char * c)407 mbwidth(const char *c)
408 {
409 switch (encoding) {
410
411 case S_ENC_UTF8:
412 return ((unsigned char)(*c) >= 0xe3 ? 2 : 1);
413
414 case S_ENC_SJIS:
415 /* Assume all double-byte characters have double-width. */
416 return is_sjis_lead_byte(*c) ? 2 : 1;
417
418 default:
419 return 1;
420 }
421 }
422 #endif
423
424 static int
strwidth(const char * str)425 strwidth(const char * str)
426 {
427 #if !defined(_WIN32)
428 int width = 0;
429 int i = 0;
430
431 switch (encoding) {
432 case S_ENC_UTF8:
433 while (str[i]) {
434 const char *ch = &str[i++];
435 if ((*ch & 0xE0) == 0xC0) {
436 i += 1;
437 } else if ((*ch & 0xF0) == 0xE0) {
438 i += 2;
439 } else if ((*ch & 0xF8) == 0xF0) {
440 i += 3;
441 }
442 width += mbwidth(ch);
443 }
444 break;
445 case S_ENC_SJIS:
446 /* Assume all double-byte characters have double-width. */
447 width = gp_strlen(str);
448 break;
449 default:
450 width = strlen(str);
451 }
452 return width;
453 #else
454 /* double width characters are handled in the backend */
455 return gp_strlen(str);
456 #endif
457 }
458
459 static int
isdoublewidth(size_t pos)460 isdoublewidth(size_t pos)
461 {
462 #if defined(_WIN32)
463 /* double width characters are handled in the backend */
464 return FALSE;
465 #else
466 return mbwidth(cur_line + pos) > 1;
467 #endif
468 }
469
470 /*
471 * Determine length of multi-byte sequence starting at current position
472 */
473 static int
char_seqlen()474 char_seqlen()
475 {
476 switch (encoding) {
477
478 case S_ENC_UTF8: {
479 int i = cur_pos;
480 do {i++;}
481 while (((cur_line[i] & 0xc0) != 0xc0)
482 && ((cur_line[i] & 0x80) != 0)
483 && (i < max_pos));
484 return (i - cur_pos);
485 }
486
487 case S_ENC_SJIS:
488 return is_sjis_lead_byte(cur_line[cur_pos]) ? 2 : 1;
489
490 default:
491 return 1;
492 }
493 }
494
495 /*
496 * Back up over one multi-byte character sequence immediately preceding
497 * the current position. Non-destructive. Affects both cur_pos and screen cursor.
498 */
499 static int
backspace()500 backspace()
501 {
502 switch (encoding) {
503
504 case S_ENC_UTF8: {
505 int seqlen = 0;
506 do {
507 cur_pos--;
508 seqlen++;
509 } while (((cur_line[cur_pos] & 0xc0) != 0xc0)
510 && ((cur_line[cur_pos] & 0x80) != 0)
511 && (cur_pos > 0)
512 );
513
514 if ( ((cur_line[cur_pos] & 0xc0) == 0xc0)
515 || isprint((unsigned char)cur_line[cur_pos])
516 )
517 user_putc(BACKSPACE);
518 if (isdoublewidth(cur_pos))
519 user_putc(BACKSPACE);
520 return seqlen;
521 }
522
523 case S_ENC_SJIS: {
524 /* With S-JIS you cannot always determine if a byte is a single byte or part
525 of a double-byte sequence by looking of an arbitrary byte in a string.
526 Always test from the start of the string instead.
527 */
528 int i;
529 int seqlen = 1;
530
531 for (i = 0; i < cur_pos; i += seqlen) {
532 seqlen = is_sjis_lead_byte(cur_line[i]) ? 2 : 1;
533 }
534 cur_pos -= seqlen;
535 user_putc(BACKSPACE);
536 if (isdoublewidth(cur_pos))
537 user_putc(BACKSPACE);
538 return seqlen;
539 }
540
541 default:
542 cur_pos--;
543 user_putc(BACKSPACE);
544 return 1;
545 }
546 }
547
548 /*
549 * Step forward over one multi-byte character sequence.
550 * We don't assume a non-destructive forward space, so we have
551 * to redraw the character as we go.
552 */
553 static void
step_forward()554 step_forward()
555 {
556 int i, seqlen;
557
558 switch (encoding) {
559
560 case S_ENC_UTF8:
561 case S_ENC_SJIS:
562 seqlen = char_seqlen();
563 for (i = 0; i < seqlen; i++)
564 user_putc(cur_line[cur_pos++]);
565 break;
566
567 default:
568 user_putc(cur_line[cur_pos++]);
569 break;
570 }
571 }
572
573 /*
574 * Delete the character we are on and collapse all subsequent characters back one
575 */
576 static void
delete_forward()577 delete_forward()
578 {
579 if (cur_pos < max_pos) {
580 size_t i;
581 int seqlen = char_seqlen();
582 max_pos -= seqlen;
583 for (i = cur_pos; i < max_pos; i++)
584 cur_line[i] = cur_line[i + seqlen];
585 cur_line[max_pos] = '\0';
586 fix_line();
587 }
588 }
589
590 /*
591 * Delete the previous character and collapse all subsequent characters back one
592 */
593 static void
delete_backward()594 delete_backward()
595 {
596 if (cur_pos > 0) {
597 size_t i;
598 int seqlen = backspace();
599 max_pos -= seqlen;
600 for (i = cur_pos; i < max_pos; i++)
601 cur_line[i] = cur_line[i + seqlen];
602 cur_line[max_pos] = '\0';
603 fix_line();
604 }
605 }
606
607 static void
extend_cur_line()608 extend_cur_line()
609 {
610 char *new_line;
611
612 /* extend input line length */
613 new_line = (char *) gp_realloc(cur_line, line_len + MAXBUF, NULL);
614 if (!new_line) {
615 reset_termio();
616 int_error(NO_CARET, "Can't extend readline length");
617 }
618 cur_line = new_line;
619 line_len += MAXBUF;
620 FPRINTF((stderr, "\nextending readline length to %d chars\n", line_len));
621 }
622
623
624 #if defined(HAVE_DIRENT_H) || defined(_WIN32)
625 static char *
fn_completion(size_t anchor_pos,int direction)626 fn_completion(size_t anchor_pos, int direction)
627 {
628 static char * completions[MAX_COMPLETIONS];
629 static int n_completions = 0;
630 static int completion_idx = 0;
631
632 if (direction == 0) {
633 /* new completion */
634 DIR * dir;
635 char * start, * path;
636 char * t, * search;
637 char * name = NULL;
638 size_t nlen;
639
640 if (n_completions != 0) {
641 /* new completion, cleanup first */
642 int i;
643 for (i = 0; i < n_completions; i++)
644 free(completions[i]);
645 memset(completions, 0, sizeof(completions));
646 n_completions = 0;
647 completion_idx = 0;
648 }
649
650 /* extract path to complete */
651 start = cur_line + anchor_pos;
652 if (anchor_pos > 0) {
653 /* first, look for a quote to start the string */
654 for ( ; start >= cur_line; start--) {
655 if ((*start == '"') || (*start == '\'')) {
656 start++;
657 /* handle pipe commands */
658 if ((*start == '<') || (*start == '|'))
659 start++;
660 break;
661 }
662 }
663 /* if not found, search for a space or a system command '!' instead */
664 if (start <= cur_line) {
665 for (start = cur_line + anchor_pos; start >= cur_line; start--) {
666 if ((*start == ' ') || (*start == '!')) {
667 start++;
668 break;
669 }
670 }
671 }
672 if (start < cur_line)
673 start = cur_line;
674
675 path = strndup(start, cur_line - start + anchor_pos);
676 gp_expand_tilde(&path);
677 } else {
678 path = gp_strdup("");
679 }
680
681 /* seperate directory and (partial) file directory name */
682 t = strrchr(path, DIRSEP1);
683 #if DIRSEP2 != NUL
684 if (t == NULL) t = strrchr(path, DIRSEP2);
685 #endif
686 if (t == NULL) {
687 /* name... */
688 search = gp_strdup(".");
689 name = strdup(path);
690 } else if (t == path) {
691 /* root dir: /name... */
692 search = strndup(path, 1);
693 nlen = cur_pos - (t - path) - 1;
694 name = strndup(t + 1, nlen);
695 } else {
696 /* normal case: dir/dir/name... */
697 search = strndup(path, t - path);
698 nlen = cur_pos - (t - path) - 1;
699 name = strndup(t + 1, nlen);
700 }
701 nlen = strlen(name);
702 free(path);
703
704 n_completions = 0;
705 if ((dir = opendir(search))) {
706 struct dirent * entry;
707 while ((entry = readdir(dir)) != NULL) {
708 /* ignore files and directories starting with a dot */
709 if (entry->d_name[0] == '.')
710 continue;
711
712 /* skip entries which don't match */
713 if (nlen > 0)
714 if (strncmp(entry->d_name, name, nlen) != 0) continue;
715
716 completions[n_completions] = gp_strdup(entry->d_name + nlen);
717 n_completions++;
718
719 /* limit number of completions */
720 if (n_completions == MAX_COMPLETIONS) break;
721 }
722 closedir(dir);
723 free(search);
724 if (name) free(name);
725 if (n_completions > 0)
726 return completions[0];
727 else
728 return NULL;
729 }
730 free(search);
731 if (name) free(name);
732 } else {
733 /* cycle trough previous results */
734 if (n_completions > 0) {
735 if (direction > 0)
736 completion_idx = (completion_idx + 1) % n_completions;
737 else
738 completion_idx = (completion_idx + n_completions - 1) % n_completions;
739 return completions[completion_idx];
740 } else
741 return NULL;
742 }
743 return NULL;
744 }
745
746
747 static void
tab_completion(TBOOLEAN forward)748 tab_completion(TBOOLEAN forward)
749 {
750 size_t i;
751 char * completion;
752 size_t completion_len;
753 static size_t last_tab_pos = -1;
754 static size_t last_completion_len = 0;
755 int direction;
756
757 /* detect tab cycling */
758 if ((last_tab_pos + last_completion_len) != cur_pos) {
759 last_completion_len = 0;
760 last_tab_pos = cur_pos;
761 direction = 0; /* new completion */
762 } else {
763 direction = (forward ? 1 : -1);
764 }
765
766 /* find completion */
767 completion = fn_completion(last_tab_pos, direction);
768 if (!completion) return;
769
770 /* make room for new completion */
771 completion_len = strlen(completion);
772 if (completion_len > last_completion_len)
773 while (max_pos + completion_len - last_completion_len + 1 > line_len)
774 extend_cur_line();
775
776 SUSPENDOUTPUT;
777 /* erase from last_tab_pos to eol */
778 while (cur_pos > last_tab_pos)
779 backspace();
780 while (cur_pos < max_pos) {
781 user_putc(SPACE);
782 if (isdoublewidth(cur_pos))
783 user_putc(SPACE);
784 cur_pos += char_seqlen();
785 }
786
787 /* rewind to last_tab_pos */
788 while (cur_pos > last_tab_pos)
789 backspace();
790
791 /* insert completion string */
792 if (max_pos > (last_tab_pos - last_completion_len))
793 memmove(cur_line + last_tab_pos + completion_len,
794 cur_line + last_tab_pos + last_completion_len,
795 max_pos - last_tab_pos - last_completion_len);
796 memcpy(cur_line + last_tab_pos, completion, completion_len);
797 max_pos += completion_len - last_completion_len;
798 cur_line[max_pos] = NUL;
799
800 /* draw new completion */
801 for (i = 0; i < completion_len; i++)
802 user_putc(cur_line[last_tab_pos+i]);
803 cur_pos += completion_len;
804 fix_line();
805 RESUMEOUTPUT;
806
807 /* remember this completion */
808 last_tab_pos = cur_pos - completion_len;
809 last_completion_len = completion_len;
810 }
811
812 #endif /* HAVE_DIRENT_H || _WIN32 */
813
814
815 char *
readline(const char * prompt)816 readline(const char *prompt)
817 {
818 int cur_char;
819 char *new_line;
820 TBOOLEAN next_verbatim = FALSE;
821 char *prev_line;
822
823 /* start with a string of MAXBUF chars */
824 if (line_len != 0) {
825 free(cur_line);
826 line_len = 0;
827 }
828 cur_line = (char *) gp_alloc(MAXBUF, "readline");
829 line_len = MAXBUF;
830
831 /* set the termio so we can do our own input processing */
832 set_termio();
833
834 /* print the prompt */
835 fputs(prompt, stderr);
836 cur_line[0] = '\0';
837 cur_pos = 0;
838 max_pos = 0;
839
840 /* move to end of history */
841 while (next_history());
842
843 /* init global variables */
844 search_mode = FALSE;
845
846 /* get characters */
847 for (;;) {
848
849 cur_char = special_getc();
850
851 /* Accumulate ascii (7bit) printable characters
852 * and all leading 8bit characters.
853 */
854 if (((isprint(cur_char)
855 || (((cur_char & 0x80) != 0) && (cur_char != EOF))
856 ) && (cur_char != '\t')) /* TAB is a printable character in some locales */
857 || next_verbatim
858 ) {
859 size_t i;
860
861 if (max_pos + 1 >= line_len) {
862 extend_cur_line();
863 }
864 for (i = max_pos; i > cur_pos; i--) {
865 cur_line[i] = cur_line[i - 1];
866 }
867 user_putc(cur_char);
868
869 cur_line[cur_pos] = cur_char;
870 cur_pos += 1;
871 max_pos += 1;
872 cur_line[max_pos] = '\0';
873
874 if (cur_pos < max_pos) {
875 switch (encoding) {
876 case S_ENC_UTF8:
877 if ((cur_char & 0xc0) == 0) {
878 next_verbatim = FALSE;
879 fix_line(); /* Normal ascii character */
880 } else if ((cur_char & 0xc0) == 0xc0) {
881 ; /* start of a multibyte sequence. */
882 } else if (((cur_char & 0xc0) == 0x80) &&
883 ((unsigned char)(cur_line[cur_pos-2]) >= 0xe0)) {
884 ; /* second byte of a >2 byte sequence */
885 } else {
886 /* Last char of multi-byte sequence */
887 next_verbatim = FALSE;
888 fix_line();
889 }
890 break;
891
892 case S_ENC_SJIS: {
893 /* S-JIS requires a state variable */
894 static int mbwait = 0;
895
896 if (mbwait == 0) {
897 if (!is_sjis_lead_byte(cur_char)) {
898 /* single-byte character */
899 next_verbatim = FALSE;
900 fix_line();
901 } else {
902 /* first byte of a double-byte sequence */
903 ;
904 }
905 } else {
906 /* second byte of a double-byte sequence */
907 mbwait = 0;
908 next_verbatim = FALSE;
909 fix_line();
910 }
911 }
912
913 default:
914 next_verbatim = FALSE;
915 fix_line();
916 break;
917 }
918 } else {
919 static int mbwait = 0;
920
921 next_verbatim = FALSE;
922 if (search_mode) {
923 /* Only update the search at the end of a multi-byte sequence. */
924 if (mbwait == 0) {
925 if (encoding == S_ENC_SJIS)
926 mbwait = is_sjis_lead_byte(cur_char) ? 1 : 0;
927 if (encoding == S_ENC_UTF8) {
928 char ch = cur_char;
929 if (ch & 0x80)
930 while ((ch = (ch << 1)) & 0x80)
931 mbwait++;
932 }
933 } else {
934 mbwait--;
935 }
936 if (!mbwait)
937 do_search(-1);
938 }
939 }
940
941 /* ignore special characters in search_mode */
942 } else if (!search_mode) {
943
944 if (0) {
945 ;
946
947 /* else interpret unix terminal driver characters */
948 #ifdef VERASE
949 } else if (cur_char == term_chars[VERASE]) { /* ^H */
950 delete_backward();
951 #endif /* VERASE */
952 #ifdef VEOF
953 } else if (cur_char == term_chars[VEOF]) { /* ^D? */
954 if (max_pos == 0) {
955 reset_termio();
956 return ((char *) NULL);
957 }
958 delete_forward();
959 #endif /* VEOF */
960 #ifdef VKILL
961 } else if (cur_char == term_chars[VKILL]) { /* ^U? */
962 clear_line(prompt);
963 #endif /* VKILL */
964 #ifdef VWERASE
965 } else if (cur_char == term_chars[VWERASE]) { /* ^W? */
966 delete_previous_word();
967 #endif /* VWERASE */
968 #ifdef VREPRINT
969 #if 0 /* conflict with reverse-search */
970 } else if (cur_char == term_chars[VREPRINT]) { /* ^R? */
971 putc(NEWLINE, stderr); /* go to a fresh line */
972 redraw_line(prompt);
973 #endif
974 #endif /* VREPRINT */
975 #ifdef VSUSP
976 } else if (cur_char == term_chars[VSUSP]) {
977 reset_termio();
978 kill(0, SIGTSTP);
979
980 /* process stops here */
981
982 set_termio();
983 /* print the prompt */
984 redraw_line(prompt);
985 #endif /* VSUSP */
986 } else {
987 /* do normal editing commands */
988 /* some of these are also done above */
989 switch (cur_char) {
990 case EOF:
991 reset_termio();
992 return ((char *) NULL);
993 case 001: /* ^A */
994 while (cur_pos > 0)
995 backspace();
996 break;
997 case 002: /* ^B */
998 if (cur_pos > 0)
999 backspace();
1000 break;
1001 case 005: /* ^E */
1002 while (cur_pos < max_pos) {
1003 user_putc(cur_line[cur_pos]);
1004 cur_pos += 1;
1005 }
1006 break;
1007 case 006: /* ^F */
1008 if (cur_pos < max_pos) {
1009 step_forward();
1010 }
1011 break;
1012 #if defined(HAVE_DIRENT_H) || defined(_WIN32)
1013 case 011: /* ^I / TAB */
1014 tab_completion(TRUE); /* next tab completion */
1015 break;
1016 case 034: /* remapped by wtext.c or ansi_getc from Shift-Tab */
1017 tab_completion(FALSE); /* previous tab completion */
1018 break;
1019 #endif
1020 case 013: /* ^K */
1021 clear_eoline(prompt);
1022 max_pos = cur_pos;
1023 break;
1024 case 020: /* ^P */
1025 if (previous_history() != NULL) {
1026 clear_line(prompt);
1027 copy_line(current_history()->line);
1028 }
1029 break;
1030 case 016: /* ^N */
1031 clear_line(prompt);
1032 if (next_history() != NULL) {
1033 copy_line(current_history()->line);
1034 } else {
1035 cur_pos = max_pos = 0;
1036 }
1037 break;
1038 case 022: /* ^R */
1039 prev_line = strdup(cur_line);
1040 switch_prompt(prompt, search_prompt);
1041 while (next_history()); /* seek to end of history */
1042 search_result = NULL;
1043 search_result_width = 0;
1044 search_mode = TRUE;
1045 print_search_result(NULL);
1046 break;
1047 case 014: /* ^L */
1048 putc(NEWLINE, stderr); /* go to a fresh line */
1049 redraw_line(prompt);
1050 break;
1051 #ifndef DEL_ERASES_CURRENT_CHAR
1052 case 0177: /* DEL */
1053 case 023: /* Re-mapped from CSI~3 in ansi_getc() */
1054 #endif
1055 case 010: /* ^H */
1056 delete_backward();
1057 break;
1058 case 004: /* ^D */
1059 /* Also catch asynchronous termination signal on Windows */
1060 if (max_pos == 0 && terminate_flag) {
1061 reset_termio();
1062 return NULL;
1063 }
1064 /* intentionally omitting break */
1065 #ifdef DEL_ERASES_CURRENT_CHAR
1066 case 0177: /* DEL */
1067 case 023: /* Re-mapped from CSI~3 in ansi_getc() */
1068 #endif
1069 delete_forward();
1070 break;
1071 case 025: /* ^U */
1072 clear_line(prompt);
1073 break;
1074 case 026: /* ^V */
1075 next_verbatim = TRUE;
1076 break;
1077 case 027: /* ^W */
1078 delete_previous_word();
1079 break;
1080 case '\n': /* ^J */
1081 case '\r': /* ^M */
1082 cur_line[max_pos + 1] = '\0';
1083 #ifdef OS2
1084 while (cur_pos < max_pos) {
1085 user_putc(cur_line[cur_pos]);
1086 cur_pos += 1;
1087 }
1088 #endif
1089 putc(NEWLINE, stderr);
1090
1091 /* Shrink the block down to fit the string ?
1092 * if the alloc fails, we still own block at cur_line,
1093 * but this shouldn't really fail.
1094 */
1095 new_line = (char *) gp_realloc(cur_line, strlen(cur_line) + 1,
1096 "line resize");
1097 if (new_line)
1098 cur_line = new_line;
1099 /* else we just hang on to what we had - it's not a problem */
1100
1101 line_len = 0;
1102 FPRINTF((stderr, "Resizing input line to %d chars\n", strlen(cur_line)));
1103 reset_termio();
1104 return (cur_line);
1105 default:
1106 break;
1107 }
1108 }
1109
1110 } else { /* search-mode */
1111 #ifdef VERASE
1112 if (cur_char == term_chars[VERASE]) { /* ^H */
1113 delete_backward();
1114 do_search(-1);
1115 } else
1116 #endif /* VERASE */
1117 {
1118 switch (cur_char) {
1119 case 022: /* ^R */
1120 /* search next */
1121 previous_history();
1122 if (do_search(-1) == -1)
1123 next_history();
1124 break;
1125 case 023: /* ^S */
1126 /* search previous */
1127 next_history();
1128 if (do_search(1) == -1)
1129 previous_history();
1130 break;
1131 break;
1132 case '\n': /* ^J */
1133 case '\r': /* ^M */
1134 /* accept */
1135 switch_prompt(search_prompt, prompt);
1136 if (search_result != NULL)
1137 copy_line(search_result->line);
1138 free(prev_line);
1139 search_result_width = 0;
1140 search_mode = FALSE;
1141 break;
1142 #ifndef DEL_ERASES_CURRENT_CHAR
1143 case 0177: /* DEL */
1144 /* FIXME: conflict! */
1145 //case 023: /* Re-mapped from CSI~3 in ansi_getc() */
1146 #endif
1147 case 010: /* ^H */
1148 delete_backward();
1149 do_search(1);
1150 break;
1151 default:
1152 /* abort, restore previous input line */
1153 switch_prompt(search_prompt, prompt);
1154 copy_line(prev_line);
1155 free(prev_line);
1156 search_result_width = 0;
1157 search_mode = FALSE;
1158 break;
1159 }
1160 }
1161 }
1162 }
1163 }
1164
1165
1166 static int
do_search(int dir)1167 do_search(int dir)
1168 {
1169 int ret = -1;
1170
1171 if ((ret = history_search(cur_line, dir)) != -1)
1172 search_result = current_history();
1173 print_search_result(search_result);
1174 return ret;
1175 }
1176
1177
1178 void
print_search_result(const struct hist * result)1179 print_search_result(const struct hist * result)
1180 {
1181 int i, width = 0;
1182
1183 SUSPENDOUTPUT;
1184 fputs(search_prompt2, stderr);
1185 if (result != NULL && result->line != NULL) {
1186 fputs(result->line, stderr);
1187 width = strwidth(result->line);
1188 }
1189
1190 /* overwrite previous search result, and the line might
1191 just have gotten 1 double-width character shorter */
1192 for (i = 0; i < search_result_width - width + 2; i++)
1193 putc(SPACE, stderr);
1194 for (i = 0; i < search_result_width - width + 2; i++)
1195 putc(BACKSPACE, stderr);
1196 search_result_width = width;
1197
1198 /* restore cursor position */
1199 for (i = 0; i < width; i++)
1200 putc(BACKSPACE, stderr);
1201 for (i = 0; i < strlen(search_prompt2); i++)
1202 putc(BACKSPACE, stderr);
1203 RESUMEOUTPUT;
1204 }
1205
1206
1207 static void
switch_prompt(const char * old_prompt,const char * new_prompt)1208 switch_prompt(const char * old_prompt, const char * new_prompt)
1209 {
1210 int i, len;
1211
1212 SUSPENDOUTPUT;
1213
1214 /* clear search results (if any) */
1215 if (search_mode) {
1216 for (i = 0; i < search_result_width + strlen(search_prompt2); i++)
1217 user_putc(SPACE);
1218 for (i = 0; i < search_result_width + strlen(search_prompt2); i++)
1219 user_putc(BACKSPACE);
1220 }
1221
1222 /* clear current line */
1223 clear_line(old_prompt);
1224 putc('\r', stderr);
1225 fputs(new_prompt, stderr);
1226 cur_pos = 0;
1227
1228 /* erase remainder of previous prompt */
1229 len = GPMAX((int)strlen(old_prompt) - (int)strlen(new_prompt), 0);
1230 for (i = 0; i < len; i++)
1231 user_putc(SPACE);
1232 for (i = 0; i < len; i++)
1233 user_putc(BACKSPACE);
1234 RESUMEOUTPUT;
1235 }
1236
1237
1238 /* Fix up the line from cur_pos to max_pos.
1239 * Does not need any terminal capabilities except backspace,
1240 * and space overwrites a character
1241 */
1242 static void
fix_line()1243 fix_line()
1244 {
1245 size_t i;
1246
1247 SUSPENDOUTPUT;
1248 /* write tail of string */
1249 for (i = cur_pos; i < max_pos; i++)
1250 user_putc(cur_line[i]);
1251
1252 /* We may have just shortened the line by deleting a character.
1253 * Write a space at the end to over-print the former last character.
1254 * It needs 2 spaces in case the former character was double width.
1255 */
1256 user_putc(SPACE);
1257 user_putc(SPACE);
1258 if (search_mode) {
1259 for (i = 0; i < search_result_width; i++)
1260 user_putc(SPACE);
1261 for (i = 0; i < search_result_width; i++)
1262 user_putc(BACKSPACE);
1263 }
1264 user_putc(BACKSPACE);
1265 user_putc(BACKSPACE);
1266
1267 /* Back up to original position */
1268 i = cur_pos;
1269 for (cur_pos = max_pos; cur_pos > i; )
1270 backspace();
1271 RESUMEOUTPUT;
1272 }
1273
1274 /* redraw the entire line, putting the cursor where it belongs */
1275 static void
redraw_line(const char * prompt)1276 redraw_line(const char *prompt)
1277 {
1278 size_t i;
1279
1280 SUSPENDOUTPUT;
1281 fputs(prompt, stderr);
1282 user_puts(cur_line);
1283
1284 /* put the cursor where it belongs */
1285 i = cur_pos;
1286 for (cur_pos = max_pos; cur_pos > i; )
1287 backspace();
1288 RESUMEOUTPUT;
1289 }
1290
1291 /* clear cur_line and the screen line */
1292 static void
clear_line(const char * prompt)1293 clear_line(const char *prompt)
1294 {
1295 SUSPENDOUTPUT;
1296 putc('\r', stderr);
1297 fputs(prompt, stderr);
1298 cur_pos = 0;
1299
1300 while (cur_pos < max_pos) {
1301 user_putc(SPACE);
1302 if (isdoublewidth(cur_pos))
1303 user_putc(SPACE);
1304 cur_pos += char_seqlen();
1305 }
1306 while (max_pos > 0)
1307 cur_line[--max_pos] = '\0';
1308
1309 putc('\r', stderr);
1310 fputs(prompt, stderr);
1311 cur_pos = 0;
1312 RESUMEOUTPUT;
1313 }
1314
1315 /* clear to end of line and the screen end of line */
1316 static void
clear_eoline(const char * prompt)1317 clear_eoline(const char *prompt)
1318 {
1319 size_t save_pos = cur_pos;
1320
1321 SUSPENDOUTPUT;
1322 while (cur_pos < max_pos) {
1323 user_putc(SPACE);
1324 if (isdoublewidth(cur_line[cur_pos]))
1325 user_putc(SPACE);
1326 cur_pos += char_seqlen();
1327 }
1328 cur_pos = save_pos;
1329 while (max_pos > cur_pos)
1330 cur_line[--max_pos] = '\0';
1331
1332 putc('\r', stderr);
1333 fputs(prompt, stderr);
1334 user_puts(cur_line);
1335 RESUMEOUTPUT;
1336 }
1337
1338 /* delete the full or partial word immediately before cursor position */
1339 static void
delete_previous_word()1340 delete_previous_word()
1341 {
1342 size_t save_pos = cur_pos;
1343
1344 SUSPENDOUTPUT;
1345 /* skip whitespace */
1346 while ((cur_pos > 0) &&
1347 (cur_line[cur_pos - 1] == SPACE)) {
1348 backspace();
1349 }
1350 /* find start of previous word */
1351 while ((cur_pos > 0) &&
1352 (cur_line[cur_pos - 1] != SPACE)) {
1353 backspace();
1354 }
1355 if (cur_pos != save_pos) {
1356 size_t new_cur_pos = cur_pos;
1357 size_t m = max_pos - save_pos;
1358
1359 /* erase to eol */
1360 while (cur_pos < max_pos) {
1361 user_putc(SPACE);
1362 if (isdoublewidth(cur_pos))
1363 user_putc(SPACE);
1364 cur_pos += char_seqlen();
1365 }
1366 while (cur_pos > new_cur_pos)
1367 backspace();
1368
1369 /* overwrite previous word with trailing characters */
1370 memmove(cur_line + cur_pos, cur_line + save_pos, m);
1371 /* overwrite characters at end of string with NULs */
1372 memset(cur_line + cur_pos + m, NUL, save_pos - cur_pos);
1373
1374 /* update display and line length */
1375 max_pos = cur_pos + m;
1376 fix_line();
1377 }
1378 RESUMEOUTPUT;
1379 }
1380
1381 /* copy line to cur_line, draw it and set cur_pos and max_pos */
1382 static void
copy_line(char * line)1383 copy_line(char *line)
1384 {
1385 while (strlen(line) + 1 > line_len) {
1386 extend_cur_line();
1387 }
1388 strcpy(cur_line, line);
1389 user_puts(cur_line);
1390 cur_pos = max_pos = strlen(cur_line);
1391 }
1392
1393 #if !defined(MSDOS) && !defined(_WIN32)
1394 /* Convert ANSI arrow keys to control characters */
1395 static int
ansi_getc()1396 ansi_getc()
1397 {
1398 int c;
1399
1400 #ifdef USE_MOUSE
1401 if (term && term->waitforinput && interactive)
1402 c = term->waitforinput(0);
1403 else
1404 #endif
1405 c = getc(stdin);
1406
1407 if (c == 033) {
1408 c = getc(stdin); /* check for CSI */
1409 if (c == '[') {
1410 c = getc(stdin); /* get command character */
1411 switch (c) {
1412 case 'D': /* left arrow key */
1413 c = 002;
1414 break;
1415 case 'C': /* right arrow key */
1416 c = 006;
1417 break;
1418 case 'A': /* up arrow key */
1419 c = 020;
1420 break;
1421 case 'B': /* down arrow key */
1422 c = 016;
1423 break;
1424 case 'F': /* end key */
1425 c = 005;
1426 break;
1427 case 'H': /* home key */
1428 c = 001;
1429 break;
1430 case 'Z': /* shift-tab key */
1431 c = 034; /* FS: non-standard! */
1432 break;
1433 case '3': /* DEL can be <esc>[3~ */
1434 getc(stdin); /* eat the ~ */
1435 c = 023; /* DC3 ^S NB: non-standard!! */
1436 }
1437 }
1438 }
1439 return c;
1440 }
1441 #endif
1442
1443 #if defined(MSDOS) || defined(_WIN32) || defined(OS2)
1444
1445 #ifdef WGP_CONSOLE
1446 static int
win_getch()1447 win_getch()
1448 {
1449 if (term && term->waitforinput)
1450 return term->waitforinput(0);
1451 else
1452 return ConsoleGetch();
1453 }
1454 #else
1455
1456 /* Convert Arrow keystrokes to Control characters: */
1457 static int
msdos_getch()1458 msdos_getch()
1459 {
1460 int c;
1461
1462 #ifdef DJGPP
1463 int ch = getkey();
1464 c = (ch & 0xff00) ? 0 : ch & 0xff;
1465 #elif defined (OS2)
1466 c = getc(stdin);
1467 #else /* not OS2, not DJGPP*/
1468 # if defined (USE_MOUSE)
1469 if (term && term->waitforinput && interactive)
1470 c = term->waitforinput(0);
1471 else
1472 # endif /* not USE_MOUSE */
1473 c = getch();
1474 #endif /* not DJGPP, not OS2 */
1475
1476 if (c == 0) {
1477 #ifdef DJGPP
1478 c = ch & 0xff;
1479 #elif defined(OS2)
1480 c = getc(stdin);
1481 #else /* not OS2, not DJGPP */
1482 # if defined (USE_MOUSE)
1483 if (term && term->waitforinput && interactive)
1484 c = term->waitforinput(0);
1485 else
1486 # endif /* not USE_MOUSE */
1487 c = getch(); /* Get the extended code. */
1488 #endif /* not DJGPP, not OS2 */
1489
1490 switch (c) {
1491 case 75: /* Left Arrow. */
1492 c = 002;
1493 break;
1494 case 77: /* Right Arrow. */
1495 c = 006;
1496 break;
1497 case 72: /* Up Arrow. */
1498 c = 020;
1499 break;
1500 case 80: /* Down Arrow. */
1501 c = 016;
1502 break;
1503 case 115: /* Ctl Left Arrow. */
1504 case 71: /* Home */
1505 c = 001;
1506 break;
1507 case 116: /* Ctl Right Arrow. */
1508 case 79: /* End */
1509 c = 005;
1510 break;
1511 case 83: /* Delete */
1512 c = 0177;
1513 break;
1514 default:
1515 c = 0;
1516 break;
1517 }
1518 } else if (c == 033) { /* ESC */
1519 c = 025;
1520 }
1521 return c;
1522 }
1523 #endif /* WGP_CONSOLE */
1524 #endif /* MSDOS || _WIN32 || OS2 */
1525
1526 #ifdef OS2
1527 /* We need to call different procedures, dependent on the
1528 session type: VIO/window or an (XFree86) xterm */
1529 static int
os2_getch()1530 os2_getch() {
1531 static int IsXterm = 0;
1532 static int init = 0;
1533
1534 if (!init) {
1535 if (getenv("WINDOWID")) {
1536 IsXterm = 1;
1537 }
1538 init = 1;
1539 }
1540 if (IsXterm) {
1541 return ansi_getc();
1542 } else {
1543 return msdos_getch();
1544 }
1545 }
1546 #endif /* OS2 */
1547
1548
1549 /* set termio so we can do our own input processing */
1550 static void
set_termio()1551 set_termio()
1552 {
1553 #if !defined(MSDOS) && !defined(_WIN32)
1554 /* set termio so we can do our own input processing */
1555 /* and save the old terminal modes so we can reset them later */
1556 if (term_set == 0) {
1557 /*
1558 * Get terminal modes.
1559 */
1560 # ifdef SGTTY
1561 ioctl(0, TIOCGETP, &orig_termio);
1562 # else /* not SGTTY */
1563 # ifdef TERMIOS
1564 # ifdef TCGETS
1565 ioctl(0, TCGETS, &orig_termio);
1566 # else /* not TCGETS */
1567 tcgetattr(0, &orig_termio);
1568 # endif /* not TCGETS */
1569 # else /* not TERMIOS */
1570 ioctl(0, TCGETA, &orig_termio);
1571 # endif /* TERMIOS */
1572 # endif /* not SGTTY */
1573
1574 /*
1575 * Save terminal modes
1576 */
1577 rl_termio = orig_termio;
1578
1579 /*
1580 * Set the modes to the way we want them
1581 * and save our input special characters
1582 */
1583 # ifdef SGTTY
1584 rl_termio.sg_flags |= CBREAK;
1585 rl_termio.sg_flags &= ~(ECHO | XTABS);
1586 ioctl(0, TIOCSETN, &rl_termio);
1587
1588 ioctl(0, TIOCGETC, &s_tchars);
1589 term_chars[VERASE] = orig_termio.sg_erase;
1590 term_chars[VEOF] = s_tchars.t_eofc;
1591 term_chars[VKILL] = orig_termio.sg_kill;
1592 # ifdef TIOCGLTC
1593 ioctl(0, TIOCGLTC, &s_ltchars);
1594 term_chars[VWERASE] = s_ltchars.t_werasc;
1595 term_chars[VREPRINT] = s_ltchars.t_rprntc;
1596 term_chars[VSUSP] = s_ltchars.t_suspc;
1597
1598 /* disable suspending process on ^Z */
1599 s_ltchars.t_suspc = 0;
1600 ioctl(0, TIOCSLTC, &s_ltchars);
1601 # endif /* TIOCGLTC */
1602 # else /* not SGTTY */
1603 rl_termio.c_iflag &= ~(BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
1604 rl_termio.c_iflag |= (IGNBRK | IGNPAR);
1605
1606 /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
1607
1608 rl_termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH);
1609 # ifdef OS2
1610 /* for emx: remove default terminal processing */
1611 rl_termio.c_lflag &= ~(IDEFAULT);
1612 # endif /* OS2 */
1613 rl_termio.c_lflag |= (ISIG);
1614 rl_termio.c_cc[VMIN] = 1;
1615 rl_termio.c_cc[VTIME] = 0;
1616
1617 # ifndef VWERASE
1618 # define VWERASE 3
1619 # endif /* VWERASE */
1620 term_chars[VERASE] = orig_termio.c_cc[VERASE];
1621 term_chars[VEOF] = orig_termio.c_cc[VEOF];
1622 term_chars[VKILL] = orig_termio.c_cc[VKILL];
1623 # ifdef TERMIOS
1624 term_chars[VWERASE] = orig_termio.c_cc[VWERASE];
1625 # ifdef VREPRINT
1626 term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
1627 # else /* not VREPRINT */
1628 # ifdef VRPRNT
1629 term_chars[VRPRNT] = orig_termio.c_cc[VRPRNT];
1630 # endif /* VRPRNT */
1631 # endif /* not VREPRINT */
1632 term_chars[VSUSP] = orig_termio.c_cc[VSUSP];
1633
1634 /* disable suspending process on ^Z */
1635 rl_termio.c_cc[VSUSP] = 0;
1636 # endif /* TERMIOS */
1637 # endif /* not SGTTY */
1638
1639 /*
1640 * Set the new terminal modes.
1641 */
1642 # ifdef SGTTY
1643 ioctl(0, TIOCSLTC, &s_ltchars);
1644 # else /* not SGTTY */
1645 # ifdef TERMIOS
1646 # ifdef TCSETSW
1647 ioctl(0, TCSETSW, &rl_termio);
1648 # else /* not TCSETSW */
1649 tcsetattr(0, TCSADRAIN, &rl_termio);
1650 # endif /* not TCSETSW */
1651 # else /* not TERMIOS */
1652 ioctl(0, TCSETAW, &rl_termio);
1653 # endif /* not TERMIOS */
1654 # endif /* not SGTTY */
1655 term_set = 1;
1656 }
1657 #endif /* not MSDOS && not _WIN32 */
1658 }
1659
1660 static void
reset_termio()1661 reset_termio()
1662 {
1663 #if !defined(MSDOS) && !defined(_WIN32)
1664 /* reset saved terminal modes */
1665 if (term_set == 1) {
1666 # ifdef SGTTY
1667 ioctl(0, TIOCSETN, &orig_termio);
1668 # ifdef TIOCGLTC
1669 /* enable suspending process on ^Z */
1670 s_ltchars.t_suspc = term_chars[VSUSP];
1671 ioctl(0, TIOCSLTC, &s_ltchars);
1672 # endif /* TIOCGLTC */
1673 # else /* not SGTTY */
1674 # ifdef TERMIOS
1675 # ifdef TCSETSW
1676 ioctl(0, TCSETSW, &orig_termio);
1677 # else /* not TCSETSW */
1678 tcsetattr(0, TCSADRAIN, &orig_termio);
1679 # endif /* not TCSETSW */
1680 # else /* not TERMIOS */
1681 ioctl(0, TCSETAW, &orig_termio);
1682 # endif /* TERMIOS */
1683 # endif /* not SGTTY */
1684 term_set = 0;
1685 }
1686 #endif /* not MSDOS && not _WIN32 */
1687 }
1688
1689 #endif /* READLINE */
1690