This is readline.c in view mode; [Download] [Up]
#ifndef lint static char *RCSid = "$Id: readline.c%v 3.38.2.81 1993/02/24 02:29:34 woo Exp woo $"; #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. * * Send your comments or suggestions to * info-gnuplot@dartmouth.edu. * This is a mailing list; to join it send a note to * info-gnuplot-request@dartmouth.edu. * Send bug reports to * bug-gnuplot@dartmouth.edu. */ #ifdef READLINE #ifdef ATARI #include "plot.h" #endif #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 <stdio.h> #include <ctype.h> #include <signal.h> #if !defined(MSDOS) && !defined(ATARI) && !defined(_Windows) && !defined(DOS386) /* * Set up structures using the proper include file */ #ifdef _IBMR2 #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; #define VERASE 0 #define VEOF 1 #define VKILL 2 #ifdef TIOCGLTC /* available only with the 'new' line discipline */ static struct ltchars s_ltchars; #define VWERASE 3 #define VREPRINT 4 #define VSUSP 5 #endif /* TIOCGLTC */ #define NCCS 6 #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.) */ #ifdef SIGTSTP #define 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 #ifndef IUCLC #define IUCLC 0001000 #endif #endif /* ISC22 */ 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 */ #ifdef VRPRNT #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 */ #ifdef NeXT #define special_getc() ESCgetc() static char ESCgetc(); #else #define special_getc() getc(stdin) #endif #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 ATARI #include <stdlib.h> #ifdef __PUREC__ #include <tos.h> #else #include <osbind.h> #endif #define special_getc() tos_getch() static char tos_getch(); #endif #endif /* !MSDOS && !ATARI && !_Windows */ #if !defined(ATARI) /* is it <string.h> or <strings.h>? just declare what we need */ extern int strlen(); extern char *strcpy(); #endif extern char *alloc(); /* we'll use the safe malloc from misc.c */ #define MAXBUF 1024 #define BACKSPACE 0x08 /* ^H */ #define SPACE ' ' 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[MAXBUF]; /* current contents of the line */ static int cur_pos = 0; /* current position of the cursor */ static int max_pos = 0; /* maximum character position */ void add_history(); static void fix_line(); static void redraw_line(); static void clear_line(); static void clear_eoline(); static void copy_line(); static void set_termio(); static void reset_termio(); /* 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. */ 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; } 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 */ backspace() { user_putc(BACKSPACE); } char * readline(prompt) char *prompt; { unsigned char cur_char; char *new_line; /* unsigned char *new_line; */ /* 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(); #ifdef OS2 /* for emx: remap scan codes for cursor keys */ if( cur_char == 0 ) { cur_char = getc(stdin); switch( cur_char){ case 75: /* left, map to ^B */ cur_char=2; break ; case 77: /* right, map to ^F */ cur_char=6; break ; case 115: /* ctrl left */ case 71: /* home, map to ^A */ cur_char=1; break ; case 116: /* ctrl right */ case 79: /* end, map to ^E */ cur_char=5; break ; case 72: /* up, map to ^P */ cur_char=16; break ; case 80: /* down, map to ^N */ cur_char=14; break ; case 83: /* delete, map to ^D */ cur_char=4; break ; default: /* ignore */ cur_char=0; continue ; } } #endif /*OS2*/ if((isprint(cur_char) #if defined(ATARI) || defined(_Windows) || defined(MSDOS) || defined(DOS386) /* this should be used for all 8bit ASCII machines, I guess */ || ((unsigned char)cur_char > 0x7f) #endif )&& max_pos<MAXBUF-1) { int i; 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('\n',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('\n',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 */ case '\r': /* ^M */ cur_line[max_pos+1] = '\0'; putc('\n', stderr); new_line = (char *)alloc((unsigned long) (strlen(cur_line)+1), "history"); strcpy(new_line,cur_line); 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(prompt) char *prompt; { 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; { 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; } #if defined(MSDOS) || defined(_Windows) || defined(DOS386) /* Convert Arrow keystrokes to Control characters: */ static char msdos_getch() { #ifdef DJGPP char c; int ch = getkey(); c = (ch & 0xff00) ? 0 : ch & 0xff; #else char c = getch(); #endif if (c == 0) { #ifdef DJGPP c = ch & 0xff; #else c = getch(); /* Get the extended code. */ #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 */ #ifdef ATARI /* Convert Arrow keystrokes to Control characters: TOS version */ /* the volatile could be necessary to keep gcc from reordering the two Super calls */ #define CONTERM ((/*volatile*/ char *)0x484L) static void remove_conterm() { void *ssp=(void*)Super(0L); *CONTERM &= ~0x8; Super(ssp); } static char tos_getch() { long rawkey; char c; int scan_code; void *ssp; static int init = 1; static int in_help = 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 (init) { ssp = (void*)Super(0L); if( !(*CONTERM & 0x8) ) { *CONTERM |= 0x8; } else { init=0; } (void)Super(ssp); if( init ) { atexit(remove_conterm); init = 0; } } (void)Cursconf(1, 0); /* cursor on */ rawkey = Cnecin(); c = (char)rawkey; scan_code= ((int)(rawkey>>16)) & 0xff; /* get the scancode */ if( rawkey&0x07000000 ) scan_code |= 0x80; /* shift or control */ switch (scan_code) { case 0x62: /* HELP */ if (max_pos==0) { in_help = 1; return 'h'; } else { return 0; } case 0xe2: /* shift HELP */ if (max_pos==0) { 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: /* Crtl 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 */ #ifdef NeXT char ESCgetc() { char c; c=getc(stdin); if( c!='\033' ) { /* ESC */ return c; } c=getc(stdin); if( c!='[' ) { return c; } c=getc(stdin); switch( c ) { case 'A': return '\x10'; /* cursor up becomes ^P */ case 'B': return '\x0e'; /* cursor down becomes ^N */ case 'C': return '\x06'; /* cursor right becomes ^F */ case 'D': return '\x02'; /* cursor left becomes ^B */ default : return c; } } #endif /* set termio so we can do our own input processing */ static void set_termio() { #if !defined(MSDOS) && !defined(ATARI) && !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. */ #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 */ /* * Save terminal modes */ rl_termio = orig_termio; /* * Set the modes to the way we want them * and save our input special characters */ #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 */ /* * Set the new terminal modes. */ #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 */ term_set = 1; } #endif /* !MSDOS && !ATARI && !defined(_Windows) */ } static void reset_termio() { #if !defined(MSDOS) && !defined(ATARI) && !defined(_Windows) && !defined(DOS386) /* reset saved terminal modes */ if(term_set == 1) { #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 */ term_set = 0; } #endif /* !MSDOS && !ATARI && !_Windows */ } #endif /* READLINE */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.