Public Domain Korn Shell - Part.03 of 7
USENET Administration
netnews at netcom.UUCP
Wed Dec 12 22:36:21 AEST 1990
#!/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 at 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
More information about the Alt.sources
mailing list