📄 getline.c
字号:
#ifndef lintstatic char rcsid[] ="$Id: getline.c,v 5.0 1995/12/10 10:34:21 orel Exp $";static char *copyright = "Copyright (C) 1991, 1992, 1993, Chris Thewalt";#endif/* * Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu) * * Permission to use, copy, modify, and distribute this software * for any purpose and without fee is hereby granted, provided * that the above copyright notices appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. This software is provided "as is" without express or * implied warranty. * * Thanks to the following people who have provided enhancements and fixes: * Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List, * DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten, * Edin Hodzic, Eric J Bivona, Kai Uwe Rommel */#ifdef _AIX#define POSIX#endif#include "getline.h"static int gl_tab(); /* forward reference needed for gl_tab_hook *//******************** imported interface *********************************/#include <string.h>#include <ctype.h>#include <errno.h>#include <signal.h>extern int isatty(); extern void *malloc();extern void free();extern int kill(); /********************* exported interface ********************************/char *getline(); /* read a line of input */void gl_setwidth(); /* specify width of screen */void gl_histadd(); /* adds entries to hist */void gl_strwidth(); /* to bind gl_strlen */int (*gl_in_hook)() = 0;int (*gl_out_hook)() = 0;int (*gl_tab_hook)() = gl_tab;/******************** internal interface *********************************/#define BUF_SIZE 1024static int gl_init_done = -1; /* terminal mode flag */static int gl_termw = 80; /* actual terminal width */static int gl_scroll = 27; /* width of EOL scrolling region */static int gl_width = 0; /* net size available for input */static int gl_extent = 0; /* how far to redraw, 0 means all */static int gl_overwrite = 0; /* overwrite mode */static int gl_pos, gl_cnt = 0; /* position and size of input */static char gl_buf[BUF_SIZE]; /* input buffer */static char gl_killbuf[BUF_SIZE]=""; /* killed text */static char *gl_prompt; /* to save the prompt string */static char gl_intrc = 0; /* keyboard SIGINT char */static char gl_quitc = 0; /* keyboard SIGQUIT char */static char gl_suspc = 0; /* keyboard SIGTSTP char */static char gl_dsuspc = 0; /* delayed SIGTSTP char */static int gl_search_mode = 0; /* search mode flag */static void gl_init(); /* prepare to edit a line */static void gl_cleanup(); /* to undo gl_init */void gl_char_init(); /* get ready for no echo input */void gl_char_cleanup(); /* undo gl_char_init */static size_t (*gl_strlen)() = (size_t(*)())strlen; /* returns printable prompt width */static void gl_addchar(); /* install specified char */static void gl_del(); /* del, either left (-1) or cur (0) */static void gl_error(); /* write error msg and die */static void gl_fixup(); /* fixup state variables and screen */static int gl_getc(); /* read one char from terminal */static void gl_kill(); /* delete to EOL */static void gl_newline(); /* handle \n or \r */static void gl_putc(); /* write one char to terminal */static void gl_puts(); /* write a line to terminal */static void gl_redraw(); /* issue \n and redraw all */static void gl_transpose(); /* transpose two chars */static void gl_yank(); /* yank killed text */static void gl_word(); /* move a word */static void hist_init(); /* initializes hist pointers */static char *hist_next(); /* return ptr to next item */static char *hist_prev(); /* return ptr to prev item */static char *hist_save(); /* makes copy of a string, without NL */static void search_addchar(); /* increment search string */static void search_term(); /* reset with current contents */static void search_back(); /* look back for current string */static void search_forw(); /* look forw for current string *//************************ nonportable part *********************************/extern int write();extern void exit();#ifdef _IBMR2#define unix#endif#ifdef MSDOS#include <bios.h>#endif#ifdef unixextern int read();extern int ioctl();#ifdef POSIX /* use POSIX interface */#include <termios.h>struct termios new_termios, old_termios;#else /* not POSIX */#include <sys/ioctl.h>#ifdef M_XENIX /* does not really use bsd terminal interface */#undef TIOCSETN#endif /* M_XENIX */#ifdef TIOCSETN /* use BSD interface */#include <sgtty.h>struct sgttyb new_tty, old_tty;struct tchars tch;struct ltchars ltch;#else /* use SYSV interface */#include <termio.h>struct termio new_termio, old_termio;#endif /* TIOCSETN */#endif /* POSIX */#endif /* unix */#ifdef vms#include <descrip.h>#include <ttdef.h>#include <iodef.h>#include unixio static int setbuff[2]; /* buffer to set terminal attributes */static short chan = -1; /* channel to terminal */struct dsc$descriptor_s descrip; /* VMS descriptor */#endifvoidgl_char_init() /* turn off input echo */{#ifdef unix#ifdef POSIX tcgetattr(0, &old_termios); gl_intrc = old_termios.c_cc[VINTR]; gl_quitc = old_termios.c_cc[VQUIT];#ifdef VSUSP gl_suspc = old_termios.c_cc[VSUSP];#endif#ifdef VDSUSP gl_dsuspc = old_termios.c_cc[VDSUSP];#endif new_termios = old_termios; new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); new_termios.c_iflag |= (IGNBRK|IGNPAR); new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); new_termios.c_cc[VMIN] = 1; new_termios.c_cc[VTIME] = 0; tcsetattr(0, TCSANOW, &new_termios);#else /* not POSIX */#ifdef TIOCSETN /* BSD */ ioctl(0, TIOCGETC, &tch); ioctl(0, TIOCGLTC, <ch); gl_intrc = tch.t_intrc; gl_quitc = tch.t_quitc; gl_suspc = ltch.t_suspc; gl_dsuspc = ltch.t_dsuspc; ioctl(0, TIOCGETP, &old_tty); new_tty = old_tty; new_tty.sg_flags |= RAW; new_tty.sg_flags &= ~ECHO; ioctl(0, TIOCSETN, &new_tty);#else /* SYSV */ ioctl(0, TCGETA, &old_termio); gl_intrc = old_termio.c_cc[VINTR]; gl_quitc = old_termio.c_cc[VQUIT]; new_termio = old_termio; new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); new_termio.c_iflag |= (IGNBRK|IGNPAR); new_termio.c_lflag &= ~(ICANON|ISIG|ECHO); new_termio.c_cc[VMIN] = 1; new_termio.c_cc[VTIME] = 0; ioctl(0, TCSETA, &new_termio);#endif /* TIOCSETN */#endif /* POSIX */#endif /* unix */#ifdef vms descrip.dsc$w_length = strlen("tt:"); descrip.dsc$b_dtype = DSC$K_DTYPE_T; descrip.dsc$b_class = DSC$K_CLASS_S; descrip.dsc$a_pointer = "tt:"; (void)sys$assign(&descrip,&chan,0,0); (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0); setbuff[1] |= TT$M_NOECHO; (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);#endif /* vms */}voidgl_char_cleanup() /* undo effects of gl_char_init */{#ifdef unix#ifdef POSIX tcsetattr(0, TCSANOW, &old_termios);#else /* not POSIX */#ifdef TIOCSETN /* BSD */ old_tty.sg_flags &= ~RAW; ioctl(0, TIOCSETN, &old_tty);#else /* SYSV */ ioctl(0, TCSETA, &old_termio);#endif /* TIOCSETN */#endif /* POSIX */#endif /* unix */#ifdef vms setbuff[1] &= ~TT$M_NOECHO; (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); sys$dassgn(chan); chan = -1;#endif }#if MSDOS || __EMX__int pc_keymap(c)int c;{ switch (c) { case 72: c = 16; /* up -> ^P */ break; case 80: c = 14; /* down -> ^N */ break; case 75: c = 2; /* left -> ^B */ break; case 77: c = 6; /* right -> ^F */ break; default: c = 0; /* make it garbage */ } return c;}#endif /* MSDOS || __EMCX__ */static intgl_getc()/* get a character without echoing it to screen */{ int c; char ch;#ifdef unix c = (read(0, &ch, 1) > 0)? ch : -1;#endif#ifdef MSDOS c = _bios_keybrd(_NKEYBRD_READ); if ((c & 0377) == 224) { c = pc_keymap((c >> 8) & 0377); } else { c &= 0377; }#endif#ifdef __TURBOC__ while(!bioskey(1)) ; c = bioskey(0) & 0xff;#endif#ifdef __EMX__#define getch() _read_kbd(0, 1, 0) c = getch(); if (c == 224 || c == 0) { c = pc_keymap(getch()); } else { c &= 0377; }#endif#ifdef vms if(chan < 0) { c='\0'; } (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0); c &= 0177; /* get a char */#endif return c;}static voidgl_putc(c)int c;{ char ch = c; write(1, &ch, 1); if (ch == '\n') { ch = '\r'; write(1, &ch, 1); /* RAW mode needs '\r', does not hurt */ }}/******************** fairly portable part *********************************/static voidgl_puts(buf)char *buf;{ int len; if (buf) { len = strlen(buf); write(1, buf, len); }}static voidgl_error(buf)char *buf;{ int len = strlen(buf); gl_cleanup(); write(2, buf, len); exit(1);}static voidgl_init()/* set up variables and terminal */{ if (gl_init_done < 0) { /* -1 only on startup */ hist_init(); } if (isatty(0) == 0 || isatty(1) == 0) gl_error("\n*** Error: getline(): not interactive, use stdio.\n"); gl_char_init(); gl_init_done = 1;}static voidgl_cleanup()/* undo effects of gl_init, as necessary */{ if (gl_init_done > 0) gl_char_cleanup(); gl_init_done = 0;}voidgl_setwidth(w)int w;{ if (w > 20) { gl_termw = w; gl_scroll = w / 3; } else { gl_error("\n*** Error: minimum screen width is 21\n"); }}char *getline(prompt)char *prompt;{ int c, loc, tmp; int sig; gl_init(); gl_prompt = (prompt)? prompt : ""; gl_buf[0] = 0; if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, -2, BUF_SIZE); while ((c = gl_getc()) >= 0) { gl_extent = 0; /* reset to full extent */ if (isprint(c)) { if (gl_search_mode) search_addchar(c); else gl_addchar(c); } else { if (gl_search_mode) { if (c == '\033' || c == '\016' || c == '\020') { search_term(); c = 0; /* ignore the character */ } else if (c == '\010' || c == '\177') { search_addchar(-1); /* unwind search string */ c = 0; } else if (c != '\022' && c != '\023') { search_term(); /* terminate and handle char */ } } switch (c) { case '\n': case '\r': /* newline */ gl_newline(); gl_cleanup(); return gl_buf; /*NOTREACHED*/ break; case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */ break; case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */ break; case '\004': /* ^D */ if (gl_cnt == 0) { gl_buf[0] = 0; gl_cleanup(); gl_putc('\n'); return gl_buf; } else { gl_del(0); } break; case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */ break; case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */ break; case '\010': case '\177': gl_del(-1); /* ^H and DEL */ break; case '\t': /* TAB */ if (gl_tab_hook) { tmp = gl_pos; loc = gl_tab_hook(gl_buf, gl_strlen(gl_prompt), &tmp); if (loc >= 0 || tmp != gl_pos) gl_fixup(gl_prompt, loc, tmp); } break; case '\013': gl_kill(gl_pos); /* ^K */ break; case '\014': gl_redraw(); /* ^L */ break; case '\016': /* ^N */ strcpy(gl_buf, hist_next()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case '\017': gl_overwrite = !gl_overwrite; /* ^O */ break; case '\020': /* ^P */ strcpy(gl_buf, hist_prev()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case '\022': search_back(1); /* ^R */ break; case '\023': search_forw(1); /* ^S */ break; case '\024': gl_transpose(); /* ^T */ break; case '\025': gl_kill(0); /* ^U */ break; case '\031': gl_yank(); /* ^Y */ break; case '\033': /* ansi arrow keys */ c = gl_getc(); if (c == '[') { switch(c = gl_getc()) { case 'A': /* up */ strcpy(gl_buf, hist_prev()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case 'B': /* down */ strcpy(gl_buf, hist_next()); if (gl_in_hook) gl_in_hook(gl_buf); gl_fixup(gl_prompt, 0, BUF_SIZE); break; case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */ break; case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */ break; default: gl_putc('\007'); /* who knows */ break; } } else if (c == 'f' || c == 'F') { gl_word(1); } else if (c == 'b' || c == 'B') { gl_word(-1); } else gl_putc('\007'); break; default: /* check for a terminal signal */#ifdef unix if (c > 0) { /* ignore 0 (reset above) */ sig = 0;#ifdef SIGINT if (c == gl_intrc) sig = SIGINT;#endif#ifdef SIGQUIT if (c == gl_quitc) sig = SIGQUIT;#endif#ifdef SIGTSTP if (c == gl_suspc || c == gl_dsuspc) sig = SIGTSTP;#endif if (sig != 0) { gl_cleanup(); kill(0, sig); gl_init(); gl_redraw(); c = 0; } }#endif /* unix */ if (c > 0) gl_putc('\007'); break; } } } gl_cleanup(); gl_buf[0] = 0; return gl_buf;}static voidgl_addchar(c)int c;/* adds the character c to the input buffer at current location */{ int i; if (gl_cnt >= BUF_SIZE - 1) gl_error("\n*** Error: getline(): input buffer overflow\n"); if (gl_overwrite == 0 || gl_pos == gl_cnt) { for (i=gl_cnt; i >= gl_pos; i--) gl_buf[i+1] = gl_buf[i]; gl_buf[gl_pos] = c; gl_fixup(gl_prompt, gl_pos, gl_pos+1); } else { gl_buf[gl_pos] = c; gl_extent = 1; gl_fixup(gl_prompt, gl_pos, gl_pos+1); }}static voidgl_yank()/* adds the kill buffer to the input buffer at current location */{ int i, len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -