📄 edit.c
字号:
/* * Command line editing - common code * */#include "config.h"#ifdef EDIT#include "sh.h"#include "tty.h"#define EXTERN#include "edit.h"#undef EXTERN#ifdef OS_SCO /* SCO Unix 3.2v4.1 */# include <sys/stream.h> /* needed for <sys/ptem.h> */# include <sys/ptem.h> /* needed for struct winsize */#endif /* OS_SCO */#include <ctype.h>#include "ksh_stat.h"#if defined(TIOCGWINSZ)static RETSIGTYPE x_sigwinch ARGS((int sig));static int got_sigwinch;static void check_sigwinch ARGS((void));#endif /* TIOCGWINSZ */static int x_file_glob ARGS((int flags, const char *str, int slen, char ***wordsp));static int x_command_glob ARGS((int flags, const char *str, int slen, char ***wordsp));static int x_locate_word ARGS((const char *buf, int buflen, int pos, int *startp, int *is_command));static char vdisable_c;/* Called from main */voidx_init(){ /* set to -2 to force initial binding */ edchars.erase = edchars.kill = edchars.intr = edchars.quit = edchars.eof = -2; /* default value for deficient systems */ edchars.werase = 027; /* ^W */#ifdef TIOCGWINSZ# ifdef SIGWINCH if (setsig(&sigtraps[SIGWINCH], x_sigwinch, SS_RESTORE_ORIG|SS_SHTRAP)) sigtraps[SIGWINCH].flags |= TF_SHELL_USES;# endif /* SIGWINCH */ got_sigwinch = 1; /* force initial check */ check_sigwinch();#endif /* TIOCGWINSZ */#ifdef EMACS x_init_emacs();#endif /* EMACS */ /* Bizarreness to figure out how to disable * a struct termios.c_cc[] char */#ifdef _POSIX_VDISABLE if (_POSIX_VDISABLE >= 0) vdisable_c = (char) _POSIX_VDISABLE; else /* `feature not available' */ vdisable_c = (char) 0377;#else# if defined(HAVE_PATHCONF) && defined(_PC_VDISABLE) vdisable_c = fpathconf(tty_fd, _PC_VDISABLE);# else vdisable_c = (char) 0377; /* default to old BSD value */# endif#endif /* _POSIX_VDISABLE */}#if defined(TIOCGWINSZ)static RETSIGTYPEx_sigwinch(sig) int sig;{ got_sigwinch = 1; return RETSIGVAL;}static voidcheck_sigwinch ARGS((void)){ if (got_sigwinch) { struct winsize ws; got_sigwinch = 0; if (procpid == kshpid && ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) { struct tbl *vp; /* Do NOT export COLUMNS/LINES. Many applications * check COLUMNS/LINES before checking ws.ws_col/row, * so if the app is started with C/L in the environ * and the window is then resized, the app won't * see the change cause the environ doesn't change. */ if (ws.ws_col) { x_cols = ws.ws_col < MIN_COLS ? MIN_COLS : ws.ws_col; if ((vp = typeset("COLUMNS", 0, 0, 0, 0))) setint(vp, (long) ws.ws_col); } if (ws.ws_row && (vp = typeset("LINES", 0, 0, 0, 0))) setint(vp, (long) ws.ws_row); } }}#endif /* TIOCGWINSZ *//* * read an edited command line */intx_read(buf, len) char *buf; size_t len;{ int i;#if defined(TIOCGWINSZ) if (got_sigwinch) check_sigwinch();#endif /* TIOCGWINSZ */ x_mode(TRUE);#ifdef EMACS if (Flag(FEMACS) || Flag(FGMACS)) i = x_emacs(buf, len); else#endif#ifdef VI if (Flag(FVI)) i = x_vi(buf, len); else#endif i = -1; /* internal error */ x_mode(FALSE); return i;}/* tty I/O */intx_getc(){#ifdef OS2 unsigned char c = _read_kbd(0, 1, 0); return c == 0 ? 0xE0 : c;#else /* OS2 */ char c; int n; while ((n = blocking_read(0, &c, 1)) < 0 && errno == EINTR) if (trap) { x_mode(FALSE); runtraps(0); x_mode(TRUE); } if (n != 1) return -1; return (int) (unsigned char) c;#endif /* OS2 */}voidx_flush(){ shf_flush(shl_out);}voidx_putc(c) int c;{ shf_putc(c, shl_out);}voidx_puts(s) const char *s;{ while (*s != 0) shf_putc(*s++, shl_out);}bool_tx_mode(onoff) bool_t onoff;{ static bool_t x_cur_mode; bool_t prev; if (x_cur_mode == onoff) return x_cur_mode; prev = x_cur_mode; x_cur_mode = onoff; if (onoff) { TTY_state cb; X_chars oldchars; oldchars = edchars; cb = tty_state;#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H) edchars.erase = cb.c_cc[VERASE]; edchars.kill = cb.c_cc[VKILL]; edchars.intr = cb.c_cc[VINTR]; edchars.quit = cb.c_cc[VQUIT]; edchars.eof = cb.c_cc[VEOF];# ifdef VWERASE edchars.werase = cb.c_cc[VWERASE];# endif# ifdef _CRAY2 /* brain-damaged terminal handler */ cb.c_lflag &= ~(ICANON|ECHO); /* rely on print routine to map '\n' to CR,LF */# else cb.c_iflag &= ~(INLCR|ICRNL);# ifdef _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */ cb.c_lflag &= ~(ICANON|ECHO);# else# ifdef SWTCH /* need CBREAK to handle swtch char */ cb.c_lflag &= ~(ICANON|ECHO); cb.c_lflag |= ISIG; cb.c_cc[VINTR] = vdisable_c; cb.c_cc[VQUIT] = vdisable_c;# else cb.c_lflag &= ~(ISIG|ICANON|ECHO);# endif# endif# ifdef VLNEXT /* osf/1 processes lnext when ~icanon */ cb.c_cc[VLNEXT] = vdisable_c;# endif /* VLNEXT */# ifdef VDISCARD /* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */ cb.c_cc[VDISCARD] = vdisable_c;# endif /* VDISCARD */ cb.c_cc[VTIME] = 0; cb.c_cc[VMIN] = 1;# endif /* _CRAY2 */#else /* Assume BSD tty stuff. */ edchars.erase = cb.sgttyb.sg_erase; edchars.kill = cb.sgttyb.sg_kill; cb.sgttyb.sg_flags &= ~ECHO; cb.sgttyb.sg_flags |= CBREAK;# ifdef TIOCGATC edchars.intr = cb.lchars.tc_intrc; edchars.quit = cb.lchars.tc_quitc; edchars.eof = cb.lchars.tc_eofc; edchars.werase = cb.lchars.tc_werasc; cb.lchars.tc_suspc = -1; cb.lchars.tc_dsuspc = -1; cb.lchars.tc_lnextc = -1; cb.lchars.tc_statc = -1; cb.lchars.tc_intrc = -1; cb.lchars.tc_quitc = -1; cb.lchars.tc_rprntc = -1;# else edchars.intr = cb.tchars.t_intrc; edchars.quit = cb.tchars.t_quitc; edchars.eof = cb.tchars.t_eofc; cb.tchars.t_intrc = -1; cb.tchars.t_quitc = -1;# ifdef TIOCGLTC edchars.werase = cb.ltchars.t_werasc; cb.ltchars.t_suspc = -1; cb.ltchars.t_dsuspc = -1; cb.ltchars.t_lnextc = -1; cb.ltchars.t_rprntc = -1;# endif# endif /* TIOCGATC */#endif /* HAVE_TERMIOS_H || HAVE_TERMIO_H */ set_tty(tty_fd, &cb, TF_WAIT);#ifdef __CYGWIN__ if (edchars.eof == '\0') edchars.eof = '\4';#endif /* __CYGWIN__ */ /* Convert unset values to internal `unset' value */ if (edchars.erase == vdisable_c) edchars.erase = -1; if (edchars.kill == vdisable_c) edchars.kill = -1; if (edchars.intr == vdisable_c) edchars.intr = -1; if (edchars.quit == vdisable_c) edchars.quit = -1; if (edchars.eof == vdisable_c) edchars.eof = -1; if (edchars.werase == vdisable_c) edchars.werase = -1; if (memcmp(&edchars, &oldchars, sizeof(edchars)) != 0) {#ifdef EMACS x_emacs_keys(&edchars);#endif } } else { /* TF_WAIT doesn't seem to be necessary when leaving xmode */ set_tty(tty_fd, &tty_state, TF_NONE); } return prev;}/* NAME: * promptlen - calculate the length of PS1 etc. * * DESCRIPTION: * This function is based on a fix from guy@demon.co.uk * It fixes a bug in that if PS1 contains '!', the length * given by strlen() is probably wrong. * * RETURN VALUE: * length */intpromptlen(cp, spp) const char *cp; const char **spp;{ int count = 0; const char *sp = cp; char delimiter = 0; int indelimit = 0; /* Undocumented AT&T ksh feature: * If the second char in the prompt string is \r then the first char * is taken to be a non-printing delimiter and any chars between two * instances of the delimiter are not considered to be part of the * prompt length */ if (*cp && cp[1] == '\r') { delimiter = *cp; cp += 2; } for (; *cp; cp++) { if (indelimit && *cp != delimiter) ; else if (*cp == '\n' || *cp == '\r') { count = 0; sp = cp + 1; } else if (*cp == '\t') { count = (count | 7) + 1; } else if (*cp == '\b') { if (count > 0) count--; } else if (*cp == delimiter) indelimit = !indelimit; else count++; } if (spp) *spp = sp; return count;}voidset_editmode(ed) const char *ed;{ static const enum sh_flag edit_flags[] = {#ifdef EMACS FEMACS, FGMACS,#endif#ifdef VI FVI,#endif }; char *rcp; int i; if ((rcp = ksh_strrchr_dirsep(ed))) ed = ++rcp; for (i = 0; i < NELEM(edit_flags); i++) if (strstr(ed, options[(int) edit_flags[i]].name)) { change_flag(edit_flags[i], OF_SPECIAL, 1); return; }}/* ------------------------------------------------------------------------- *//* Misc common code for vi/emacs *//* Handle the commenting/uncommenting of a line. * Returns: * 1 if a carriage return is indicated (comment added) * 0 if no return (comment removed) * -1 if there is an error (not enough room for comment chars) * If successful, *lenp contains the new length. Note: cursor should be * moved to the start of the line after (un)commenting. */intx_do_comment(buf, bsize, lenp) char *buf; int bsize; int *lenp;{ int i, j; int len = *lenp; if (len == 0) return 1; /* somewhat arbitrary - it's what at&t ksh does */ /* Already commented? */ if (buf[0] == '#') { int saw_nl = 0; for (j = 0, i = 1; i < len; i++) { if (!saw_nl || buf[i] != '#') buf[j++] = buf[i]; saw_nl = buf[i] == '\n'; } *lenp = j; return 0; } else { int n = 1; /* See if there's room for the #'s - 1 per \n */ for (i = 0; i < len; i++) if (buf[i] == '\n') n++; if (len + n >= bsize) return -1; /* Now add them... */ for (i = len, j = len + n; --i >= 0; ) { if (buf[i] == '\n') buf[--j] = '#'; buf[--j] = buf[i]; } buf[0] = '#'; *lenp += n; return 1; }}/* ------------------------------------------------------------------------- *//* Common file/command completion code for vi/emacs */static char *add_glob ARGS((const char *str, int slen));static void glob_table ARGS((const char *pat, XPtrV *wp, struct table *tp));static void glob_path ARGS((int flags, const char *pat, XPtrV *wp, const char *path));#if 0 /* not used... */int x_complete_word ARGS((const char *str, int slen, int is_command, int *multiple, char **ret));intx_complete_word(str, slen, is_command, nwordsp, ret) const char *str; int slen; int is_command; int *nwordsp; char **ret;{ int nwords; int prefix_len; char **words; nwords = (is_command ? x_command_glob : x_file_glob)(XCF_FULLPATH, str, slen, &words); *nwordsp = nwords; if (nwords == 0) { *ret = (char *) 0; return -1; } prefix_len = x_longest_prefix(nwords, words); *ret = str_nsave(words[0], prefix_len, ATEMP); x_free_words(nwords, words); return prefix_len;}#endif /* 0 */voidx_print_expansions(nwords, words, is_command) int nwords; char *const *words; int is_command;{ int use_copy = 0; int prefix_len; XPtrV l; /* Check if all matches are in the same directory (in this * case, we want to omitt the directory name) */ if (!is_command && (prefix_len = x_longest_prefix(nwords, words)) > 0) { int i; /* Special case for 1 match (prefix is whole word) */ if (nwords == 1) prefix_len = x_basename(words[0], (char *) 0); /* Any (non-trailing) slashes in non-common word suffixes? */ for (i = 0; i < nwords; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -