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, &ltcharsorig);
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, &ltchars);
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, &ltcharsorig);
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