netnews@netcom.UUCP (USENET Administration) (12/12/90)
#!/bin/sh # This is part 03 of ksh-pd # ============= src/lex.c ============== if test ! -d 'src'; then echo 'x - creating directory src' mkdir 'src' fi if test -f 'src/lex.c' -a X"$1" != X"-c"; then echo 'x - skipping src/lex.c (File already exists)' else echo 'x - extracting src/lex.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/lex.c' && X/* X * lexical analysis and source input X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/lex.c,v 3.4 88/12/17 21:19:21 egisin Exp $"; X X#include <stddef.h> X#include <stdio.h> X#include <string.h> X#include <errno.h> X#include <setjmp.h> X#include <unistd.h> X#include "sh.h" X#include "lex.h" X#include "tree.h" X#include "table.h" X#include "expand.h" X X int ttyfd = -1; /* tty fd for edit and jobs */ X char *history[HISTORY]; /* saved commands */ X char **histptr = history - 1; /* last history item */ X int histpush; /* number of pushed fc commands */ X Xstatic int alias; Xstatic int getsc_ ARGS((void)); X X/* optimized getsc_() */ X#define getsc() ((*source->str != 0) ? *source->str++ : getsc_()) X#define ungetsc() (source->str--) X X/* X * Lexical analyzer X * X * tokens are not regular expressions, they are LL(1). X * for example, "${var:-${PWD}}", and "$(size $(whence ksh))". X * hence the state stack. X */ X Xint Xyylex(cf) X int cf; X{ X register int c, state; X char states [64], *statep = states; X XString ws; /* expandable output word */ X register char *wp; /* output word pointer */ X register char *sp, *dp; X int istate; X int c2; X X Again: X Xinit(ws, wp, 256); X if (alias) { /* trailing ' ' in alias definition */ X alias = 0; X cf |= ALIAS; X } X X if (cf&ONEWORD) X istate = SWORD; X else { /* normal lexing */ X istate = SBASE; X while ((c = getsc()) == ' ' || c == '\t') X ; X if (c == '#') X while ((c = getsc()) != 0 && c != '\n') X ; X ungetsc(); X } X X /* collect non-special or quoted characters to form word */ X for (*statep = state = istate; X !((c = getsc()) == 0 || state == SBASE && ctype(c, C_LEX1)); ) { X Xcheck(ws, wp); X switch (state) { X case SBASE: X Sbase: X switch (c) { X case '\\': X c = getsc(); X if (c != '\n') X *wp++ = QCHAR, *wp++ = c; X else X if (wp == Xstring(ws, wp)) X goto Again; X break; X case '\'': X *++statep = state = SSQUOTE; X *wp++ = OQUOTE; X break; X case '"': X *++statep = state = SDQUOTE; X *wp++ = OQUOTE; X break; X default: X goto Subst; X } X break; X X Subst: X switch (c) { X case '\\': X c = getsc(); X switch (c) { X case '\n': X break; X case '"': case '\\': X case '$': case '`': X *wp++ = QCHAR, *wp++ = c; X break; X default: X *wp++ = CHAR, *wp++ = '\\'; X *wp++ = CHAR, *wp++ = c; X break; X } X break; X case '$': X c = getsc(); X if (c == '(') { X *++statep = state = SPAREN; X *wp++ = COMSUB; X } else X if (c == '{') { X *++statep = state = SBRACE; X *wp++ = OSUBST; X c = getsc(); X do { X Xcheck(ws, wp); X *wp++ = c; X c = getsc(); X } while (ctype(c, C_ALPHA|C_DIGIT)); X *wp++ = 0; X /* todo: more compile-time checking */ X if (c == '}') X ungetsc(); X else if (c == '#' || c == '%') { X /* Korn pattern trimming */ X if (getsc() == c) X c |= 0x80; X else X ungetsc(); X *wp++ = c; X } else if (c == ':') X *wp++ = 0x80|getsc(); X else X *wp++ = c; X } else if (ctype(c, C_ALPHA)) { X *wp++ = OSUBST; X do { X *wp++ = c; X c = getsc(); X } while (ctype(c, C_ALPHA|C_DIGIT)); X *wp++ = 0; X *wp++ = CSUBST; X ungetsc(); X } else if (ctype(c, C_DIGIT|C_VAR1)) { X *wp++ = OSUBST; X *wp++ = c; X *wp++ = 0; X *wp++ = CSUBST; X } else { X *wp++ = CHAR, *wp++ = '$'; X ungetsc(); X } X break; X case '`': X *++statep = state = SBQUOTE; X *wp++ = COMSUB; X break; X default: X *wp++ = CHAR, *wp++ = c; X } X break; X X case SSQUOTE: X if (c == '\'') { X state = *--statep; X *wp++ = CQUOTE; X } else X *wp++ = QCHAR, *wp++ = c; X break; X X case SDQUOTE: X if (c == '"') { X state = *--statep; X *wp++ = CQUOTE; X } else X goto Subst; X break; X X case SPAREN: X if (c == '(') X *++statep = state; X else if (c == ')') X state = *--statep; X if (state == SPAREN) X *wp++ = c; X else X *wp++ = 0; /* end of COMSUB */ X break; X X case SBRACE: X if (c == '}') { X state = *--statep; X *wp++ = CSUBST; X } else X goto Sbase; X break; X X case SBQUOTE: X if (c == '`') { X *wp++ = 0; X state = *--statep; X } else /* todo: handle silly `\`` escapes */ X /* todo: both \" and \` in "`...`" */ X *wp++ = c; X break; X X case SWORD: /* ONEWORD */ X goto Subst; X } X } X if (state != istate) X yyerror("no closing quote"); X X if (c == '<' || c == '>') { X char *cp = Xstring(ws, wp); X if (wp > cp && cp[0] == CHAR && digit(cp[1])) { X wp = cp; /* throw away word */ X c2/*unit*/ = cp[1] - '0'; X } else X c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */ X } X X if (wp == Xstring(ws, wp) && state == SBASE) { X Xfree(ws, sp); /* free word */ X /* no word, process LEX1 character */ X switch (c) { X default: X return c; X X case '|': X case '&': X case ';': X if (getsc() == c) X c = (c == ';') ? BREAK : X (c == '|') ? LOGOR : X (c == '&') ? LOGAND : X YYERRCODE; X else X ungetsc(); X return c; X X case '>': X case '<': { X register struct ioword *iop; X X iop = (struct ioword *) alloc(sizeof(*iop), ATEMP); X iop->unit = c2/*unit*/; X X c2 = getsc(); X if (c2 == '>' || c2 == '<') { X iop->flag = c != c2 ? IORDWR : c == '>' ? IOCAT : IOHERE; X c2 = getsc(); X } else X iop->flag = c == '>' ? IOWRITE : IOREAD; X X if (iop->flag == IOHERE) X if (c2 == '-') X iop->flag |= IOSKIP; X else X ungetsc(); X else X if (c2 == '&') X iop->flag = IODUP; X else if (c2 == '!' && iop->flag == IOWRITE) X iop->flag |= IOCLOB; X else X ungetsc(); X yylval.iop = iop; X return REDIR; X } X case '\n': X gethere(); X if (cf & CONTIN) X goto Again; X return c; X X case '(': X c2 = getsc(); X if (c2 == ')') X c = MPAREN; X else if (c2 == '(') X yyerror("(( not supported"); X else X ungetsc(); X case ')': X return c; X } X } X X *wp++ = EOS; /* terminate word */ X yylval.cp = Xclose(ws, wp); X if (state == SWORD) /* ONEWORD? */ X return LWORD; X ungetsc(); /* unget terminator */ X X /* copy word to unprefixed string ident */ X for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; ) X *dp++ = *sp++; X *dp = 0; X#if 0 X if (*ident == '~' || (dp = strchr(ident, '=')) != NULL && dp[1] == '~') X "Tilde expansion"; X#endif X if (c != EOS) X *ident = 0; /* word is not unquoted */ X X if (*ident != 0 && (cf&(KEYWORD|ALIAS))) { X register struct tbl *p; X X p = tsearch(&lexicals, ident, hash(ident)); X if (p != NULL && (p->flag&ISSET)) X if (p->type == CKEYWD && (cf&KEYWORD)) { X afree(yylval.cp, ATEMP); X return p->val.i; X } else X if (p->type == CALIAS && (cf&ALIAS)) { X register Source *s; X X /* check for recursive aliasing */ X for (s = source; s->type == SALIAS; s = s->next) X if (s->u.tblp == p) X return LWORD; X afree(yylval.cp, ATEMP); X X /* push alias expansion */ X s = pushs(SALIAS); X s->str = p->val.s; X s->u.tblp = p; X s->next = source; X source = s; X goto Again; X } X } X X return LWORD; X} X Xstatic void readhere(); X Xgethere() X{ X register struct ioword **p; X X for (p = heres; p < herep; p++) X readhere(*p); X herep = heres; X} X X/* X * read "<<word" text into temp file X * todo: set up E_ERR to fclose(f) on unwind X */ X Xstatic void Xreadhere(iop) X register struct ioword *iop; X{ X register FILE *f; X struct temp *h; X register int c; X char *eof; X register char *cp; X char line [LINE+1]; X X eof = evalstr(iop->name, 0); X X h = maketemp(ATEMP); X h->next = e.temps; e.temps = h; X iop->name = h->name; X f = fopen(h->name, "w"); X if (f == NULL) X errorf("Cannot create temporary file\n"); X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ); X X for (;;) { X cp = line; X while ((c = getsc()) != '\n') { X if (c == 0) X errorf("here document `%s' unclosed\n", eof); X if (cp >= line+LINE) X break; X *cp++ = c; X } X ungetsc(); X *cp = 0; X for (cp = line; iop->flag&IOSKIP && *cp == '\t'; cp++) X ; X if (strcmp(eof, cp) == 0 || c == 0) X break; X while ((c = *cp++) != '\0') X putc(c, f); X while ((c = getsc()) != '\n') { X if (c == 0) X errorf("here document `%s' unclosed\n", eof); X putc(c, f); X } X putc(c, f); X } X fclose(f); X} X Xvoid Xyyerror(msg) X Const char *msg; X{ X yynerrs++; X while (source->type == SALIAS) /* pop aliases */ X source = source->next; X if (source->file != NULL) X shellf("%s[%d]: ", source->file, source->line); X source->str = null; /* zap pending input */ X errorf("%s\n", msg); X} X X/* X * input for yylex with alias expansion X */ X XSource * Xpushs(type) X int type; X{ X register Source *s; X X s = (Source *) alloc(sizeof(Source), ATEMP); X s->type = type; X s->str = null; /* "" */ X s->line = 0; X s->file = NULL; X s->echo = 0; X s->next = NULL; X return s; X} X Xstatic int Xgetsc_() X{ X register Source *s = source; X register int c; X X while ((c = *s->str++) == 0) { X s->str = NULL; /* return 0 for EOF by default */ X switch (s->type) { X case SEOF: X s->str = null; X return 0; X X case STTY: X if (histpush < 0) { /* commands pushed by dofc */ X s->type = SHIST; X s->str = null; X continue; X } X s->line++; X s->str = line; X line[0] = '\0'; X pprompt(prompt); X flushshf(1); flushshf(2); X#if EDIT X if (flag[FEMACS]) X c = x_read(ttyfd, line, LINE); X else X#endif X c = read(ttyfd, line, LINE); X if (c < 0) /* read error */ X c = 0; X if (c == 0) /* EOF */ X s->str = NULL; X prompt = strval(global("PS2")); X line[c] = '\0'; X if (line[0] != '\n') X histsave(line); X else X s->line--; X break; X X case SHIST: X if (histpush == 0) { X s->type = STTY; X s->str = null; X continue; X } X s->line++; X s->str = histptr[++histpush]; X pprompt("!< "); /* todo: PS9 */ X shellf("%s\n", s->str); X strcpy(line, s->str); X s->str = strchr(line, 0); X *s->str++ = '\n'; X *s->str = 0; X s->str = line; X break; X X case SFILE: X s->line++; X s->str = fgets(line, LINE, s->u.file); X if (s->str == NULL) X if (s->u.file != stdin) X fclose(s->u.file); X break; X X case SWSTR: X break; X X case SSTRING: X s->str = "\n"; X s->type = SEOF; X break; X X case SWORDS: X s->str = *s->u.strv++; X s->type = SWORDSEP; X break; X X case SWORDSEP: X if (*s->u.strv == NULL) { X s->str = "\n"; X s->type = SEOF; X } else { X s->str = " "; X s->type = SWORDS; X } X break; X X case SALIAS: X s->str = s->u.tblp->val.s; X if (s->str[0] != 0 && strchr(s->str, 0)[-1] == ' ') X alias = 1; /* trailing ' ' */ X source = s = s->next; /* pop source stack */ X continue; X } X if (s->str == NULL) { X s->type = SEOF; X s->str = null; /* "" */ X return 0; X } X if (s->echo) X fputs(s->str, shlout); X } X return c; X} X Xpprompt(cp) X register char *cp; X{ X while (*cp != 0) X if (*cp != '!') X putc(*cp++, shlout); X else X if (*++cp == '!') X putc(*cp++, shlout); X else X shellf("%d", source->line); X fflush(shlout); X} X SHAR_EOF true || echo 'restore of src/lex.c failed' fi # ============= src/edit.c ============== if test -f 'src/edit.c' -a X"$1" != X"-c"; then echo 'x - skipping src/edit.c (File already exists)' else echo 'x - extracting src/edit.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/edit.c' && X/* X * EDIT.C -- Emacs-like command line editing and history X * X * created by Ron Natalie at BRL X * modified by Doug Kingston, Doug Gwyn, and Lou Salkind X * adapted to PD ksh by Eric Gisin X */ X X#if EDIT X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/edit.c,v 3.2 88/12/14 20:11:44 egisin Exp $"; X X#include <stddef.h> X#include <stdlib.h> X#include <string.h> X#include <stdio.h> X#include <unistd.h> X#include <signal.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <dirent.h> X#include <fcntl.h> X#include <ctype.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "lex.h" X#include "tree.h" /* DOTILDE */ X#include "tty.h" X#include "table.h" X#include "expand.h" X XArea aedit; X#define AEDIT &aedit /* area for kill ring and macro defns */ X X#undef CTRL /* _BSD brain damage */ X#define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */ X#define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */ X X#if ! defined S_ISDIR X#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) X#endif X X#if ! defined S_ISREG X#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) X#endif X X#if defined _CRAY2 Xextern unsigned sleep(); X#endif X X/* values returned by keyboard functions */ X#define KSTD 0 X#define KPREF 1 /* ^[, ^X */ X#define KEOL 2 /* ^M, ^J */ X#define KINTR 3 /* ^G, ^C */ X Xstruct x_ftab { X int (*xf_func)(); X char *xf_name; X char xf_db_tab; X char xf_db_char; X short xf_flags; X}; X X#define XF_NINPUT 1 X#define XF_ALLOC 2 X#define XF_NOBIND 4 X X#define isfs(c) (c == ' ' || c == '\t') X#define BEL 0x07 X#define CMASK 0x7F /* 7-bit ASCII character mask */ X Xtypedef int bool_t; X#define FALSE 0 X#define TRUE 1 X Xstatic bool_t x_mode = FALSE; Xstatic int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X'); Xstatic char **x_histp; /* history position */ Xstatic char *xbuf; /* beg input buffer */ Xstatic char *xend; /* end input buffer */ Xstatic char *xcp; Xstatic char *xep; Xstatic int (*x_last_command)(); X/*static struct x_ftab *x_tab[3][128];*/ Xstatic struct x_ftab Const *(*x_tab)[128] = NULL; /* key definition */ Xstatic char *(*x_atab)[128] = NULL; /* macro definitions */ X#define KILLSIZE 20 Xstatic char *killstack[KILLSIZE]; Xstatic int killsp, killtp; Xstatic int x_curprefix; Xstatic char *macroptr; Xstatic int first_time = 1; Xstatic int x_maxlen; /* to determine column width */ Xstatic int x_cols = 80; /* todo: $COLUMNS */ X Xstatic void x_flush(), x_putc(), x_puts(); Xstatic void x_goto(), x_bs(), x_delete(), x_ins(), x_mapin(); Xstatic int x_fword(), x_bword(), x_size(), x_size_str(); Xstatic void x_zotc(), x_zots(), x_push(), x_redraw(), x_load_hist(); Xstatic void compl_command(), compl_dec(), compl_file(); Xstatic int x_insert(), x_ins_string(), x_del_back(); Xstatic int x_del_char(), x_del_bword(), x_mv_bword(), x_mv_fword(); Xstatic int x_del_fword(), x_mv_back(), x_mv_forw(), x_search_char(); Xstatic int x_newline(), x_end_of_text(), x_abort(), x_error(); Xstatic int x_beg_hist(), x_end_hist(), x_prev_com(), x_next_com(); Xstatic int x_search_hist(), x_del_line(), x_mv_end(), x_mv_begin(); Xstatic int x_draw_line(), x_transpose(), x_meta1(), x_meta2(); Xstatic int x_kill(), x_yank(), x_meta_yank(), x_literal(); Xstatic int x_stuffreset(), x_stuff(), x_complete(), x_enumerate(); X#if SILLY Xstatic int x_game_of_life(); X#endif Xstatic int x_comp_file(), x_comp_comm(); Xstatic int x_list_file(), x_list_comm(); Xstatic int strmatch(); X Xstatic struct x_ftab Const x_ftab[] = { X {x_insert, "auto-insert", 0, 0, 0 }, X {x_error, "error", 0, 0, 0 }, X {x_ins_string, "macro-string", 0, 0, XF_NOBIND|XF_ALLOC}, X/* Do not move the above! */ X {x_del_back, "delete-char-backward", 0, CTRL('H'), 0 }, X {x_del_char, "delete-char-forward", 0, CTRL('D'), 0 }, X {x_del_bword, "delete-word-backward", 0, CTRL('W'), 0 }, X {x_mv_bword, "backward-word", 1, 'b', 0 }, X {x_mv_fword, "forward-word", 1, 'f', 0 }, X {x_del_fword, "delete-word-forward", 1, 'd', 0 }, X {x_mv_back, "backward-char", 0, CTRL('B'), 0 }, X {x_mv_forw, "forward-char", 0, CTRL('F'), 0 }, X {x_search_char, "search-character", 0, CTRL(']'), 0 }, X {x_newline, "newline", 0, CTRL('M'), 0 }, X {x_newline, "newline", 0, CTRL('J'), 0 }, X {x_end_of_text, "eot", 0, CTRL('_'), 0 }, X {x_abort, "abort", 0, CTRL('G'), 0 }, X {x_prev_com, "up-history", 0, CTRL('P'), XF_NINPUT}, X {x_next_com, "down-history", 0, CTRL('N'), XF_NINPUT}, X {x_search_hist, "search-history", 0, CTRL('R'), XF_NINPUT}, X {x_beg_hist, "beginning-of-history", 1, '<', XF_NINPUT}, X {x_end_hist, "end-of-history", 1, '>', XF_NINPUT}, X {x_del_line, "kill-line", 0, CTRL('U'), 0 }, X {x_mv_end, "end-of-line", 0, CTRL('E'), 0 }, X {x_mv_begin, "beginning-of-line", 0, CTRL('A'), 0 }, X {x_draw_line, "redraw", 0, CTRL('L'), 0 }, X {x_meta1, "prefix-1", 0, CTRL('['), 0 }, X {x_meta2, "prefix-2", 0, CTRL('X'), 0 }, X {x_kill, "kill-to-eol", 0, CTRL('K'), 0 }, X {x_yank, "yank", 0, CTRL('Y'), 0 }, X {x_meta_yank, "yank-pop", 1, 'y', 0 }, X {x_literal, "quote", 0, CTRL('^'), 0 }, X {x_stuffreset, "stuff-reset", 0, 0, 0 }, X#if BRL && defined(TIOCSTI) X {x_stuff, "stuff", 0, CTRL('T'), 0 }, X {x_transpose, "transpose-chars", 0, 0, 0 }, X#else X {x_stuff, "stuff", 0, 0, 0 }, X {x_transpose, "transpose-chars", 0, CTRL('T'), 0 }, X#endif X {x_complete, "complete", 1, CTRL('['), 0 }, X {x_enumerate, "list", 1, '?', 0 }, X {x_comp_file, "complete-file", 2, CTRL('X'), 0 }, X {x_comp_comm, "complete-command", 2, CTRL('['), 0 }, X {x_list_file, "list-file", 0, 0, 0 }, X {x_list_comm, "list-command", 2, '?', 0 }, X#if SILLY X {x_game_of_life, "play-game-of-life", 0, 0, 0 }, X#endif X { 0 } X}; X X#define xft_insert &x_ftab[0] X#define xft_error &x_ftab[1] X#define xft_ins_string &x_ftab[2] X Xint Xx_read(fd, buf, len) X int fd; /* not used */ X char *buf; X size_t len; X{ X char c; X int i; X int (*func)(); X extern x_insert(); X X (void)set_xmode(TRUE); X xbuf = buf; xend = buf + len; X xcp = xep = buf; X *xcp = 0; X x_curprefix = 0; X macroptr = null; X x_histp = histptr + 1; X X while (1) { X x_flush(); X if (*macroptr) { X c = *macroptr++; X if (*macroptr == 0) X macroptr = null; X } X else { X i = read(ttyfd, &c, 1); X if (i != 1) X goto Exit; X } X X if (x_curprefix == -1) X func = x_insert; X else X func = x_tab[x_curprefix][c&CMASK]->xf_func; X if (func == NULL) X func = x_error; X i = c | (x_curprefix << 8); X x_curprefix = 0; X switch (i = (*func)(i)) { X case KSTD: X x_last_command = func; X case KPREF: X break; X case KEOL: X i = xep - xbuf; X x_last_command = 0; X /* XXX -- doesn't get them all */ X if (strncmp(xbuf, "stty", 4) == 0) X first_time = 1; X goto Exit; X case KINTR: /* special case for interrupt */ X i = -1; X errno = EINTR; X goto Exit; X } X } X Exit: X (void)set_xmode(FALSE); X if (i < 0 && errno == EINTR) X trapsig(SIGINT); X return i; X} X Xstatic int Xx_insert(c) { X char str[2]; X X /* X * Should allow tab and control chars. X */ X if (c == 0) { X x_putc(BEL); X return KSTD; X } X str[0] = c; X str[1] = 0; X x_ins(str); X return KSTD; X} X Xstatic int Xx_ins_string(c) X{ X if (*macroptr) { X x_putc(BEL); X return KSTD; X } X macroptr = x_atab[c>>8][c & CMASK]; X return KSTD; X} X Xstatic void Xx_ins(cp) X char *cp; X{ X int count, i; X X count = strlen(cp); X if (xep+count >= xend) { X x_putc(BEL); X return; X } X X if (xcp != xep) X memmove(xcp+count, xcp, xep - xcp + 1); X else X xcp[count] = 0; X memmove(xcp, cp, count); X x_zots(xcp); X xcp += count; X xep += count; X i = xep - xcp; X cp = xep; X while (i--) X x_bs(*--cp); X return; X} X Xstatic int Xx_del_back(c) { X if (xcp == xbuf) { X x_putc(BEL); X return KSTD; X } X x_goto(xcp - 1); X x_delete(1); X return KSTD; X} X Xstatic int Xx_del_char(c) { X if (xcp == xep) { X x_putc(BEL); X return KSTD; X } X x_delete(1); X return KSTD; X} X Xstatic void Xx_delete(nc) { X int i,j; X char *cp; X X if (nc == 0) X return; X xep -= nc; X cp = xcp; X j = 0; X i = nc; X while (i--) { X j += x_size(*cp++); X } X memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */ X x_zots(xcp); X i = j; X while (i--) X x_putc(' '); X i = j; X while (i--) X x_putc('\b'); X /*x_goto(xcp);*/ X i = xep - xcp; X cp = xep; X while (i--) X x_bs(*--cp); X return; X} X Xstatic int Xx_del_bword(c) { X x_delete(x_bword()); X return KSTD; X} X Xstatic int Xx_mv_bword(c) { X (void)x_bword(); X return KSTD; X} X Xstatic int Xx_mv_fword(c) { X x_goto(xcp + x_fword()); X return KSTD; X} X Xstatic int Xx_del_fword(c) { X x_delete(x_fword()); X return KSTD; X} X Xstatic int Xx_bword() { X int nc = 0; X register char *cp = xcp; X X if (cp == xbuf) { X x_putc(BEL); X return 0; X } X while (cp != xbuf && isfs(cp[-1])) { X cp--; X nc++; X } X while (cp != xbuf && !isfs(cp[-1])) { X cp--; X nc++; X } X x_goto(cp); X return nc; X} X Xstatic int Xx_fword() { X int nc = 0; X char *cp = xcp; X X if (cp == xep) { X x_putc(BEL); X return 0; X } X while (cp != xep && !isfs(*cp)) { X cp++; X nc++; X } X while (cp != xep && isfs(*cp)) { X cp++; X nc++; X } X return nc; X} X Xstatic void Xx_goto(cp) X register char *cp; X{ X if (cp < xcp) { /* move back */ X while (cp < xcp) X x_bs(*--xcp); X } else X if (cp > xcp) { /* move forward */ X while (cp > xcp) X x_zotc(*xcp++); X } X} X Xstatic void Xx_bs(c) { X register i; X i = x_size(c); X while (i--) X x_putc('\b'); X} X Xstatic int Xx_size_str(cp) X register char *cp; X{ X register size = 0; X while (*cp) X size += x_size(*cp++); X return size; X} X Xstatic int Xx_size(c) { X if (c=='\t') X return 4; /* Kludge, tabs are always four spaces. */ X if (c < ' ' || c == 0x7F) /* ASCII control char */ X return 2; X return 1; X} X Xstatic void Xx_zots(str) X register char *str; X{ X while (*str) X x_zotc(*str++); X} X Xstatic void Xx_zotc(c) X int c; X{ X if (c == '\t') { X /* Kludge, tabs are always four spaces. */ X x_puts(" "); X } else if (c < ' ' || c == 0x7F) { /* ASCII */ X x_putc('^'); X x_putc(UNCTRL(c)); X } else X x_putc(c); X} X X/* tty output */ X Xstatic void Xx_flush() X{ X fflush(stdout); X} X Xstatic void Xx_putc(c) X int c; X{ X putc(c, stdout); X} X Xstatic void Xx_puts(s) X register char *s; X{ X while (*s != 0) X putc(*s++, stdout); X} X Xstatic int Xx_mv_back(c) { X if (xcp == xbuf) { X x_putc(BEL); X return KSTD; X } X x_goto(xcp-1); X return KSTD; X} X Xstatic int Xx_mv_forw(c) { X if (xcp == xep) { X x_putc(BEL); X return KSTD; X } X x_goto(xcp+1); X return KSTD; X} X Xstatic int Xx_search_char(c) { X char ci, *cp; X X *xep = '\0'; X if (read(ttyfd, &ci, 1) != 1 || X /* we search forward, I don't know what Korn does */ X (cp = (xcp == xep) ? NULL : strchr(xcp+1, ci)) == NULL && X (cp = strchr(xbuf, ci)) == NULL) { X x_putc(BEL); X return KSTD; X } X x_goto(cp); X return KSTD; X} X Xstatic int Xx_newline(c) { X x_putc('\n'); X x_flush(); X *xep++ = '\n'; X return KEOL; X} X Xstatic int Xx_end_of_text(c) { X#if 0 X x_store_hist(); X#endif X return KEOL; X} X Xstatic int x_beg_hist(c) {x_load_hist(history); return KSTD;} X Xstatic int x_end_hist(c) {x_load_hist(histptr); return KSTD;} X Xstatic int x_prev_com(c) {x_load_hist(x_histp-1); return KSTD;} X Xstatic int x_next_com(c) {x_load_hist(x_histp+1); return KSTD;} X Xstatic void Xx_load_hist(hp) X register char **hp; X{ X int oldsize; X X if (hp < history || hp > histptr) { X x_putc(BEL); X return; X } X x_histp = hp; X oldsize = x_size_str(xbuf); X (void)strcpy(xbuf, *hp); X xep = xcp = xbuf + strlen(*hp); X x_redraw(oldsize); X} X Xstatic int x_search(), x_match(); X X/* reverse incremental history search */ Xstatic int Xx_search_hist(ci) X{ X int offset = -1; /* offset of match in xbuf, else -1 */ X static char c[2]; /* input buffer */ X char pat [256+1]; /* pattern buffer */ X register char *p = pat; X int (*func)(); X X *p = 0; X while (1) { X if (offset < 0) { X x_puts("\nI-search: "); X x_zots(pat); X } X x_flush(); X if (read(ttyfd, c, 1) < 1) X return KSTD; X func = x_tab[0][*c&CMASK]->xf_func; X if (*c == CTRL('[')) X break; X else if (func == x_search_hist) X offset = x_search(pat, offset); X else if (func == x_del_back) X continue; /* todo */ X else if (func == x_insert) { X /* add char to pattern */ X *p++ = *c, *p = 0; X if (offset >= 0) { X /* already have partial match */ X offset = x_match(xbuf, pat); X if (offset >= 0) { X x_goto(xbuf + offset + (p - pat) - (*pat == '^')); X continue; X } X } X offset = x_search(pat, offset); X } else { /* other command */ X macroptr = c; /* push command */ X break; X } X } X if (offset < 0) X x_redraw(-1); X return KSTD; X} X X/* search backward from current line */ Xstatic int Xx_search(pat, offset) X char *pat; X int offset; X{ X register char **hp; X int i; X X for (hp = x_histp; --hp >= history; ) { X i = x_match(*hp, pat); X if (i >= 0) { X if (offset < 0) X x_putc('\n'); X x_load_hist(hp); X x_goto(xbuf + i + strlen(pat) - (*pat == '^')); X return i; X } X } X x_putc(BEL); X x_histp = histptr; X return -1; X} X X/* return position of first match of pattern in string, else -1 */ Xstatic int Xx_match(str, pat) X char *str, *pat; X{ X if (*pat == '^') { X return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1; X } else { X char *q = strstr(str, pat); X return (q == NULL) ? -1 : q - str; X } X} X Xstatic int Xx_del_line(c) { X int i, j; X X *xep = 0; X i = xep- xbuf; X j = x_size_str(xbuf); X xcp = xbuf; X x_push(i); X xep = xbuf; X *xcp = 0; X x_redraw(j); X return KSTD; X} X Xstatic int Xx_mv_end(c) { X x_goto(xep); X return KSTD; X} X Xstatic int Xx_mv_begin(c) { X x_goto(xbuf); X return KSTD; X} X Xstatic int Xx_draw_line(c) X{ X x_redraw(-1); X return KSTD; X X} X Xstatic void Xx_redraw(limit) { X int i, j; X char *cp; X X if (limit == -1) X x_putc('\n'); X else X x_putc('\r'); X x_flush(); X pprompt(prompt); X x_zots(xbuf); X if (limit != -1) { X i = limit - x_size_str(xbuf); X j = 0; X while (j < i) { X x_putc(' '); X j++; X } X while (j--) X x_putc('\b'); X } X i = xep - xcp; X cp = xep; X while (i--) X x_bs(*--cp); X return; X} X Xstatic int Xx_transpose(c) { X char tmp; X if (xcp == xbuf || xcp == xep) { X x_putc(BEL); X return KSTD; X } X x_bs(xcp[-1]); X x_zotc(xcp[0]); X x_zotc(xcp[-1]); X tmp = xcp[-1]; X xcp[-1] = xcp[0]; X xcp[0] = tmp; X x_bs(xcp[0]); X return KSTD; X} X Xstatic int Xx_literal(c) { X x_curprefix = -1; X return KSTD; X} X Xstatic int Xx_meta1(c) { X x_curprefix = 1; X return KPREF; X} X Xstatic int Xx_meta2(c) { X x_curprefix = 2; X return KPREF; X} X Xstatic int Xx_kill(c) { X int i; X X i = xep - xcp; X x_push(i); X x_delete(i); X return KSTD; X} X Xstatic void Xx_push(nchars) { X char *cp; X cp = alloc((size_t)(nchars+1), AEDIT); X memmove(cp, xcp, nchars); X cp[nchars] = 0; X if (killstack[killsp]) X afree((Void *)killstack[killsp], AEDIT); X killstack[killsp] = cp; X killsp = (killsp + 1) % KILLSIZE; X} X Xstatic int Xx_yank(c) { X if (killsp == 0) X killtp = KILLSIZE; X else X killtp = killsp; X killtp --; X if (killstack[killtp] == 0) { X x_puts("\nnothing to yank"); X x_redraw(-1); X return KSTD; X } X x_ins(killstack[killtp]); X return KSTD; X} X Xstatic int Xx_meta_yank(c) { X int len; X if (x_last_command != x_yank && x_last_command != x_meta_yank) { X x_puts("\nyank something first"); X x_redraw(-1); X return KSTD; X } X len = strlen(killstack[killtp]); X x_goto(xcp - len); X x_delete(len); X do { X if (killtp == 0) X killtp = KILLSIZE - 1; X else X killtp--; X } while (killstack[killtp] == 0); X x_ins(killstack[killtp]); X return KSTD; X} X Xstatic int Xx_abort(c) { X /* x_zotc(c); */ X return KINTR; X} X Xstatic int Xx_error(c) { X x_putc(BEL); X return KSTD; X} X X#if _BSD X#if defined TIOCGATC Xstatic struct ttychars lchars, lcharsorig; X#else Xstatic struct tchars tchars, tcharsorig; Xstatic struct ltchars ltchars, ltcharsorig; X#endif X#endif X X#if _BSD Xbool_t Xset_xmode(onoff) Xbool_t onoff; X{ X bool_t prev; Xtypedef struct sgttyb Sgttyb; X static Sgttyb cb; X static Sgttyb orig; X X if (x_mode == onoff) return x_mode; X prev = x_mode; X x_mode = onoff; X if (onoff) { X if (first_time) { X (void)ioctl(0, TIOCGETP, &cb); X orig = cb; X cb.sg_flags &= ~ECHO; X cb.sg_flags |= CBREAK; X#if defined TIOCGATC X (void)ioctl(0, TIOCGATC, &lcharsorig); X lchars = lcharsorig; X lchars.tc_suspc = -1; X lchars.tc_dsuspc = -1; X lchars.tc_lnextc = -1; X lchars.tc_statc = -1; X lchars.tc_intrc = -1; X lchars.tc_quitc = -1; X lchars.tc_rprntc = -1; X#else X (void)ioctl(0, TIOCGETC, &tcharsorig); X (void)ioctl(0, TIOCGLTC, <charsorig); X tchars = tcharsorig; X ltchars = ltcharsorig; X ltchars.t_suspc = -1; X ltchars.t_dsuspc = -1; X ltchars.t_lnextc = -1; X tchars.t_intrc = -1; X tchars.t_quitc = -1; X ltchars.t_rprntc = -1; X#endif X first_time = 0; X } X (void)ioctl(0, TIOCSETN, &cb); X#if defined TIOCGATC X (void)ioctl(0, TIOCSATC, &lchars); X#else X (void)ioctl(0, TIOCSETC, &tchars); X (void)ioctl(0, TIOCSLTC, <chars); X#endif X } X else { X (void)ioctl(0, TIOCSETN, &orig); X#if defined TIOCGATC X (void)ioctl(0, TIOCSATC, &lcharsorig); X#else X (void)ioctl(0, TIOCSETC, &tcharsorig); X (void)ioctl(0, TIOCSLTC, <charsorig); X#endif X } X return prev; X} X X#else /* !_BSD */ X Xbool_t Xset_xmode(onoff) Xbool_t onoff; X{ X bool_t prev; X static struct termio cb, orig; X X if (x_mode == onoff) return x_mode; X prev = x_mode; X x_mode = onoff; X X if (onoff) { X if (first_time) { X (void)ioctl(0, TCGETA, &cb); X orig = cb; X#if defined _CRAY2 /* brain-damaged terminal handler */ X cb.c_lflag &= ~(ICANON|ECHO); X /* rely on print routine to map '\n' to CR,LF */ X#else X cb.c_iflag &= ~(INLCR|ICRNL); X#if _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */ X cb.c_lflag &= ~(ICANON|ECHO); X#else X cb.c_lflag &= ~(ISIG|ICANON|ECHO); X#endif X cb.c_cc[VTIME] = 0; X cb.c_cc[VMIN] = 1; X#endif /* _CRAY2 */ X first_time = 0; X } X#if ! defined TCSETAW /* e.g. Cray-2 */ X /* first wait for output to drain */ X#if defined TCSBRK X (void)ioctl(0, TCSBRK, 1); X#else /* the following kludge is minimally intrusive, but sometimes fails */ X (void)sleep((unsigned)1); /* fake it */ X#endif X#endif X#if _BSD_SYSV || !defined(TCSETAW) X/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */ X (void)ioctl(0, TCSETA, &cb); X#else X (void)ioctl(0, TCSETAW, &cb); X#endif X } X else { X#if ! defined TCSETAW /* e.g. Cray-2 */ X /* first wait for output to drain */ X#if defined TCSBRK X (void)ioctl(0, TCSBRK, 1); X#else X/* doesn't seem to be necessary when leaving xmode */ X/* (void)sleep((unsigned)1); /* fake it */ X#endif X#endif X#if _BSD_SYSV || !defined(TCSETAW) X/* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */ X (void)ioctl(0, TCSETA, &orig); X#else X (void)ioctl(0, TCSETAW, &orig); X#endif X } X return prev; X} X#endif /* _BSD */ X Xstatic int Xx_stuffreset(c) X{ X#if defined TIOCSTI X (void)x_stuff(c); X return KINTR; X#else X x_zotc(c); X xcp = xep = xbuf; X *xcp = 0; X x_redraw(-1); X return KSTD; X#endif X} X Xstatic int Xx_stuff(c) X{ X#if defined TIOCSTI X char ch = c; X bool_t savmode = set_xmode(FALSE); X X (void)ioctl(0, TIOCSTI, &ch); X (void)set_xmode(savmode); X x_redraw(-1); X#endif X return KSTD; X} X Xstatic void Xx_mapin(cp) X char *cp; X{ X char *op; X X op = cp; X while (*cp) { X /* XXX -- should handle \^ escape? */ X if (*cp == '^') { X cp++; X if (*cp >= '?') /* includes '?'; ASCII */ X *op++ = CTRL(*cp); X else { X *op++ = '^'; X cp--; X } X } else X *op++ = *cp; X cp++; X } X *op = 0; X} X Xstatic char * Xx_mapout(c) X int c; X{ X static char buf[8]; X register char *p = buf; X X if (c < ' ' || c == 0x7F) { /* ASCII */ X *p++ = '^'; X *p++ = (c == 0x7F) ? '?' : (c | 0x40); X } else X *p++ = c; X *p = 0; X return buf; X} X Xstatic void Xx_print(prefix, key) X int prefix, key; X{ X if (prefix == 1) X shellf("%s", x_mapout(x_prefix1)); X if (prefix == 2) X shellf("%s", x_mapout(x_prefix2)); X shellf("%s = ", x_mapout(key)); X if (x_tab[prefix][key]->xf_func != x_ins_string) X shellf("%s\n", x_tab[prefix][key]->xf_name); X else X shellf("'%s'\n", x_atab[prefix][key]); X} X Xvoid Xx_bind(a1, a2, macro) X char *a1, *a2; X int macro; /* bind -m */ X{ X struct x_ftab Const *fp; X int prefix, key; X char *sp = NULL; X X if (x_tab == NULL) X errorf("cannot bind, not a tty\n"); X X if (a1 == NULL) { X for (prefix = 0; prefix < 3; prefix++) X for (key = 0; key < 0x80; key++) { X fp = x_tab[prefix][key]; X if (fp == NULL || X fp->xf_func == x_insert || fp->xf_func == x_error) X continue; X x_print(prefix, key); X } X return; X } X X x_mapin(a1); X prefix = key = 0; X for (;; a1++) { X key = *a1; X if (x_tab[prefix][key]->xf_func == x_meta1) X prefix = 1; X else X if (x_tab[prefix][key]->xf_func == x_meta2) X prefix = 2; X else X break; X } X X if (a2 == NULL) { X x_print(prefix, key); X return; X } X X if (*a2 == 0) X fp = xft_insert; X else if (!macro) { X for (fp = x_ftab; fp->xf_func; fp++) X if (strcmp(fp->xf_name, a2) == 0) X break; X if (fp->xf_func == NULL || (fp->xf_flags & XF_NOBIND)) X errorf("%s: no such function\n", a2); X if (fp->xf_func == x_meta1) X x_prefix1 = key; X if (fp->xf_func == x_meta2) X x_prefix2 = key; X } else { X fp = xft_ins_string; X x_mapin(a2); X sp = strsave(a2, AEDIT); X } X X if ((x_tab[prefix][key]->xf_flags & XF_ALLOC) && x_atab[prefix][key]) X afree((Void *)x_atab[prefix][key], AEDIT); X x_tab[prefix][key] = fp; X x_atab[prefix][key] = sp; X} X Xvoid Xx_init() X{ X register int i, j; X struct x_ftab Const *fp; X X ainit(AEDIT); X X x_tab = alloc(sizeofN(*x_tab, 3), AEDIT); X for (j = 0; j < 128; j++) X x_tab[0][j] = xft_insert; X for (i = 1; i < 3; i++) X for (j = 0; j < 128; j++) X x_tab[i][j] = xft_error; X for (fp = x_ftab; fp->xf_func; fp++) X if (fp->xf_db_char || fp->xf_db_tab) X x_tab[fp->xf_db_tab][fp->xf_db_char] = fp; X X x_atab = alloc(sizeofN(*x_atab, 3), AEDIT); X for (i = 1; i < 3; i++) X for (j = 0; j < 128; j++) X x_atab[i][j] = NULL; X} X X#if SILLY Xstatic int Xx_game_of_life(c) { X char newbuf [256+1]; X register char *ip, *op; X int i, len; X X i = xep - xbuf; X *xep = 0; X len = x_size_str(xbuf); X xcp = xbuf; X memmove(newbuf+1, xbuf, i); X newbuf[0] = 'A'; X newbuf[i] = 'A'; X for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) { X /* Empty space */ X if (*ip < '@' || *ip == '_' || *ip == 0x7F) { X /* Two adults, make whoopee */ X if (ip[-1] < '_' && ip[1] < '_') { X /* Make kid look like parents. */ X *op = '`' + ((ip[-1] + ip[1])/2)%32; X if (*op == 0x7F) /* Birth defect */ X *op = '`'; X } X else X *op = ' '; /* nothing happens */ X continue; X } X /* Child */ X if (*ip > '`') { X /* All alone, dies */ X if (ip[-1] == ' ' && ip[1] == ' ') X *op = ' '; X else /* Gets older */ X *op = *ip-'`'+'@'; X continue; X } X /* Adult */ X /* Overcrowded, dies */ X if (ip[-1] >= '@' && ip[1] >= '@') { X *op = ' '; X continue; X } X *op = *ip; X } X *op = 0; X x_redraw(len); X return KSTD; X} X#endif X X/* X * File/command name completion routines X */ X X/* type: 0 for list, 1 for completion */ X Xstatic XPtrV words; X Xstatic void Xadd_stash(dirnam, name) X char *dirnam; /* directory name, if file */ X char *name; X{ X char *cp; X register int type = 0; /* '*' if executable, '/' if directory, else 0 */ X register int len = strlen(name); X X /* determine file type */ X if (dirnam) { X struct stat statb; X char *buf = alloc((size_t)(strlen(dirnam)+len+2), ATEMP); X X if (strcmp(dirnam, ".") == 0) X *buf = '\0'; X else if (strcmp(dirnam, "/") == 0) X (void)strcpy(buf, "/"); X else X (void)strcat(strcpy(buf, dirnam), "/"); X (void)strcat(buf, name); X if (stat(buf, &statb)==0) X if (S_ISDIR(statb.st_mode)) X type = '/'; X else if (S_ISREG(statb.st_mode) && access(buf, 01)==0) X type = '*'; X if (type) X ++len; X afree((Void *)buf, ATEMP); X } X X if (len > x_maxlen) X x_maxlen = len; X X /* stash name for later sorting */ X cp = alloc((size_t)(len+1), ATEMP); X (void)strcpy(cp = alloc((size_t)(len+1), ATEMP), name); X if (dirnam && type) { /* append file type indicator */ X cp[len-1] = type; X cp[len] = '\0'; X } X XPput(words, cp); X} X Xstatic void Xlist_stash() X{ X register char **array, **record; X int items = 0, tabstop, loc, nrows, jump, offset; X X items = XPsize(words); X array = (char**) XPptrv(words); X if (items == 0) X return; X qsortp(XPptrv(words), (size_t)XPsize(words), xstrcmp); X X /* print names */ X x_maxlen = (x_maxlen/8 + 1) * 8; /* column width */ X nrows = (items-1) / (x_cols/x_maxlen) + 1; X for (offset = 0; offset < nrows; ++offset) { X tabstop = loc = 0; X x_putc('\n'); X for (jump = 0; offset+jump < items; jump += nrows) { X if (jump) X while (loc < tabstop) { X x_putc('\t'); X loc = (loc/8 + 1) * 8; X } X record = array + (offset + jump); X x_puts(*record); X afree((Void *)*record, ATEMP); X loc += strlen(*record); X tabstop += x_maxlen; /* next tab stop */ X } X } X X afree((Void*)array, ATEMP); X x_redraw(-1); X} X Xstatic int Xx_comp_comm(c) { X compl_command(1); X return KSTD; X} Xstatic int Xx_list_comm(c) { X compl_command(0); X return KSTD; X} Xstatic int Xx_complete(c) { X compl_dec(1); X return KSTD; X} Xstatic int Xx_enumerate(c) { X compl_dec(0); X return KSTD; X} Xstatic int Xx_comp_file(c) { X compl_file(1); X return KSTD; X} Xstatic int Xx_list_file(c) { X compl_file(0); X return KSTD; X} X Xstatic void Xcompl_dec(type) X{ X char *cp; X cp = xcp; X X while (cp != xbuf && !isfs(*cp)) X cp--; X if (cp == xbuf && strchr(cp, '/') == NULL) X compl_command(type); X else X compl_file(type); X} X Xstatic void Xcompl_file(type) X{ X char *str; X register char *cp, *xp; X char *lastp; X char *dirnam; X char buf [256+1]; X char bug [256+1]; X DIR *dirp; X struct dirent *dp; X long loc = -1; X int len; X int multi = 0; X X str = xcp; X cp = buf; X xp = str; X while (xp != xbuf) { X --xp; X if (isfs(*xp)) { X xp++; X break; X } X } X if (digit(*xp) && (xp[1] == '<' || xp[1] == '>')) X xp++; X while (*xp == '<' || *xp == '>') X xp++; X if (type) X while (*xcp && !isfs(*xcp)) X x_zotc(*xcp++); X else { X x_maxlen = 0; X XPinit(words, 16); X } X while (*xp && !isfs(*xp)) X *cp++ = *xp++; X X *cp = 0; X strcpy(buf, cp = substitute(buf, DOTILDE)); X afree((Void*)cp, ATEMP); X lastp = strrchr(buf, '/'); X if (lastp) X *lastp = 0; X X dirnam = (lastp == NULL) ? "." : (lastp == buf) ? "/" : buf; X dirp = opendir(dirnam); X if (dirp == NULL) { X x_putc(BEL); X return; X } X X if (lastp == NULL) X lastp = buf; X else X lastp++; X len = strlen(lastp); X X while ((dp = readdir(dirp)) != NULL) { X cp = dp->d_name; X if (cp[0] == '.' && X (cp[1] == '\0' || cp[1] == '.' && cp[2] == '\0')) X continue; /* always ignore . and .. */ X if (strncmp(lastp, cp, len) == 0) X if (type) { X if (loc == -1) { X (void)strcpy(bug, cp); X loc = strlen(cp); X } else { X multi = 1; X loc = strmatch(bug, cp); X bug[loc] = 0; X } X } else X add_stash(dirnam, cp); X } X (void)closedir(dirp); X X if (type) { X if (loc <= 0) { X x_putc(BEL); X return; X } X cp = bug + len; X x_ins(cp); X if (!multi) { X struct stat statb; X if (lastp == buf) X buf[0] = 0; X else if (lastp == buf + 1) { X buf[1] = 0; X buf[0] = '/'; X } else X (void)strcat(buf, "/"); X (void)strcat(buf, bug); X if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode)) X x_ins("/"); X else X x_ins(" "); X } X } else X list_stash(); X} X Xstatic void Xcompl_command(type) X{ X register struct tbl *tp; X char *str; X char buf [256+1]; X char bug [256+1]; X char *xp; X char *cp; X int len; X int multi; X int loc; X X str = xcp; X cp = buf; X xp = str; X while (xp != xbuf) { X --xp; X if (isfs(*xp)) { X xp++; X break; X } X } X if (type) X while (*xcp && !isfs(*xcp)) X x_zotc(*xcp++); X else { X x_maxlen = 0; X XPinit(words, 16); X } X while (*xp && !isfs(*xp)) X *cp++ = *xp++; X *cp = 0; X X len = strlen(buf); X loc = -1; X multi = 0; X X for (twalk(&commands); (tp = tnext()) != NULL; ) { X int klen; X X if (!(tp->flag&ISSET)) X continue; X klen = strlen(tp->name); X if (klen < len) X return; X if (strncmp(buf, tp->name, len) ==0) X if (type) { X if (loc == -1) { X (void)strcpy(bug, tp->name); X loc = klen; X } else { X multi = 1; X loc = strmatch(bug, tp->name); X bug[loc] = 0; X } X } else X add_stash((char *)0, tp->name); X } X X if (type) { X if (loc <= 0) { X x_putc(BEL); X return; X } X cp = bug + len; X x_ins(cp); X if (!multi) X x_ins(" "); X } else X list_stash(); X} X Xstatic int Xstrmatch(s1, s2) X register char *s1, *s2; X{ X register char *p; X X for (p = s1; *p == *s2++ && *p != 0; p++) X ; X return p - s1; X} X X#endif /* EDIT */ X SHAR_EOF true || echo 'restore of src/edit.c failed' fi # ============= src/history.c ============== if test -f 'src/history.c' -a X"$1" != X"-c"; then echo 'x - skipping src/history.c (File already exists)' else echo 'x - extracting src/history.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/history.c' && X/* X * command history X * X * only implements in-memory history. X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/history.c,v 3.2 88/11/21 10:34:30 egisin Exp $"; X X#include <stddef.h> X#include <stdio.h> X#include <string.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "lex.h" X Xchar **histget(); Xchar *histrpl(); X Xc_fc(wp) X register char **wp; X{ X register char *id; X FILE *f; X struct temp *tf; X register char **hp; X char **hbeg, **hend; X int lflag = 0, nflag = 0, sflag = 0; X X for (wp++; (id = *wp) != NULL && *id == '-' && !sflag; wp++) X switch (id[1]) { X case 'l': X lflag++; X break; X case 'n': X nflag++; X break; X case 's': X sflag++; X break; X } X X /* fc -s [pat=rep] [cmd], equivalent to Korn's fc -e - [pat=rep] */ X if (sflag) { X char *pat = NULL, *rep = NULL; X X hp = histptr - 1; X while ((id = *wp++) != NULL) X /* todo: multiple substitutions */ X if ((rep = strchr(id, '=')) != NULL) { X pat = id; X *rep++ = '\0'; X } else X hp = histget(id); X X if (hp == NULL || hp < history) X errorf("cannot find history\n"); X if (pat == NULL) X strcpy(line, *hp); X else X histrpl(*hp, pat, rep); X histsave(line); X histpush--; X line[0] = '\0'; X return 0; X } X X if (*wp != NULL) { X hbeg = histget(*wp++); /* first */ X if (*wp != NULL) X hend = histget(*wp++); /* last */ X else X hend = hbeg; X } else { X if (lflag) X hbeg = histptr - 12, hend = histptr; X else X hbeg = hend = histptr - 1; X if (hbeg < history) X hbeg = history; X } X if (hbeg == NULL || hend == NULL) X errorf("can't find history\n"); X X if (lflag) X f = stdout; X else { X nflag++; X tf = maketemp(ATEMP); X tf->next = e.temps; e.temps = tf; X f = fopen(tf->name, "w"); X if (f == NULL) X errorf("cannot create temp file %s", tf->name); X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ); X } X X for (hp = hbeg; hp <= hend; hp++) { X if (!nflag) X fprintf(f, "%3d: ", source->line - (int)(histptr-hp)); X fprintf(f, "%s\n", *hp); X } X X if (lflag) X return 0; X else X fclose(f); X X setstr(local("_"), tf->name); X command("${FCEDIT:-/bin/ed} $_"); /* edit temp file */ X X f = fopen(tf->name, "r"); X if (f == NULL) X errorf("cannot open temp file %s\n", tf->name); X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ); X /* we push the editted lines onto the history list */ X while (fgets(line, sizeof(line), f) != NULL) { X histsave(line); X histpush--; X } X line[0] = '\0'; X fclose(f); X X return 0; X} X X/* X * save command in history X */ Xvoid Xhistsave(cmd) X char *cmd; X{ X register char **hp = histptr; X char *cp; X X if (++hp >= history + HISTORY) { /* remove oldest command */ X afree((Void*)*history, APERM); X for (hp = history; hp < history + HISTORY - 1; hp++) X hp[0] = hp[1]; X } X *hp = strsave(cmd, APERM); X if ((cp = strchr(*hp, '\n')) != NULL) X *cp = '\0'; X histptr = hp; X} X X/* X * get pointer to history given pattern X * pattern is a number or string X */ Xchar ** Xhistget(str) X char *str; X{ X register char **hp = NULL; X X if (*str == '-') X hp = histptr + getn(str); X else X if (digit(*str)) X hp = histptr + (getn(str) - source->line); X else X if (*str == '?') { /* unanchored match */ X for (hp = histptr-1; hp >= history; hp--) X if (strstr(*hp, str+1) != NULL) X break; X } else { /* anchored match */ X for (hp = histptr; hp >= history; hp--) X if (strncmp(*hp, str, strlen(str)) == 0) X break; X } X X return (history <= hp && hp <= histptr) ? hp : NULL; X} X Xchar * Xhistrpl(s, pat, rep) X char *s; X char *pat, *rep; X{ X char *s1; X X if (strlen(s) - strlen(pat) + strlen(rep) >= LINE) X errorf("substitution too long\n"); X s1 = strstr(s, pat); X if (s1 == NULL) X errorf("substitution failed\n"); X *s1 = '\0'; X strcpy(line, s); /* first part */ X strcat(line, rep); /* replacement */ X strcat(line, s1 + strlen(pat)); /* last part */ X return line; X} X X#if 0 X X/* History file management routines (by DPK@BRL) */ X Xvoid Xhist_init() X{ X register struct namnod *n; X int fd; X X if (hist_fd >= 0 || (flags&oneflg)) X return; X if ((n = findnam(histname)) == (struct namnod *)0 X || n->namval == (char *)0) X return; X if ((fd = open(n->namval, O_RDWR)) >= 0) { X hist_load(fd); X (void)fcntl(fd, F_SETFL, O_APPEND); X } X hist_fd = fd; X} X Xvoid Xhist_finish() X{ X if (hist_fd >= 0) X (void)close(hist_fd); X hist_fd = -1; X} X Xvoid Xhist_record(buf, len) Xchar *buf; Xint len; X{ X if (hist_fd >= 0) X (void)write(hist_fd, buf, (unsigned)len); X} X Xvoid Xhist_load(fd) Xint fd; X{ X extern long lseek(); X struct stat sb; X char *x; X register char *cmdp, *end; X register int len; X register int i; X X if (fstat(fd, &sb) < 0 || sb.st_size <= 0) X return; X if (x = alloc((unsigned)(sb.st_size+1))) { X (void)lseek(fd, 0L, 0); X if ((len = read(fd, x, (unsigned)sb.st_size)) <= 0) { X free((struct blk *)x); X return; X } X x[len] = 0; X end = x; X for (;;) { X while(*end == NL) X end++; /* Skip NL */ X if (*end == 0) X break; X cmdp = end; X while(*end && *end != NL) X end++; /* Goto NL */ X if (*end == 0) X break; X if ((len = (end - cmdp)) < 2) X continue; X if (len >= BUFSIZ) X len = BUFSIZ - 1; /* Protection */ X i = curhist % NHISTORY; X if(histbuf[i]) X free((struct blk *)histbuf[i]); X histbuf[i] = alloc((unsigned)(len+1)); X (void)strncpy(histbuf[i], cmdp, len); X histbuf[i][len] = 0; X curhist++; X histpc=curhist; X } X free((struct blk *)x); X } X return; X} X X#endif X SHAR_EOF true || echo 'restore of src/history.c failed' fi true || echo 'restore of src/tree.c failed' echo End of part 3, continue with part 4 exit 0