#ifndef lint
static char *RCSid = "$Id: readline.c,v 1.57 1995/06/14 12:17:52 drd Exp $";
#endif


/* GNUPLOT - readline.c */
/*
 * Copyright (C) 1986 - 1993   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 modified code.  Modifications are to be distributed 
 * as patches to released version.
 *  
 * This software is provided "as is" without express or implied warranty.
 * 
 *
 * AUTHORS
 *
 *   Original Software:
 *     Tom Tkacik
 *
 *   Msdos port and some enhancements:
 *     Gershon Elber and many others.
 * 
 * There is a mailing list for gnuplot users. Note, however, that the
 * newsgroup 
 *	comp.graphics.gnuplot 
 * is identical to the mailing list (they
 * both carry the same set of messages). We prefer that you read the
 * messages through that newsgroup, to subscribing to the mailing list.
 * (If you can read that newsgroup, and are already on the mailing list,
 * please send a message info-gnuplot-request@dartmouth.edu, asking to be
 * removed from the mailing list.)
 *
 * The address for mailing to list members is
 *	   info-gnuplot@dartmouth.edu
 * and for mailing administrative requests is 
 *	   info-gnuplot-request@dartmouth.edu
 * The mailing list for bug reports is 
 *	   bug-gnuplot@dartmouth.edu
 * The list of those interested in beta-test versions is
 *	   info-gnuplot-beta@dartmouth.edu
 */

#if defined(READLINE) && !defined(GNU_READLINE)

#ifdef _WINDOWS
#define _Windows
#endif


/* 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 */

#include <ctype.h>
#include <signal.h>
#include "plot.h" /* get prototype for alloc and gpfaralloc */
#include "stdfn.h"

#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
#ifndef VEOF
#define VEOF      1
#endif
#ifndef VKILL
#define VKILL     2
#endif
#ifdef TIOCGLTC		 /* available only with the 'new' line discipline */
static struct ltchars s_ltchars;
#ifndef VWERASE
#define VWERASE   3
#endif
#ifndef VREPRINT
#define VREPRINT  4
#endif
#ifndef VSUSP
#define VSUSP     5
#endif
#endif /* TIOCGLTC */
#ifndef NCCS
#define NCCS      6
#endif

#else /* 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
#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 
#ifndef IUCLC
#define IUCLC 0001000
#endif
#endif /* ISC22 */
#if defined(NEXT) && !defined(IUCLC)
#define IUCLC 0 /* no idea what this flag does */
#endif

static struct termios orig_termio, rl_termio;
#else
#include <termio.h>
static struct termio orig_termio, rl_termio;
/* termio defines NCC instead of NCCS */
#define NCCS    NCC
#endif /* SIGTSTP */
#endif /* SGTTY */

/* ULTRIX defines VRPRNT instead of VREPRINT */
#if defined(VRPRNT) && !defined(VREPRINT)
#define VREPRINT VRPRNT
#endif

/* 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();

#else /* !MSDOS && !ATARI && !_Windows */

#ifdef _Windows
#include <windows.h>
#include "win/wtext.h"
#include "win/wgnuplib.h"
extern TW textwin;
#define TEXTUSER 0xf1
#define TEXTGNUPLOT 0xf0
#define special_getc() msdos_getch()
static char msdos_getch();
#endif

#if defined(MSDOS) || defined(DOS386)
/* MSDOS specific stuff */
#ifdef DJGPP
#include <pc.h>
#endif
#ifdef __EMX__
#include <conio.h>
#endif
#define special_getc() msdos_getch()
static char msdos_getch();
#endif /* MSDOS */

#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();

/* 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 (c,fp)
	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)
#ifdef __PUREC__
#include <tos.h>
#else
#include <osbind.h>
#endif
#define special_getc() tos_getch()
char tos_getch();
#endif

#endif /* !MSDOS && !ATARI && !MTOS && !_Windows && !OSK*/

#ifdef OS2
#define special_getc() msdos_getch()
static char msdos_getch();
#endif


#define MAXBUF	1024	/* initial size and increment of input line length */
#define BACKSPACE 0x08	/* ^H */
#define SPACE	' '
#ifdef OSK
#define NEWLINE	'\012'
#else
#define NEWLINE	'\n'
#endif

struct hist {
	char *line;
	struct hist *prev;
	struct hist *next;
};

static struct hist *history = NULL;  /* no history yet */
static struct hist *cur_entry = NULL;

static char *cur_line;  /* current contents of the line */
static int line_len=0;
static int cur_pos = 0;	/* current position of the cursor */
static int max_pos = 0;	/* maximum character position */


static void fix_line __P((void));
static void redraw_line __P((char *prompt));
static void clear_line __P((char *prompt));
static void clear_eoline __P((void));
static void copy_line __P((char *line));
static void set_termio __P((void));
static void reset_termio __P((void));
static int ansi_getc __P((void));
static int user_putc __P((int ch));
static int user_puts __P((char *str));
static void backspace __P((void));
static void extend_cur_line __P((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(ch)
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(str)
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=ralloc(cur_line, line_len+MAXBUF, NULL);
  if(!new_line) {
    reset_termio();
    int_error("Can't extend readline length", NO_CARET);
  }
  cur_line=new_line;
  line_len+=MAXBUF;
#ifdef DEBUG_STR
  fprintf(stderr, "\nextending readline length to %d chars\n", line_len);
#endif
}

char *
readline(prompt)
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=alloc((unsigned long)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.
 *
 */

#ifdef CHARSET7BIT
		if(isprint(cur_char)) {
#else  /* CHARSET7BIT */
		if(isprint(cur_char) || (((unsigned char)cur_char > 0x7f) &&
					 cur_char != EOF)) {
#endif /* CHARSET7BIT */
			int 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) {
				int 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 */
				int 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 */
			int 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';
				putc(NEWLINE, stderr);
				new_line = (char *)ralloc(cur_line, (unsigned long)(strlen(cur_line)+1), "line resize");
				line_len=0;
#ifdef DEBUG_STR
				fprintf(stderr, "Resizing input line to %d chars\n", strlen(new_line));
#endif
				reset_termio();
				return(new_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()
{
	int 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(prompt)
char *prompt;
{
	int 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(prompt)
char *prompt;
{
	int 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()
{
	int 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(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);
}

/* add line to the history */
void
add_history(line)
char *line;
{
	struct hist *entry;
	entry = (struct hist *)alloc((unsigned long)sizeof(struct hist),"history");
	entry->line = alloc((unsigned long)(strlen(line)+1),"history");
	strcpy(entry->line, line);

	entry->prev = history;
	entry->next = NULL;
	if(history != NULL) {
		history->next = entry;
	}
	history = entry;
}


/* Convert ANSI arrow keys to control characters */
static int
ansi_getc()
{
  int 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;
      }
    }
  }
  return c;
}

#if defined(MSDOS) || defined(_Windows) || defined(DOS386) || defined(OS2)

/* Convert Arrow keystrokes to Control characters: */
static  char
msdos_getch()
{
#ifdef DJGPP
	char c;
	int ch = getkey();
	c = (ch & 0xff00) ? 0 : ch & 0xff;
#else
#ifdef OS2
    char c = getc(stdin);
#else
    char c = getch();
#endif
#endif

    if (c == 0) {
#ifdef DJGPP
	c = ch & 0xff;
#else
#ifdef OS2
        c = getc(stdin);
#else
  c = getch(); /* Get the extended code. */
#endif
#endif
	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 */

#if defined(ATARI) || defined(MTOS)

/* Convert Arrow keystrokes to Control characters: TOS version */

long poll_events(int);		/* from term/atariaes.trm */

/* 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  /* SGTTY */
#ifdef TERMIOS
#ifdef TCGETS
		ioctl(0, TCGETS, &orig_termio);
#else
		tcgetattr(0, &orig_termio);
#endif /* TCGETS */
#else
		ioctl(0, TCGETA, &orig_termio);
#endif /* TERMIOS */
#endif /* SGTTY */
#else  /* OSK */
		setbuf(stdin, (char *)0);		/* Make stdin and stdout unbuffered */
		setbuf(stderr, (char *)0);
		_gs_opt (STDIN, &new_settings);
#endif

		/*
		 * Save terminal modes
		 */
#ifndef OSK
		rl_termio = orig_termio;
#else
		_gs_opt (STDIN, &old_settings);
#endif

		/*
		 * 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  /* 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
		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
#ifdef VRPRNT
		term_chars[VRPRNT] = orig_termio.c_cc[VRPRNT];
#endif
#endif
		term_chars[VSUSP]    = orig_termio.c_cc[VSUSP];

		/* disable suspending process on ^Z */
		rl_termio.c_cc[VSUSP] = 0;
#endif /* TERMIOS */
#endif /* 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

		/*
		 * Set the new terminal modes.
		 */
#ifndef OSK
#ifdef SGTTY
		ioctl(0, TIOCSLTC, &s_ltchars);
#else
#ifdef TERMIOS
#ifdef TCSETSW
		ioctl(0, TCSETSW, &rl_termio);
#else
		tcsetattr(0, TCSADRAIN, &rl_termio);
#endif /* TCSETSW */
#else
		ioctl(0, TCSETAW, &rl_termio);
#endif /* TERMIOS */
#endif /* SGTTY */
#else  /* OSK */
		_ss_opt (STDIN, &new_settings);
#endif
		term_set = 1;
	}
#endif /* !MSDOS && !ATARI && !MTOS && !defined(_Windows) */
}
  
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  /* SGTTY */
#ifdef TERMIOS
#ifdef TCSETSW
		ioctl(0, TCSETSW, &orig_termio);
#else
		tcsetattr(0, TCSADRAIN, &orig_termio);
#endif /* TCSETSW */
#else
		ioctl(0, TCSETAW, &orig_termio);
#endif /* TERMIOS */
#endif /* SGTTY */
#else  /* OSK */
		_ss_opt (STDIN, &old_settings);
#endif
		term_set = 0;
	}
#endif /* !MSDOS && !ATARI && !MTOS && !_Windows */
}
#endif /* READLINE */
