Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / readline.c
diff --git a/src/readline.c b/src/readline.c
new file mode 100644 (file)
index 0000000..c38e980
--- /dev/null
@@ -0,0 +1,1175 @@
+#ifndef lint
+static char *RCSid() { return RCSid("$Id: readline.c,v 1.41.2.2 2008/12/12 06:57:50 sfeam Exp $"); }
+#endif
+
+/* GNUPLOT - readline.c */
+
+/*[
+ * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code.  Modifications are to
+ * be distributed as patches to the released version.  Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ *   1. distribute the corresponding source modifications from the
+ *    released version in the form of a patch file along with the binaries,
+ *   2. add special version identification to distinguish your version
+ *    in addition to the base release version number,
+ *   3. provide your name and address as the primary contact for the
+ *    support of your modified version, and
+ *   4. retain our contact information in regard to use of the base
+ *    software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+
+/*
+ * AUTHORS
+ *
+ *   Original Software:
+ *     Tom Tkacik
+ *
+ *   Msdos port and some enhancements:
+ *     Gershon Elber and many others.
+ *
+ */
+
+#include <signal.h>
+
+#include "stdfn.h"
+#include "readline.h"
+
+#include "alloc.h"
+#include "gp_hist.h"
+#include "plot.h"
+#include "util.h"
+#include "term_api.h"
+
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
+/* #include <readline/readline.h> --- HBB 20000508: now included by readline.h*/
+/* #include <readline/history.h> --- HBB 20000508: now included by gp_hist */
+
+
+static char* line_buffer;
+static int line_complete;
+
+/**
+ * called by libreadline or editline if the input
+ * was typed (not from the ipc).
+ */
+static void
+LineCompleteHandler(char* ptr)
+{
+    rl_callback_handler_remove();
+    line_buffer = ptr;
+    line_complete = 1;
+}
+
+#if defined(HAVE_LIBEDITLINE)
+int
+#else
+static int
+#endif
+#if defined(HAVE_LIBEDITLINE)
+getc_wrapper(FILE* fp /* is NULL, supplied by libedit */)
+#else
+getc_wrapper(FILE* fp /* should be stdin, supplied by readline */)
+#endif
+{
+    int c;
+
+    while (1) {
+#ifdef USE_MOUSE
+       if (term && term->waitforinput && interactive) {
+           c = term->waitforinput();
+       }
+       else
+#endif
+#if defined(HAVE_LIBEDITLINE)
+           c = getchar();
+#else
+           c = getc(fp);
+#endif
+       if (c == EOF && errno == EINTR)
+           continue;
+       return c;
+    }
+}
+
+#endif /* HAVE_LIBREADLINE || HAVE_LIBEDITLINE */
+
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE) || defined(READLINE)
+char*
+readline_ipc(const char* prompt)
+{
+#if defined(PIPE_IPC) && defined(HAVE_LIBREADLINE)
+    /* use readline's alternate interface.
+     * this requires rl_library_version > 2.2
+     * TODO: make a check in configure.in */
+
+    rl_callback_handler_install((char*) prompt, LineCompleteHandler);
+    rl_getc_function = getc_wrapper;
+
+    for (line_complete = 0; !line_complete; /* EMPTY */) {
+       rl_callback_read_char(); /* stdin */
+    }
+    return line_buffer;
+#else
+    return readline((const char*) prompt);
+#endif
+}
+#endif  /* defined(HAVE_LIBREADLINE) || define(READLINE) */
+
+
+#if defined(READLINE) && !(defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE))
+
+/* a small portable version of GNU's readline
+ * this is not the BASH or GNU EMACS version of READLINE due to Copyleft
+ * restrictions
+ * do not need any terminal capabilities except backspace,
+ * and space overwrites a character
+ */
+
+/* NANO-EMACS line editing facility
+ * printable characters print as themselves (insert not overwrite)
+ * ^A moves to the beginning of the line
+ * ^B moves back a single character
+ * ^E moves to the end of the line
+ * ^F moves forward a single character
+ * ^K kills from current position to the end of line
+ * ^P moves back through history
+ * ^N moves forward through history
+ * ^H and DEL delete the previous character
+ * ^D deletes the current character, or EOF if line is empty
+ * ^L/^R redraw line in case it gets trashed
+ * ^U kills the entire line
+ * ^W kills last word
+ * LF and CR return the entire line regardless of the cursor postition
+ * EOF with an empty line returns (char *)NULL
+ *
+ * all other characters are ignored
+ */
+
+#ifdef HAVE_SYS_IOCTL_H
+/* For ioctl() prototype under Linux (and BeOS?) */
+# include <sys/ioctl.h>
+#endif
+
+/* replaces the previous klugde in configure */
+#if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR)
+# define TERMIOS
+#else /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
+# ifdef HAVE_SGTTY_H
+#  define SGTTY
+# endif
+#endif /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
+
+#if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386) && !defined(OSK)
+
+/*
+ * Set up structures using the proper include file
+ */
+# if defined(_IBMR2) || defined(alliant)
+#  define SGTTY
+# endif
+
+/*  submitted by Francois.Dagorn@cicb.fr */
+# ifdef SGTTY
+#  include <sgtty.h>
+static struct sgttyb orig_termio, rl_termio;
+/* define terminal control characters */
+static struct tchars s_tchars;
+#  ifndef VERASE
+#   define VERASE    0
+#  endif                       /* not VERASE */
+#  ifndef VEOF
+#   define VEOF      1
+#  endif                       /* not VEOF */
+#  ifndef VKILL
+#   define VKILL     2
+#  endif                       /* not VKILL */
+#  ifdef TIOCGLTC              /* available only with the 'new' line discipline */
+static struct ltchars s_ltchars;
+#   ifndef VWERASE
+#    define VWERASE   3
+#   endif                      /* not VWERASE */
+#   ifndef VREPRINT
+#    define VREPRINT  4
+#   endif                      /* not VREPRINT */
+#   ifndef VSUSP
+#    define VSUSP     5
+#   endif                      /* not VSUP */
+#  endif                       /* TIOCGLTC */
+#  ifndef NCCS
+#   define NCCS      6
+#  endif                       /* not NCCS */
+
+# else                         /* not SGTTY */
+
+/* SIGTSTP defines job control
+ * if there is job control then we need termios.h instead of termio.h
+ * (Are there any systems with job control that use termio.h?  I hope not.)
+ */
+#  if defined(SIGTSTP) || defined(TERMIOS)
+#   ifndef TERMIOS
+#    define TERMIOS
+#   endif                      /* not TERMIOS */
+#   include <termios.h>
+/* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
+#   ifdef ISC22
+#    ifndef ONOCR              /* taken from sys/termio.h */
+#     define ONOCR 0000020     /* true at least for ISC 2.2 */
+#    endif                     /* not ONOCR */
+#    ifndef IUCLC
+#     define IUCLC 0001000
+#    endif                     /* not IUCLC */
+#   endif                      /* ISC22 */
+#   if !defined(IUCLC)
+     /* translate upper to lower case not supported */
+#    define IUCLC 0
+#   endif                      /* not IUCLC */
+
+static struct termios orig_termio, rl_termio;
+#  else                                /* not SIGSTP || TERMIOS */
+#   include <termio.h>
+static struct termio orig_termio, rl_termio;
+/* termio defines NCC instead of NCCS */
+#   define NCCS    NCC
+#  endif                       /* not SIGTSTP || TERMIOS */
+# endif                                /* SGTTY */
+
+/* ULTRIX defines VRPRNT instead of VREPRINT */
+# if defined(VRPRNT) && !defined(VREPRINT)
+#  define VREPRINT VRPRNT
+# endif                                /* VRPRNT */
+
+/* define characters to use with our input character handler */
+static char term_chars[NCCS];
+
+static int term_set = 0;       /* =1 if rl_termio set */
+
+#define special_getc() ansi_getc()
+static int ansi_getc __PROTO((void));
+
+#else /* MSDOS or ATARI or MTOS or _Windows or DOS386 or OSK */
+
+# ifdef _Windows
+#  include <windows.h>
+#  include "win/wtext.h"
+#  include "win/winmain.h"
+#  define TEXTUSER 0xf1
+#  define TEXTGNUPLOT 0xf0
+#  define special_getc() msdos_getch()
+static char msdos_getch __PROTO((void));       /* HBB 980308: PROTO'ed it */
+# endif                                /* _Windows */
+
+# if defined(MSDOS) || defined(DOS386)
+/* MSDOS specific stuff */
+#  ifdef DJGPP
+#   include <pc.h>
+#  endif                       /* DJGPP */
+#  if defined(__EMX__) || defined (__WATCOMC__)
+#   include <conio.h>
+#  endif                       /* __EMX__ */
+#  define special_getc() msdos_getch()
+static char msdos_getch();
+# endif                                /* MSDOS || DOS386 */
+
+# ifdef OSK
+#  include <sgstat.h>
+#  include <modes.h>
+
+#  define STDIN        0
+static int term_set = 0;       /* =1 if new_settings is set */
+
+static struct _sgs old_settings;       /* old terminal settings        */
+static struct _sgs new_settings;       /* new terminal settings        */
+
+#  define special_getc() ansi_getc()
+static int ansi_getc __PROTO((void));
+
+/* On OS9 a '\n' is a character 13 and '\r' == '\n'. This gives troubles
+   here, so we need a new putc wich handles this correctly and print a
+   character 10 on each place we want a '\n'.
+ */
+#  undef putc                  /* Undefine the macro for putc */
+
+static int
+putc(char c, FILE *fp)
+{
+    write(fileno(fp), &c, 1);
+    if (c == '\012') {         /* A normal ASCII '\n' */
+       c = '\r';
+       write(fileno(fp), &c, 1);
+    }
+}
+
+# endif                                /* OSK */
+
+# if defined(ATARI) || defined(MTOS)
+#  define special_getc() tos_getch()
+# endif                                /* ATARI || MTOS */
+
+#endif /* MSDOS or ATARI or MTOS or _Windows or DOS386 or OSK */
+
+#ifdef OS2
+# if defined( special_getc )
+#  undef special_getc()
+# endif                                /* special_getc */
+# define special_getc() os2_getch()
+static char msdos_getch __PROTO((void));       /* HBB 980308: PROTO'ed it */
+static char os2_getch __PROTO((void));
+#endif /* OS2 */
+
+
+/* initial size and increment of input line length */
+#define MAXBUF 1024
+#define BACKSPACE 0x08   /* ^H */
+#define SPACE  ' '
+
+#ifdef OSK
+# define NEWLINE       '\012'
+#else /* OSK */
+# define NEWLINE       '\n'
+#endif /* not OSK */
+
+static char *cur_line;         /* current contents of the line */
+static size_t line_len = 0;
+static size_t cur_pos = 0;     /* current position of the cursor */
+static size_t max_pos = 0;     /* maximum character position */
+
+static void fix_line __PROTO((void));
+static void redraw_line __PROTO((const char *prompt));
+static void clear_line __PROTO((const char *prompt));
+static void clear_eoline __PROTO((void));
+static void copy_line __PROTO((char *line));
+static void set_termio __PROTO((void));
+static void reset_termio __PROTO((void));
+static int user_putc __PROTO((int ch));
+static int user_puts __PROTO((char *str));
+static void backspace __PROTO((void));
+static void extend_cur_line __PROTO((void));
+
+
+/* user_putc and user_puts should be used in the place of
+ * fputc(ch,stderr) and fputs(str,stderr) for all output
+ * of user typed characters.  This allows MS-Windows to
+ * display user input in a different color.
+ */
+static int
+user_putc(int ch)
+{
+    int rv;
+#ifdef _Windows
+    TextAttr(&textwin, TEXTUSER);
+#endif
+    rv = fputc(ch, stderr);
+#ifdef _Windows
+    TextAttr(&textwin, TEXTGNUPLOT);
+#endif
+    return rv;
+}
+
+static int
+user_puts(char *str)
+{
+    int rv;
+#ifdef _Windows
+    TextAttr(&textwin, TEXTUSER);
+#endif
+    rv = fputs(str, stderr);
+#ifdef _Windows
+    TextAttr(&textwin, TEXTGNUPLOT);
+#endif
+    return rv;
+}
+
+/* This function provides a centralized non-destructive backspace capability
+ * M. Castro
+ */
+static void
+backspace()
+{
+    user_putc(BACKSPACE);
+}
+
+static void
+extend_cur_line()
+{
+    char *new_line;
+
+    /* extent input line length */
+    new_line = gp_realloc(cur_line, line_len + MAXBUF, NULL);
+    if (!new_line) {
+       reset_termio();
+       int_error(NO_CARET, "Can't extend readline length");
+    }
+    cur_line = new_line;
+    line_len += MAXBUF;
+    FPRINTF((stderr, "\nextending readline length to %d chars\n", line_len));
+}
+
+char *
+readline(const char *prompt)
+{
+    int cur_char;
+    char *new_line;
+
+
+    /* start with a string of MAXBUF chars */
+    if (line_len != 0) {
+       free(cur_line);
+       line_len = 0;
+    }
+    cur_line = gp_alloc(MAXBUF, "readline");
+    line_len = MAXBUF;
+
+    /* set the termio so we can do our own input processing */
+    set_termio();
+
+    /* print the prompt */
+    fputs(prompt, stderr);
+    cur_line[0] = '\0';
+    cur_pos = 0;
+    max_pos = 0;
+    cur_entry = NULL;
+
+    /* get characters */
+    for (;;) {
+
+       cur_char = special_getc();
+
+       /* The #define CHARSET7BIT should be used when one encounters
+        * problems with 8bit characters that should not be entered on
+        * the commandline. I cannot think on any reasonable example
+        * where this could happen, but what do I know?  After all,
+        * the unix world still ignores 8bit chars in most
+        * applications.
+        *
+        * Note that latin1 defines the chars 0x80-0x9f as control
+        * chars. For the benefit of Atari, MSDOS, Windows and NeXT I
+        * have decided to ignore this, since it would require more
+        * #ifs. */
+
+       if (isprint(cur_char)
+#ifndef CHARSET7BIT
+           /* || ((unsigned char) cur_char == 011) */ /* EAM allowing <tab> breaks auto-completion! */
+           || (((unsigned char) cur_char > 0x7f) && cur_char != EOF)
+#endif /* CHARSET7BIT */
+           ) {
+           size_t i;
+
+           if (max_pos + 1 >= line_len) {
+               extend_cur_line();
+           }
+           for (i = max_pos; i > cur_pos; i--) {
+               cur_line[i] = cur_line[i - 1];
+           }
+           user_putc(cur_char);
+           cur_line[cur_pos] = cur_char;
+           cur_pos += 1;
+           max_pos += 1;
+           if (cur_pos < max_pos)
+               fix_line();
+           cur_line[max_pos] = '\0';
+
+           /* else interpret unix terminal driver characters */
+#ifdef VERASE
+       } else if (cur_char == term_chars[VERASE]) {    /* DEL? */
+           if (cur_pos > 0) {
+               size_t i;
+               cur_pos -= 1;
+               backspace();
+               for (i = cur_pos; i < max_pos; i++)
+                   cur_line[i] = cur_line[i + 1];
+               max_pos -= 1;
+               fix_line();
+           }
+#endif /* VERASE */
+#ifdef VEOF
+       } else if (cur_char == term_chars[VEOF]) {      /* ^D? */
+           if (max_pos == 0) {
+               reset_termio();
+               return ((char *) NULL);
+           }
+           if ((cur_pos < max_pos) && (cur_char == 004)) {     /* ^D */
+               size_t i;
+               for (i = cur_pos; i < max_pos; i++)
+                   cur_line[i] = cur_line[i + 1];
+               max_pos -= 1;
+               fix_line();
+           }
+#endif /* VEOF */
+#ifdef VKILL
+       } else if (cur_char == term_chars[VKILL]) {     /* ^U? */
+           clear_line(prompt);
+#endif /* VKILL */
+#ifdef VWERASE
+       } else if (cur_char == term_chars[VWERASE]) {   /* ^W? */
+           while ((cur_pos > 0) &&
+                  (cur_line[cur_pos - 1] == SPACE)) {
+               cur_pos -= 1;
+               backspace();
+           }
+           while ((cur_pos > 0) &&
+                  (cur_line[cur_pos - 1] != SPACE)) {
+               cur_pos -= 1;
+               backspace();
+           }
+           clear_eoline();
+           max_pos = cur_pos;
+#endif /* VWERASE */
+#ifdef VREPRINT
+       } else if (cur_char == term_chars[VREPRINT]) {  /* ^R? */
+           putc(NEWLINE, stderr);      /* go to a fresh line */
+           redraw_line(prompt);
+#endif /* VREPRINT */
+#ifdef VSUSP
+       } else if (cur_char == term_chars[VSUSP]) {
+           reset_termio();
+           kill(0, SIGTSTP);
+
+           /* process stops here */
+
+           set_termio();
+           /* print the prompt */
+           redraw_line(prompt);
+#endif /* VSUSP */
+       } else {
+           /* do normal editing commands */
+           /* some of these are also done above */
+           size_t i;
+           switch (cur_char) {
+           case EOF:
+               reset_termio();
+               return ((char *) NULL);
+           case 001:           /* ^A */
+               while (cur_pos > 0) {
+                   cur_pos -= 1;
+                   backspace();
+               }
+               break;
+           case 002:           /* ^B */
+               if (cur_pos > 0) {
+                   cur_pos -= 1;
+                   backspace();
+               }
+               break;
+           case 005:           /* ^E */
+               while (cur_pos < max_pos) {
+                   user_putc(cur_line[cur_pos]);
+                   cur_pos += 1;
+               }
+               break;
+           case 006:           /* ^F */
+               if (cur_pos < max_pos) {
+                   user_putc(cur_line[cur_pos]);
+                   cur_pos += 1;
+               }
+               break;
+           case 013:           /* ^K */
+               clear_eoline();
+               max_pos = cur_pos;
+               break;
+           case 020:           /* ^P */
+               if (history != NULL) {
+                   if (cur_entry == NULL) {
+                       cur_entry = history;
+                       clear_line(prompt);
+                       copy_line(cur_entry->line);
+                   } else if (cur_entry->prev != NULL) {
+                       cur_entry = cur_entry->prev;
+                       clear_line(prompt);
+                       copy_line(cur_entry->line);
+                   }
+               }
+               break;
+           case 016:           /* ^N */
+               if (cur_entry != NULL) {
+                   cur_entry = cur_entry->next;
+                   clear_line(prompt);
+                   if (cur_entry != NULL)
+                       copy_line(cur_entry->line);
+                   else
+                       cur_pos = max_pos = 0;
+               }
+               break;
+           case 014:           /* ^L */
+           case 022:           /* ^R */
+               putc(NEWLINE, stderr);  /* go to a fresh line */
+               redraw_line(prompt);
+               break;
+           case 0177:          /* DEL */
+           case 010:           /* ^H */
+               if (cur_pos > 0) {
+                   cur_pos -= 1;
+                   backspace();
+                   for (i = cur_pos; i < max_pos; i++)
+                       cur_line[i] = cur_line[i + 1];
+                   max_pos -= 1;
+                   fix_line();
+               }
+               break;
+           case 004:           /* ^D */
+               if (max_pos == 0) {
+                   reset_termio();
+                   return ((char *) NULL);
+               }
+               if (cur_pos < max_pos) {
+                   for (i = cur_pos; i < max_pos; i++)
+                       cur_line[i] = cur_line[i + 1];
+                   max_pos -= 1;
+                   fix_line();
+               }
+               break;
+           case 025:           /* ^U */
+               clear_line(prompt);
+               break;
+           case 027:           /* ^W */
+               while ((cur_pos > 0) &&
+                      (cur_line[cur_pos - 1] == SPACE)) {
+                   cur_pos -= 1;
+                   backspace();
+               }
+               while ((cur_pos > 0) &&
+                      (cur_line[cur_pos - 1] != SPACE)) {
+                   cur_pos -= 1;
+                   backspace();
+               }
+               clear_eoline();
+               max_pos = cur_pos;
+               break;
+           case '\n':          /* ^J */
+#ifndef OSK
+           case '\r':          /* ^M */
+#endif
+               cur_line[max_pos + 1] = '\0';
+#ifdef OS2
+               while (cur_pos < max_pos) {
+                   user_putc(cur_line[cur_pos]);
+                   cur_pos += 1;
+               }
+#endif
+               putc(NEWLINE, stderr);
+
+               /* Shrink the block down to fit the string ?
+                * if the alloc fails, we still own block at cur_line,
+                * but this shouldn't really fail.
+                */
+               new_line = (char *) gp_realloc(cur_line, strlen(cur_line) + 1,
+                                              "line resize");
+               if (new_line)
+                   cur_line = new_line;
+               /* else we just hang on to what we had - it's not a problem */
+
+               line_len = 0;
+               FPRINTF((stderr, "Resizing input line to %d chars\n", strlen(cur_line)));
+               reset_termio();
+               return (cur_line);
+           default:
+               break;
+           }
+       }
+    }
+}
+
+/* fix up the line from cur_pos to max_pos
+ * do not need any terminal capabilities except backspace,
+ * and space overwrites a character
+ */
+static void
+fix_line()
+{
+    size_t i;
+
+    /* write tail of string */
+    for (i = cur_pos; i < max_pos; i++)
+       user_putc(cur_line[i]);
+
+    /* write a space at the end of the line in case we deleted one */
+    user_putc(SPACE);
+
+    /* backup to original position */
+    for (i = max_pos + 1; i > cur_pos; i--)
+       backspace();
+
+}
+
+/* redraw the entire line, putting the cursor where it belongs */
+static void
+redraw_line(const char *prompt)
+{
+    size_t i;
+
+    fputs(prompt, stderr);
+    user_puts(cur_line);
+
+    /* put the cursor where it belongs */
+    for (i = max_pos; i > cur_pos; i--)
+       backspace();
+}
+
+/* clear cur_line and the screen line */
+static void
+clear_line(const char *prompt)
+{
+    size_t i;
+    for (i = 0; i < max_pos; i++)
+       cur_line[i] = '\0';
+
+    for (i = cur_pos; i > 0; i--)
+       backspace();
+
+    for (i = 0; i < max_pos; i++)
+       putc(SPACE, stderr);
+
+    putc('\r', stderr);
+    fputs(prompt, stderr);
+
+    cur_pos = 0;
+    max_pos = 0;
+}
+
+/* clear to end of line and the screen end of line */
+static void
+clear_eoline()
+{
+    size_t i;
+    for (i = cur_pos; i < max_pos; i++)
+       cur_line[i] = '\0';
+
+    for (i = cur_pos; i < max_pos; i++)
+       putc(SPACE, stderr);
+    for (i = cur_pos; i < max_pos; i++)
+       backspace();
+}
+
+/* copy line to cur_line, draw it and set cur_pos and max_pos */
+static void
+copy_line(char *line)
+{
+    while (strlen(line) + 1 > line_len) {
+       extend_cur_line();
+    }
+    strcpy(cur_line, line);
+    user_puts(cur_line);
+    cur_pos = max_pos = strlen(cur_line);
+}
+
+#if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386) && !defined(OSK)
+/* Convert ANSI arrow keys to control characters */
+static int
+ansi_getc()
+{
+    int c;
+
+#ifdef USE_MOUSE
+    if (term && term->waitforinput && interactive)
+       c = term->waitforinput();
+    else
+#endif
+    c = getc(stdin);
+
+    if (c == 033) {
+       c = getc(stdin);        /* check for CSI */
+       if (c == '[') {
+           c = getc(stdin);    /* get command character */
+           switch (c) {
+           case 'D':           /* left arrow key */
+               c = 002;
+               break;
+           case 'C':           /* right arrow key */
+               c = 006;
+               break;
+           case 'A':           /* up arrow key */
+               c = 020;
+               break;
+           case 'B':           /* down arrow key */
+               c = 016;
+               break;
+           case 'F':           /* end key */
+               c = 005;
+               break;
+           case 'H':           /* home key */
+               c = 001;
+               break;
+           }
+       }
+    }
+    return c;
+}
+#endif
+
+#if defined(MSDOS) || defined(_Windows) || defined(DOS386) || defined(OS2)
+
+/* Convert Arrow keystrokes to Control characters: */
+static char
+msdos_getch()
+{
+       char c;
+       
+#ifdef DJGPP
+    int ch = getkey();
+    c = (ch & 0xff00) ? 0 : ch & 0xff;
+#elif defined (OS2)
+    c = getc(stdin);
+#else /* not OS2, not DJGPP*/
+# if defined (_Windows) && defined (USE_MOUSE)
+    if (term && term->waitforinput && interactive)
+       c = term->waitforinput();
+    else
+# endif /* not _Windows && not USE_MOUSE */
+    c = getch();
+#endif /* not DJGPP, not OS2 */
+
+    if (c == 0) {
+#ifdef DJGPP
+       c = ch & 0xff;
+#else /* not DJGPP */
+# ifdef OS2
+       c = getc(stdin);
+# else                         /* not OS2 */
+       c = getch();            /* Get the extended code. */
+# endif                                /* OS2 */
+#endif /* not DJGPP */
+
+       switch (c) {
+       case 75:                /* Left Arrow. */
+           c = 002;
+           break;
+       case 77:                /* Right Arrow. */
+           c = 006;
+           break;
+       case 72:                /* Up Arrow. */
+           c = 020;
+           break;
+       case 80:                /* Down Arrow. */
+           c = 016;
+           break;
+       case 115:               /* Ctl Left Arrow. */
+       case 71:                /* Home */
+           c = 001;
+           break;
+       case 116:               /* Ctl Right Arrow. */
+       case 79:                /* End */
+           c = 005;
+           break;
+       case 83:                /* Delete */
+           c = 004;
+           break;
+       default:
+           c = 0;
+           break;
+       }
+    } else if (c == 033) {     /* ESC */
+       c = 025;
+    }
+    return c;
+}
+
+#endif /* MSDOS || _Windows || DOS386 || OS2 */
+
+#ifdef OS2
+/* We need to call different procedures, dependent on the
+   session type: VIO/window or an (XFree86) xterm */
+static char
+os2_getch() {
+  static int IsXterm = 0;
+  static int init = 0;
+
+  if (!init) {
+     if (getenv("WINDOWID")) {
+        IsXterm = 1;
+     }
+     init = 1;
+  }
+  if (IsXterm) {
+     return ansi_getc();
+  } else {
+     return msdos_getch();
+  }
+}
+#endif /* OS2 */
+
+#if defined(ATARI) || defined(MTOS)
+
+/* Convert Arrow keystrokes to Control characters: TOS version */
+
+/* from term/atariaes.trm: */
+long poll_events(int);
+
+/* this function is used in help.c as well. this means that the
+ * program doesn't work without -DREADLINE (which would be the case
+ * if help.c didn't use it as well, since no events would be processed)
+ */
+char
+tos_getch()
+{
+    long rawkey;
+    char c;
+    int scan_code;
+    static int in_help = 0;
+
+    if (strcmp(term->name, "atari") == 0)
+       poll_events(0);
+
+    if (in_help) {
+       switch (in_help) {
+       case 1:
+       case 5:
+           in_help++;
+           return 'e';
+       case 2:
+       case 6:
+           in_help++;
+           return 'l';
+       case 3:
+       case 7:
+           in_help++;
+           return 'p';
+       case 4:
+           in_help = 0;
+           return 0x0d;
+       case 8:
+           in_help = 0;
+           return ' ';
+       }
+    }
+    if (strcmp(term->name, "atari") == 0) {
+       do {
+           if (Bconstat(2))
+               rawkey = Cnecin();
+           else
+               rawkey = poll_events(1);
+       } while (rawkey == 0);
+    } else
+       rawkey = Cnecin();
+
+    c = (char) rawkey;
+    scan_code = ((int) (rawkey >> 16)) & 0xff; /* get the scancode */
+    if (Kbshift(-1) & 0x00000007)
+       scan_code |= 0x80;      /* shift or control ? */
+
+    switch (scan_code) {
+    case 0x62:                 /* HELP         */
+    case 0xe2:                 /* shift HELP   */
+       if (max_pos == 0) {
+           if (scan_code == 0x62) {
+               in_help = 1;
+           } else {
+               in_help = 5;
+           }
+           return 'h';
+       } else {
+           return 0;
+       }
+    case 0x48:                 /* Up Arrow */
+       return 0x10;            /* ^P */
+    case 0x50:                 /* Down Arrow */
+       return 0x0e;            /* ^N */
+    case 0x4b:                 /* Left Arrow */
+       return 0x02;            /* ^B */
+    case 0x4d:                 /* Right Arrow */
+       return 0x06;            /* ^F */
+    case 0xcb:                 /* Shift Left Arrow */
+    case 0xf3:                 /* Ctrl Left Arrow (TOS-bug ?) */
+    case 0x47:                 /* Home */
+       return 0x01;            /* ^A */
+    case 0xcd:                 /* Shift Right Arrow */
+    case 0xf4:                 /* Ctrl Right Arrow (TOS-bug ?) */
+    case 0xc7:                 /* Shift Home */
+    case 0xf7:                 /* Ctrl Home */
+       return 0x05;            /* ^E */
+    case 0x61:                 /* Undo - redraw line */
+       return 0x0c;            /* ^L */
+    default:
+       if (c == 0x1b)
+           return 0x15;        /* ESC becomes ^U */
+       if (c == 0x7f)
+           return 0x04;        /* Del becomes ^D */
+       break;
+    }
+    return c;
+}
+
+#endif /* ATARI || MTOS */
+
+  /* set termio so we can do our own input processing */
+static void
+set_termio()
+{
+#if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386)
+/* set termio so we can do our own input processing */
+/* and save the old terminal modes so we can reset them later */
+    if (term_set == 0) {
+       /*
+        * Get terminal modes.
+        */
+# ifndef OSK
+#  ifdef SGTTY
+       ioctl(0, TIOCGETP, &orig_termio);
+#  else                                /* not SGTTY */
+#   ifdef TERMIOS
+#    ifdef TCGETS
+       ioctl(0, TCGETS, &orig_termio);
+#    else                      /* not TCGETS */
+       tcgetattr(0, &orig_termio);
+#    endif                     /* not TCGETS */
+#   else                       /* not TERMIOS */
+       ioctl(0, TCGETA, &orig_termio);
+#   endif                      /* TERMIOS */
+#  endif                       /* not SGTTY */
+# else                         /* OSK */
+       setbuf(stdin, (char *) 0);      /* Make stdin and stdout unbuffered */
+       setbuf(stderr, (char *) 0);
+       _gs_opt(STDIN, &new_settings);
+# endif                                /* OSK */
+
+       /*
+        * Save terminal modes
+        */
+# ifndef OSK
+       rl_termio = orig_termio;
+# else                         /* OSK */
+       _gs_opt(STDIN, &old_settings);
+# endif                                /* OSK */
+
+       /*
+        * Set the modes to the way we want them
+        *  and save our input special characters
+        */
+# ifndef OSK
+#  ifdef SGTTY
+       rl_termio.sg_flags |= CBREAK;
+       rl_termio.sg_flags &= ~(ECHO | XTABS);
+       ioctl(0, TIOCSETN, &rl_termio);
+
+       ioctl(0, TIOCGETC, &s_tchars);
+       term_chars[VERASE] = orig_termio.sg_erase;
+       term_chars[VEOF] = s_tchars.t_eofc;
+       term_chars[VKILL] = orig_termio.sg_kill;
+#   ifdef TIOCGLTC
+       ioctl(0, TIOCGLTC, &s_ltchars);
+       term_chars[VWERASE] = s_ltchars.t_werasc;
+       term_chars[VREPRINT] = s_ltchars.t_rprntc;
+       term_chars[VSUSP] = s_ltchars.t_suspc;
+
+       /* disable suspending process on ^Z */
+       s_ltchars.t_suspc = 0;
+       ioctl(0, TIOCSLTC, &s_ltchars);
+#   endif                      /* TIOCGLTC */
+#  else                                /* not SGTTY */
+       rl_termio.c_iflag &= ~(BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
+       rl_termio.c_iflag |= (IGNBRK | IGNPAR);
+
+       /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
+
+       rl_termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH);
+#   ifdef OS2
+       /* for emx: remove default terminal processing */
+       rl_termio.c_lflag &= ~(IDEFAULT);
+#   endif                      /* OS2 */
+       rl_termio.c_lflag |= (ISIG);
+       rl_termio.c_cc[VMIN] = 1;
+       rl_termio.c_cc[VTIME] = 0;
+
+#   ifndef VWERASE
+#    define VWERASE 3
+#   endif                      /* VWERASE */
+       term_chars[VERASE] = orig_termio.c_cc[VERASE];
+       term_chars[VEOF] = orig_termio.c_cc[VEOF];
+       term_chars[VKILL] = orig_termio.c_cc[VKILL];
+#   ifdef TERMIOS
+       term_chars[VWERASE] = orig_termio.c_cc[VWERASE];
+#    ifdef VREPRINT
+       term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
+#    else                      /* not VREPRINT */
+#     ifdef VRPRNT
+       term_chars[VRPRNT] = orig_termio.c_cc[VRPRNT];
+#     endif                    /* VRPRNT */
+#    endif                     /* not VREPRINT */
+       term_chars[VSUSP] = orig_termio.c_cc[VSUSP];
+
+       /* disable suspending process on ^Z */
+       rl_termio.c_cc[VSUSP] = 0;
+#   endif                      /* TERMIOS */
+#  endif                       /* not SGTTY */
+# else                         /* OSK */
+       new_settings._sgs_echo = 0;     /* switch off terminal echo */
+       new_settings._sgs_pause = 0;    /* inhibit page pause */
+       new_settings._sgs_eofch = 0;    /* inhibit eof  */
+       new_settings._sgs_kbich = 0;    /* inhibit ^C   */
+       new_settings._sgs_kbach = 0;    /* inhibit ^E   */
+# endif                                /* OSK */
+
+       /*
+        * Set the new terminal modes.
+        */
+# ifndef OSK
+#  ifdef SGTTY
+       ioctl(0, TIOCSLTC, &s_ltchars);
+#  else                                /* not SGTTY */
+#   ifdef TERMIOS
+#    ifdef TCSETSW
+       ioctl(0, TCSETSW, &rl_termio);
+#    else                      /* not TCSETSW */
+       tcsetattr(0, TCSADRAIN, &rl_termio);
+#    endif                     /* not TCSETSW */
+#   else                       /* not TERMIOS */
+       ioctl(0, TCSETAW, &rl_termio);
+#   endif                      /* not TERMIOS */
+#  endif                       /* not SGTTY */
+# else                         /* OSK */
+       _ss_opt(STDIN, &new_settings);
+# endif                                /* OSK */
+       term_set = 1;
+    }
+#endif /* not MSDOS && not ATARI && not MTOS && not _Windows && not DOS386 */
+}
+
+static void
+reset_termio()
+{
+#if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386)
+/* reset saved terminal modes */
+    if (term_set == 1) {
+# ifndef OSK
+#  ifdef SGTTY
+       ioctl(0, TIOCSETN, &orig_termio);
+#   ifdef TIOCGLTC
+       /* enable suspending process on ^Z */
+       s_ltchars.t_suspc = term_chars[VSUSP];
+       ioctl(0, TIOCSLTC, &s_ltchars);
+#   endif                      /* TIOCGLTC */
+#  else                                /* not SGTTY */
+#   ifdef TERMIOS
+#    ifdef TCSETSW
+       ioctl(0, TCSETSW, &orig_termio);
+#    else                      /* not TCSETSW */
+       tcsetattr(0, TCSADRAIN, &orig_termio);
+#    endif                     /* not TCSETSW */
+#   else                       /* not TERMIOS */
+       ioctl(0, TCSETAW, &orig_termio);
+#   endif                      /* TERMIOS */
+#  endif                       /* not SGTTY */
+# else                         /* OSK */
+       _ss_opt(STDIN, &old_settings);
+# endif                                /* OSK */
+       term_set = 0;
+    }
+#endif /* not MSDOS && not ATARI && not MTOS && not _Windows && not DOS386 */
+}
+
+#endif /* READLINE && !HAVE_LIBREADLINE */