[comp.sources.unix] v14i066: Jove, an emacs variant, version 4.9, Part10/21

rsalz@bbn.com (Rich Salz) (04/26/88)

Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
Posting-number: Volume 14, Issue 66
Archive-name: jove4.9/part10

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 10 (of 21)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './extend.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./extend.c'\"
else
echo shar: Extracting \"'./extend.c'\" \(19914 characters\)
sed "s/^X//" >'./extend.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is    *
X * included in all the files.                                              *
X ***************************************************************************/
X
X#include "jove.h"
X#include "io.h"
X#include "termcap.h"
X#include "ctype.h"
X#ifdef JOB_CONTROL
X#	include <signal.h>
X#endif
X
X#ifdef MAC
X#	include "mac.h"
X#else
X#	include <varargs.h>
X#endif
X
X#ifdef MSDOS
X#include <process.h>
X#endif
X
X#ifdef MAC
X#	undef private
X#	define private
X#endif
X
X#ifdef	LINT_ARGS
private	void
X	fb_aux(data_obj *, data_obj **, char *, char *),
X	find_binds(data_obj *, char *),
X	vpr_aux(struct variable *, char *);
X#else
private	void
X	fb_aux(),
X	find_binds(),
X	vpr_aux();
X#endif	/* LINT_ARGS */
X
X#ifdef MAC
X#	undef private
X#	define private static
X#endif
X
X
int	InJoverc = 0;
X
extern int	getch(),
X		getchar();
X
X/* Auto execute code */
X
X#define NEXECS	20
X
private struct {
X	char	*a_pattern;
X	data_obj	*a_cmd;
X} AutoExecs[NEXECS] = {0};
X
private int	ExecIndex = 0;
X
X/* Command auto-execute. */
X
void
CAutoExec()
X{
X	DefAutoExec(findcom);
X}
X
X/* Macro auto-execute. */
X
void
MAutoExec()
X{
X	DefAutoExec(findmac);
X}
X
X/* VARARGS0 */
X
void
DefAutoExec(proc)
X#ifdef LINT_ARGS
data_obj	*(*proc)();
X#else
data_obj	*(*proc)();
X#endif
X{
X	data_obj	*d;
X	char	*pattern;
X	int	i;
X
X	if (ExecIndex >= NEXECS)
X		complain("Too many auto-executes, max %d.", NEXECS);
X	if ((d = (*proc)(ProcFmt)) == 0)
X		return;
X	pattern = do_ask("\r\n", (int (*)()) 0, (char *) 0, ": %f %s ", d->Name);
X	if (pattern != 0)
X	    for (i = 0; i < ExecIndex; i++)
X		if ((AutoExecs[i].a_cmd == d) &&
X		    (strcmp(pattern, AutoExecs[i].a_pattern) == 0))
X		    	return;		/* eliminate duplicates */
X	AutoExecs[ExecIndex].a_pattern = copystr(pattern);
X	AutoExecs[ExecIndex].a_cmd = d;
X	ExecIndex += 1;
X}
X
X/* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
X   same kind of file (i.e., match the same pattern) or OLD is 0 and it
X   matches, OR if the pattern is 0 (none was specified) then, we execute
X   the command associated with that kind of file. */
X
void
DoAutoExec(new, old)
register char	*new,
X		*old;
X{
X	register int	i;
X
X	set_arg_value(1);
X	for (i = 0; i < ExecIndex; i++)
X		if ((AutoExecs[i].a_pattern == 0) ||
X		    ((new != 0 && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
X		     (old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
X			ExecCmd(AutoExecs[i].a_cmd);
X}
X
void
BindAKey()
X{
X	BindSomething(findcom);
X}
X
void
BindMac()
X{
X	BindSomething(findmac);
X}
X
extern void	EscPrefix(),
X		CtlxPrefix(),
X		MiscPrefix();
X
data_obj **
IsPrefix(cp)
data_obj	*cp;
X{
X#ifdef MAC
X	void (*proc)();
X#else
X	int	(*proc)();
X#endif
X	
X	if (cp == 0 || (cp->Type & TYPEMASK) != FUNCTION)
X		return 0;
X	proc = ((struct cmd *) cp)->c_proc;
X	if (proc == EscPrefix)
X		return pref1map;
X	if (proc == CtlxPrefix)
X		return pref2map;
X	if (proc == MiscPrefix)
X		return miscmap;
X	return 0;
X}
X
void
UnbindC()
X{
X	char	*keys;
X	data_obj	**map = mainmap;
X
X	keys = ask((char *) 0, ProcFmt);
X	for (;;) {
X		if (keys[1] == '\0')
X			break;
X		if ((map = IsPrefix(map[*keys])) == 0)
X			break;
X		keys += 1;
X	}
X	if (keys[1] != 0)
X		complain("That's not a legitimate key sequence.");
X	map[keys[0]] = 0;
X}
X		
int
addgetc()
X{
X	int	c;
X
X	if (!InJoverc) {
X		Asking = strlen(mesgbuf);
X		c = getch();
X		Asking = 0;
X		add_mess("%p ", c);
X	} else {
X		c = getch();
X		if (c == '\n')
X			return EOF;	/* this isn't part of the sequence */
X		else if (c == '\\') {
X			if ((c = getch()) == LF)
X				complain("[Premature end of line]");
X		} else if (c == '^') {
X			if ((c = getch()) == '?')
X				c = RUBOUT;
X			else if (isalpha(c) || index("@[\\]^_", c))
X				c = CTL(c);
X			else
X				complain("[Unknown control character]");
X		}
X	}
X	return c;
X}
X
void
BindWMap(map, lastkey, cmd)
data_obj	**map,
X		*cmd;
X{
X	data_obj	**nextmap;
X	int	c;
X
X	c = addgetc();
X	if (c == EOF) {
X		if (lastkey == EOF)
X			complain("[Empty key sequence]");
X		complain("[Premature end of key sequence]");
X	} else {
X		if (nextmap = IsPrefix(map[c]))
X			BindWMap(nextmap, c, cmd);
X		else {
X			map[c] = cmd;
X#ifdef MAC
X			((struct cmd *) cmd)->c_key = c;	/* see about_j() in mac.c */
X			if(map == mainmap) ((struct cmd *) cmd)->c_map = F_MAINMAP;
X			else if(map == pref1map) ((struct cmd *) cmd)->c_map = F_PREF1MAP;
X			else if(map == pref2map) ((struct cmd *) cmd)->c_map = F_PREF2MAP;
X#endif
X		}
X	}
X}
X
X/* VARARGS0 */
X
void
BindSomething(proc)
X#ifdef LINT_ARGS
data_obj	*(*proc)();
X#else
data_obj	*(*proc)();
X#endif
X{
X	data_obj	*d;
X
X	if ((d = (*proc)(ProcFmt)) == 0)
X		return;
X	s_mess(": %f %s ", d->Name);
X	BindWMap(mainmap, EOF, d);
X}
X
X/* Describe key */
X
void
DescWMap(map, key)
data_obj	**map;
X{
X	data_obj	*cp = map[key],
X			**prefp;
X
X	if (cp == 0)
X		add_mess("is unbound.");
X	else if (prefp = IsPrefix(cp))
X		DescWMap(prefp, addgetc());
X	else
X		add_mess("is bound to %s.", cp->Name);
X}
X
void
KeyDesc()
X{
X	s_mess(ProcFmt);
X	DescWMap(mainmap, addgetc());
X}
X
void
DescCom()
X{
X	data_obj	*dp;
X	char	pattern[100],
X		doc_type[40],
X		*file = CmdDb;
X	File	*fp;
X
X	if (!strcmp(LastCmd->Name, "describe-variable"))
X		dp = (data_obj *) findvar(ProcFmt);
X	else
X		dp = (data_obj *) findcom(ProcFmt);
X	if (dp == 0)
X		return;
X	fp = open_file(file, iobuff, F_READ, COMPLAIN, QUIET);
X	Placur(ILI, 0);
X	flusho();
X	sprintf(pattern, "^:entry \"%s\" \"\\([^\"]*\\)\"", dp->Name);
X	TOstart("Help", TRUE);
X	for (;;) {
X		if (f_gets(fp, genbuf, LBSIZE) == EOF) {
X			Typeout("There is no documentation for \"%s\".", dp->Name);
X			goto outahere;
X		}
X		if ((strncmp(genbuf, ":entry", 6) == 0) && LookingAt(pattern, genbuf, 0))
X			break;
X	}
X	/* found it ... let's print it */
X	putmatch(1, doc_type, sizeof doc_type);
X	if (strcmp("Variable", doc_type) == 0)
X		Typeout(dp->Name);
X	else if (strcmp("Command", doc_type) == 0) {
X		char	binding[128];
X
X		find_binds(dp, binding);
X		if (blnkp(binding))
X			Typeout("To invoke %s, type \"ESC X %s<cr>\".",
X				dp->Name,
X				dp->Name);
X		else
X			Typeout("Type \"%s\" to invoke %s.", binding, dp->Name);
X	}
X	Typeout("");
X	while (f_gets(fp, genbuf, LBSIZE) != EOF)
X		if (strncmp(genbuf, ":entry", 6) == 0)
X			goto outahere;
X		else
X			Typeout("%s", genbuf);
outahere:
X	f_close(fp);
X	TOstop();
X}
X
void
DescBindings()
X{
X	extern void	Typeout();
X
X	TOstart("Key Bindings", TRUE);
X	DescMap(mainmap, NullStr);
X	TOstop();
X}
X
extern int specialmap;
X
void
DescMap(map, pref)
data_obj	**map;
char	*pref;
X{
X	int	c1,
X		c2 = 0,
X		numbetween;
X	char	keydescbuf[40];
X	data_obj	**prefp;
X
X#ifdef IBMPC
X	specialmap = (map == miscmap);
X#endif
X
X	for (c1 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
X		c2 = c1;
X		if (map[c1] == 0)
X			continue;
X		while (++c2 < NCHARS && map[c1] == map[c2])
X			;
X		c2 -= 1;
X		numbetween = c2 - c1;
X		if (numbetween == 1)
X			sprintf(keydescbuf, "%s {%p,%p}", pref, c1, c2);
X		else if (numbetween == 0)
X			sprintf(keydescbuf, "%s %p", pref, c1);
X		else
X			sprintf(keydescbuf, "%s [%p-%p]", pref, c1, c2);
X		if ((prefp = IsPrefix(map[c1])) && (prefp != map))
X			DescMap(prefp, keydescbuf);
X		else
X			Typeout("%-18s%s", keydescbuf, map[c1]->Name);
X	}
X}
X
private void
find_binds(dp, buf)
data_obj	*dp;
char	*buf;
X{
X	char	*endp;
X
X	buf[0] = '\0';
X	fb_aux(dp, mainmap, (char *) 0, buf);
X	endp = buf + strlen(buf) - 2;
X	if ((endp > buf) && (strcmp(endp, ", ") == 0))
X		*endp = '\0';
X}
X
private void
fb_aux(cp, map, prefix, buf)
register data_obj	*cp,
X			**map;
char	*buf,
X	*prefix;
X{
X	int	c1,
X		c2;
X	char	*bufp = buf + strlen(buf),
X		prefbuf[20];
X	data_obj	**prefp;
X
X#ifdef IBMPC
X	specialmap = (map == miscmap);
X#endif	
X
X	for (c1 = c2 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
X		c2 = c1;
X		if (map[c1] == cp) {
X			while (++c2 < NCHARS && map[c1] == map[c2])
X				;
X			c2 -= 1;
X			if (prefix)
X				sprintf(bufp, "%s ", prefix);
X			bufp += strlen(bufp);
X			switch (c2 - c1) {
X			case 0:
X				sprintf(bufp, "%p, ", c1);
X				break;
X	
X			case 1:
X				sprintf(bufp, "{%p,%p}, ", c1, c2);
X				break;
X	
X			default:
X				sprintf(bufp, "[%p-%p], ", c1, c2);
X				break;
X			}
X		}
X		if ((prefp = IsPrefix(map[c1])) && (prefp != map))  {
X			sprintf(prefbuf, "%p", c1);
X			fb_aux(cp, prefp, prefbuf, bufp);
X		}
X		bufp += strlen(bufp);
X	}
X}
X
void
Apropos()
X{
X	register struct cmd	*cp;
X	register struct macro	*m;
X	register struct variable	*v;
X	char	*ans;
X	int	anyfs = NO,
X		anyvs = NO,
X		anyms = NO;
X	char	buf[256];
X
X	ans = ask((char *) 0, ": %f (keyword) ");
X	TOstart("Help", TRUE);
X	for (cp = commands; cp->Name != 0; cp++)
X		if (sindex(ans, cp->Name)) {
X			if (anyfs == 0) {
X				Typeout("Commands");
X				Typeout("--------");
X			}
X			find_binds((data_obj *) cp, buf);
X			if (buf[0])
X				Typeout(": %-35s(%s)", cp->Name, buf);
X			else
X				Typeout(": %s", cp->Name);
X			anyfs = YES;
X		}
X	if (anyfs)
X		Typeout(NullStr);
X	for (v = variables; v->Name != 0; v++)
X		if (sindex(ans, v->Name)) {
X			if (anyvs == 0) {
X				Typeout("Variables");
X				Typeout("---------");
X			}
X			anyvs = YES;
X			vpr_aux(v, buf);
X			Typeout(": set %-26s%s", v->Name, buf);
X		}
X	if (anyvs)
X		Typeout(NullStr);
X	for (m = macros; m != 0; m = m->m_nextm)
X		if (sindex(ans, m->Name)) {
X			if (anyms == 0) {
X				Typeout("Macros");
X				Typeout("------");
X			}
X			anyms = YES;
X			find_binds((data_obj *) m, buf);
X			if (buf[0])
X				Typeout(": %-35s(%s)", m->Name, buf);
X			else
X				Typeout(": %-35s%s", "execute-macro", m->Name);
X		}
X	TOstop();
X}
X
void
Extend()
X{
X	data_obj	*d;
X
X	if (d = findcom(": "))
X		ExecCmd(d);
X}
X
X/* Read a positive integer from CP.  It must be in base BASE, and
X   complains if it isn't.  If allints is nonzero, all the characters
X   in the string must be integers or we return -1; otherwise we stop
X   reading at the first nondigit. */
X
int
chr_to_int(cp, base, allints, result)
register char	*cp;
register int	*result;
X{
X	register int	c;
X	int	value = 0,
X		sign;
X
X	if ((c = *cp) == '-') {
X		sign = -1;
X		cp += 1;
X	} else
X		sign = 1;
X	while (c = *cp++) {
X		if (!isdigit(c)) {
X			if (allints == YES)
X				return INT_BAD;
X			break;
X		}
X		c = c - '0';
X		if (c >= base)
X			complain("You must specify in base %d.", base);
X		value = value * base + c;
X	}
X	*result = value * sign;
X	return INT_OKAY;
X}
X
int
ask_int(prompt, base)
char	*prompt;
int	base;
X{
X	char	*val = ask((char *) 0, prompt);
X	int	value;
X
X	if (chr_to_int(val, base, YES, &value) == INT_BAD)
X		complain("That's not a number!");
X	return value;
X}
X
private void
vpr_aux(vp, buf)
register struct variable	*vp;
char	*buf;
X{
X	switch (vp->v_flags & V_TYPEMASK) {
X	case V_BASE10:
X		sprintf(buf, "%d", *(vp->v_value));
X		break;
X
X	case V_BASE8:
X		sprintf(buf, "%o", *(vp->v_value));
X		break;
X
X	case V_BOOL:
X		sprintf(buf, (*(vp->v_value)) ? "on" : "off");
X		break;
X
X	case V_STRING:
X	case V_FILENAME:
X		sprintf(buf, "%s", (char *) vp->v_value);
X		break;
X
X	case V_CHAR:
X		sprintf(buf, "%p", *(vp->v_value));
X		break;
X	}
X}
X
void
PrVar()
X{
X	struct variable	*vp;
X	char	prbuf[256];
X
X	if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
X		return;
X	vpr_aux(vp, prbuf);
X	s_mess(": %f %s => %s", vp->Name, prbuf);
X}
X
void
SetVar()
X{
X	struct variable	*vp;
X	char	*prompt;
X
X	if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
X		return;
X	prompt = sprint(": %f %s ", vp->Name);
X
X	switch (vp->v_flags & V_TYPEMASK) {
X	case V_BASE10:
X	case V_BASE8:
X	    {
X	    	int	value;
X
X		value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
X					  ? 10 : 8);
X		*(vp->v_value) = value;
X	    	break;
X	    }
X
X	case V_BOOL:
X	    {
X	    	char	*def = *(vp->v_value) ? "off" : "on",
X	    		*on_off;
X	    	int	value;
X
X	    	on_off = ask(def, prompt);
X		if (casecmp(on_off, "on") == 0)
X			value = ON;
X	    	else if (casecmp(on_off, "off") == 0)
X	    		value = OFF;
X	    	else
X	    		complain("Boolean variables must be ON or OFF.");
X	    	*(vp->v_value) = value;
X#ifdef MAC
X		MarkVar(vp,-1,0);	/* mark the menu item */
X#endif
X	    	s_mess("%s%s", prompt, value ? "on" : "off");
X	    	break;
X	    }
X
X	case V_FILENAME:
X	    {
X		char	fbuf[FILESIZE];
X
X	    	sprintf(&prompt[strlen(prompt)], "(default %s) ", vp->v_value);
X	    	(void) ask_file(prompt, (char *) vp->v_value, fbuf);
X		strcpy((char *) vp->v_value, fbuf);
X	    	break;
X	    }
X
X	case V_STRING:
X	    {
X		char	*str;
X
X	    	/* Do_ask() so you can set string to "" if you so desire. */
X	    	str = do_ask("\r\n", (int (*)()) 0, (char *) vp->v_value, prompt);
X	    	if (str == 0)
X			str = NullStr;
X	    	strcpy((char *) vp->v_value, str);
X		/* ... and hope there is enough room. */
X	    	break;
X	    }
X	case V_CHAR:
X		f_mess(prompt);
X	    	*(vp->v_value) = addgetc();
X		break;	    	
X
X	}
X	if (vp->v_flags & V_MODELINE)
X		UpdModLine = YES;
X	if (vp->v_flags & V_CLRSCREEN) {
X#ifdef IBMPC
X		setcolor(Fgcolor, Bgcolor);
X#endif /* IBMPC */
X		ClAndRedraw();
X	}
X	if (vp->v_flags & V_TTY_RESET)
X		tty_reset();
X}
X			
X/* Command completion - possible is an array of strings, prompt is
X   the prompt to use, and flags are ... well read jove.h.
X
X   If flags are RET_STATE, and the user hits <return> what they typed
X   so far is in the Minibuf string. */
X
private char	**Possible;
private int	comp_value,
X		comp_flags;
X
int
aux_complete(c)
X{
X	int	command,
X		length,
X		i;
X
X	if (comp_flags & CASEIND) {
X		char	*lp;
X
X		for (lp = linebuf; *lp != '\0'; lp++)
X#if (defined(IBMPC) || defined(MAC))
X			lower(lp);
X#else			
X			if (isupper(*lp))
X				*lp = tolower(*lp);
X#endif
X	}
X	switch (c) {
X	case EOF:
X		comp_value = -1;
X		return 0;
X
X	case '\r':
X	case '\n':
X		command = match(Possible, linebuf);
X		if (command >= 0) {
X			comp_value = command;
X			return 0;	/* tells ask to stop */
X		}
X		if (eolp() && bolp()) {
X			comp_value = NULLSTRING;
X			return 0;
X		}
X		if (comp_flags & RET_STATE) {
X			comp_value = command;
X			return 0;
X		}
X		if (InJoverc)
X			complain("[\"%s\" unknown]", linebuf);
X		rbell();
X		break;
X
X	case '\t':
X	case ' ':
X	    {
X		int	minmatch = 1000,
X	    		maxmatch = 0,
X	    		numfound = 0,
X	    		lastmatch = -1,
X			length = strlen(linebuf);
X
X		for (i = 0; Possible[i] != 0; i++) {
X			int	this_len;
X
X			this_len = numcomp(Possible[i], linebuf);
X			maxmatch = max(maxmatch, this_len);
X			if (this_len >= length) {
X				if (numfound)
X					minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
X				else
X					minmatch = strlen(Possible[i]);
X				numfound += 1;
X				lastmatch = i;
X				if (strcmp(linebuf, Possible[i]) == 0)
X					break;
X			}
X		}
X
X		if (numfound == 0) {
X			rbell();
X			if (InJoverc)
X				complain("[\"%s\" unknown]", linebuf);
X			/* If we're not in the .joverc then
X			   let's do something helpful for the
X			   user. */
X			if (maxmatch < length) {
X				char	*cp;
X
X				cp = linebuf + maxmatch;
X				*cp = 0;
X				Eol();
X			}
X			break;
X		}
X	    	if (c != '\t' && numfound == 1) {
X	    		comp_value = lastmatch;
X			return 0;
X		}
X		null_ncpy(linebuf, Possible[lastmatch], minmatch);
X	    	Eol();
X		if (minmatch == length)	/* No difference */
X			rbell();
X		break;
X	    }
X
X	case '?':
X		if (InJoverc)
X			complain((char *) 0);
X		/* kludge: in case we're using UseBuffers, in which case
X		   linebuf gets written all over */
X		strcpy(Minibuf, linebuf);
X		length = strlen(Minibuf);
X		TOstart("Completion", TRUE);	/* for now ... */
X		for (i = 0; Possible[i]; i++)
X			if (numcomp(Possible[i], Minibuf) >= length) {
X				Typeout(Possible[i]);
X				if (TOabort != 0)
X					break;
X			}
X
X		TOstop();
X		break;
X	}
X	return !FALSE;
X}
X
int
complete(possible, prompt, flags)
register char	*possible[];
char	*prompt;
X{
X	Possible = possible;
X	comp_flags = flags;
X	(void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
X	return comp_value;
X}
X
int
match(choices, what)
register char	**choices,
X		*what;
X{
X	register int	len;
X	int	i,
X		found = 0,
X		save,
X		exactmatch = -1;
X
X	len = strlen(what);
X	if (len == 0)
X		return NULLSTRING;
X	for (i = 0; choices[i]; i++) {
X		if (strncmp(what, choices[i], len) == 0) {
X			if (strcmp(what, choices[i]) == 0)
X				exactmatch = i;
X			save = i;
X			found += 1;	/* found one */
X		}
X	}
X
X	if (found == 0)
X		save = ORIGINAL;
X	else if (found > 1) {
X		if (exactmatch != -1)
X			save = exactmatch;
X		else
X			save = AMBIGUOUS;
X	}
X
X	return save;
X}
X
void
Source()
X{
X	char	*com, *getenv(),
X		buf[FILESIZE];
X
X#ifndef MSDOS
X	sprintf(buf, "%s/.joverc", getenv("HOME"));
X#else /* MSDOS */
X	if (com = getenv("JOVERC"))
X		strcpy(buf, com);
X	else
X		strcpy(buf, Joverc);
X#endif /* MSDOS */
X	com = ask_file((char *) 0, buf, buf);
X	if (joverc(buf) == 0)
X		complain(IOerr("read", com));
X}
X
void
BufPos()
X{
X	register Line	*lp = curbuf->b_first;
X	register int	i,
X			dotline;
X	long	dotchar,
X		nchars;
X
X	for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) {
X		if (lp == curline) {
X			dotchar = nchars + curchar;
X			dotline = i + 1;
X		}
X		nchars += length(lp) + (lp->l_next != 0); /* include the NL */
X	}
X
X	s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
X	       filename(curbuf), dotline, i, dotchar, nchars,
X	       (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
X	       calc_pos(linebuf, curchar),
X	       calc_pos(linebuf, strlen(linebuf)));
X}
X
X#define IF_UNBOUND	-1
X#define IF_TRUE		1
X#define IF_FALSE	!IF_TRUE
X
X#ifndef MAC
int
do_if(cmd)
char	*cmd;
X{
X#ifdef MSDOS
X	int status;
X#else	
X	int	pid,
X		status;
X#endif /* MSDOS */
X#ifndef MSDOS
X
X	switch (pid = fork()) {
X	case -1:
X		complain("[Fork failed: if]");
X
X	case 0:
X	    {
X#endif /* MSDOS */
X		char	*args[12],
X			*cp = cmd,
X			**ap = args;
X
X	    	*ap++ = cmd;
X	    	for (;;) {
X			if ((cp = index(cp, ' ')) == 0)
X				break;
X			*cp++ = '\0';
X			*ap++ = cp;
X		}
X		*ap = 0;
X
X#ifndef MSDOS
X		close(0);	/*	we want reads to fail */
X		/* close(1);	 but not writes or ioctl's
X		close(2);    */
X#else /* MSDOS */
X	if ((status = spawnvp(0, args[0], args)) < 0)
X		complain("[Spawn failed: if]");
X#endif /* MSDOS */
X
X#ifndef MSDOS
X	    	(void) execvp(args[0], args);
X		_exit(-10);	/* signals exec error (see below) */
X	    }
X	}
X#ifdef IPROCS
X	sighold(SIGCHLD);
X#endif
X	dowait(pid, &status);
X#ifdef IPROCS
X	sigrelse(SIGCHLD);
X#endif
X	if (status == -10)
X		complain("[Exec failed]");
X	if (status < 0)
X		complain("[Exit %d]", status);
X#endif /* MSDOS */
X	return (status == 0);	/* 0 means successful */
X}
X#endif /* MAC */
X
int
joverc(file)
char	*file;
X{
X	char	buf[LBSIZE],
X		lbuf[LBSIZE];
X	int	lnum = 0,
X		eof = FALSE;
X	jmp_buf	savejmp;
X	int	IfStatus = IF_UNBOUND;
X	File	*fp;
X
X	fp = open_file(file, buf, F_READ, !COMPLAIN, QUIET);
X	if (fp == NIL)
X		return NO;	/* joverc returns an integer */
X
X	/* Catch any errors, here, and do the right thing with them,
X	   and then restore the error handle to whoever did a setjmp
X	   last. */
X
X	InJoverc += 1;
X	push_env(savejmp);
X	if (setjmp(mainjmp)) {
X		Buffer	*savebuf = curbuf;
X
X		SetBuf(do_select((Window *) 0, "RC errors"));
X		ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file, YES), lnum, lbuf, mesgbuf), NO);
X		unmodify();
X		SetBuf(savebuf);
X		Asking = 0;
X	}
X	if (!eof) do {
X		eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF);
X		lnum += 1;
X		if (lbuf[0] == '#')		/* a comment */
X			continue;
X#ifndef MAC
X		if (casencmp(lbuf, "if", 2) == 0) {
X			char	cmd[128];
X
X			if (IfStatus != IF_UNBOUND)
X				complain("[Cannot have nested if's]");
X			if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0)
X				complain("[If syntax error]");
X			putmatch(1, cmd, sizeof cmd);
X			IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE;
X			continue;
X		} else if (casencmp(lbuf, "else", 4) == 0) {
X			if (IfStatus == IF_UNBOUND)
X				complain("[Unexpected `else']");
X			IfStatus = !IfStatus;
X			continue;
X		} else if (casencmp(lbuf, "endif", 5) == 0) {
X			if (IfStatus == IF_UNBOUND)
X				complain("[Unexpected `endif']");
X			IfStatus = IF_UNBOUND;
X			continue;
X		}
X#endif
X		if (IfStatus == IF_FALSE)
X			continue;
X		(void) strcat(lbuf, "\n");
X		Inputp = lbuf;
X		while (*Inputp == ' ' || *Inputp == '\t')
X			Inputp += 1;	/* skip white space */
X		Extend();
X	} while (!eof);
X
X	f_close(fp);
X	pop_env(savejmp);
X	Inputp = 0;
X	Asking = 0;
X	InJoverc -= 1;
X	if (IfStatus != IF_UNBOUND)
X		complain("[Missing endif]");
X	return 1;
X}
END_OF_FILE
if test 19914 -ne `wc -c <'./extend.c'`; then
    echo shar: \"'./extend.c'\" unpacked with wrong size!
fi
# end of './extend.c'
fi
if test -f './re.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./re.c'\"
else
echo shar: Extracting \"'./re.c'\" \(18437 characters\)
sed "s/^X//" >'./re.c' <<'END_OF_FILE'
X/***************************************************************************
X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
X * is provided to you without charge, and with no warranty.  You may give  *
X * away copies of JOVE, including sources, provided that this notice is    *
X * included in all the files.                                              *
X ***************************************************************************/
X
X/* search package */
X
X#include "jove.h"
X#include "ctype.h"
X#ifdef MAC
X#	undef private
X#	define private
X#endif
X
X#ifdef	LINT_ARGS
private char * insert(char *, char *, int);
X
private void
X	REreset(void),
X	search(int, int, int);
private int
X	backref(int, char *),
X	do_comp(int),
X	member(char *, int, int),
X	REgetc(void),
X	REmatch(char *, char *);
X#else
private char * insert();
X
private void
X	REreset(),
X	search();
private int
X	backref(),
X	do_comp(),
X	member(),
X	REgetc(),
X	REmatch();
X#endif	/* LINT_ARGS */
X
X#ifdef MAC
X#	undef private
X#	define private static
X#endif
X
X#define NALTS	16	/* number of alternate search strings */
X
char	searchstr[128],
X	compbuf[256],		/* global default compbuf */
X	rep_search[128],	/* replace search string */
X	rep_str[128],		/* contains replacement string */
X	*cur_compb,		/* usually points at compbuf */
X	REbuf[LBSIZE],		/* points at line we're scanning */
X	*alternates[NALTS];
X
int	REdirection;
X
int	CaseIgnore = 0,
X	WrapScan = 0,
X	UseRE = 0;
X
X#define cind_cmp(a, b)	(CaseEquiv[a] == CaseEquiv[b])
X
private int	REpeekc;
private char	*REptr;
X
private int
REgetc()
X{
X	int	c;
X
X	if ((c = REpeekc) != -1)
X		REpeekc = -1;
X	else if (*REptr)
X		c = *REptr++;
X	else
X		c = 0;
X
X	return c;
X}
X
X#define STAR 	01	/* Match any number of last RE. */
X#define AT_BOL	2	/* ^ */
X#define AT_EOL	4	/* $ */
X#define AT_BOW	6	/* \< */
X#define AT_EOW	8	/* \> */
X#define OPENP	10	/* \( */
X#define CLOSEP	12	/* \) */
X#define CURLYB	14	/* \{ */
X
X#define NOSTR	14	/* Codes <= NOSTR can't be *'d. */
X
X#define ANYC	NOSTR+2		/* . */
X#define NORMC	ANYC+2		/* normal character */
X#define CINDC	NORMC+2		/* case independent character */
X#define ONE_OF	CINDC+2		/* [xxx] */
X#define NONE_OF	ONE_OF+2	/* [^xxx] */
X#define BACKREF	NONE_OF+2	/* \# */
X#define EOP	BACKREF+2	/* end of pattern */
X
X#define NPAR	10	/* [0-9] - 0th is the entire matched string, i.e. & */
private int	nparens;
private char	*comp_p,
X		*start_p,
X		**alt_p,
X		**alt_endp;
X
void
REcompile(pattern, re, into_buf, alt_bufp)
char	*pattern,
X	*into_buf,
X	**alt_bufp;
X{
X	REptr = pattern;
X	REpeekc = -1;
X	comp_p = cur_compb = start_p = into_buf;
X	alt_p = alt_bufp;
X	alt_endp = alt_p + NALTS;
X	*alt_p++ = comp_p;
X	nparens = 0;
X	(void) do_comp(re ? OKAY_RE : NORM);
X	*alt_p = 0;
X}
X
X/* compile the pattern into an internal code */
X
private int
do_comp(kind)
X{
X	char	*last_p,
X		*chr_cnt = 0;
X	int	parens[NPAR],
X		*parenp,
X		c,
X		ret_code;
X
X	parenp = parens;
X	last_p = 0;
X	ret_code = 1;
X
X	if (kind == OKAY_RE) {
X		*comp_p++ = OPENP;
X		*comp_p++ = nparens;
X		*parenp++ = nparens++;
X		start_p = comp_p;
X	}
X
X	while (c = REgetc()) {
X		if (comp_p > &cur_compb[(sizeof compbuf) - 6])
toolong:		complain("Search string too long/complex.");
X		if (c != '*')
X			last_p = comp_p;
X
X		if (kind == NORM && index(".[*", c) != 0)
X			goto defchar;
X		switch (c) {
X		case '\\':
X			switch (c = REgetc()) {
X			case 0:
X				complain("Premature end of pattern.");
X
X			case '{':
X			    {
X			    	char	*wcntp;		/* word count */
X
X			    	*comp_p++ = CURLYB;
X			    	wcntp = comp_p;
X			    	*comp_p++ = 0;
X			    	for (;;) {
X			    		int	comp_val;
X			    		char	*comp_len;
X
X			    		comp_len = comp_p++;
X			    		comp_val = do_comp(IN_CB);
X			    		*comp_len = comp_p - comp_len;
X			    		(*wcntp) += 1;
X			    		if (comp_val == 0)
X			    			break;
X			    	}
X			    	break;
X			    }
X
X			case '}':
X				if (kind != IN_CB)
X					complain("Unexpected \}.");
X				ret_code = 0;
X				goto outahere;
X
X			case '(':
X				if (nparens >= NPAR)
X					complain("Too many ('s; max is %d.", NPAR);
X				*comp_p++ = OPENP;
X				*comp_p++ = nparens;
X				*parenp++ = nparens++;
X				break;
X
X			case ')':
X				if (parenp == parens)
X					complain("Too many )'s.");
X				*comp_p++ = CLOSEP;
X				*comp_p++ = *--parenp;
X				break;
X
X			case '|':
X				if (alt_p >= alt_endp)
X					complain("Too many alternates; max %d.", NALTS);
X				*comp_p++ = CLOSEP;
X				*comp_p++ = *--parenp;
X				*comp_p++ = EOP;
X				*alt_p++ = comp_p;
X				nparens = 0;
X				*comp_p++ = OPENP;
X				*comp_p++ = nparens;
X				*parenp++ = nparens++;
X				start_p = comp_p;
X				break;
X
X			case '1':
X			case '2':
X			case '3':
X			case '4':
X			case '5':
X			case '6':
X			case '7':
X			case '8':
X			case '9':
X				*comp_p++ = BACKREF;
X				*comp_p++ = c - '0';
X				break;
X
X			case '<':
X				*comp_p++ = AT_BOW;
X				break;
X
X			case '>':
X				*comp_p++ = AT_EOW;
X				break;
X
X			default:
X				goto defchar;
X			}
X			break;
X
X		case ',':
X			if (kind != IN_CB)
X				goto defchar;
X			goto outahere;
X
X		case '.':
X			*comp_p++ = ANYC;
X			break;
X
X		case '^':
X			if (comp_p == start_p) {
X				*comp_p++ = AT_BOL;
X				break;
X			}
X			goto defchar;
X
X		case '$':
X			if ((REpeekc = REgetc()) != 0 && REpeekc != '\\')
X				goto defchar;
X			*comp_p++ = AT_EOL;
X			break;
X
X		case '[':
X		    {
X		    	int	chrcnt;
X
X		    	*comp_p++ = ONE_OF;
X			if (comp_p + 16 >= &cur_compb[(sizeof compbuf)])
X				goto toolong;
X		    	bzero(comp_p, 16);
X		    	if ((REpeekc = REgetc()) == '^') {
X		    		*last_p = NONE_OF;
X		    		/* Get it for real this time. */
X		    		(void) REgetc();
X		    	}
X		    	chrcnt = 1;
X		    	while ((c = REgetc()) != ']' && c != 0) {
X		    		if (c == '\\')
X		    			c = REgetc();
X				else if ((REpeekc = REgetc()) == '-') {
X					int	c2;
X
X					(void) REgetc();     /* reread '-' */
X					c2 = REgetc();
X					while (c < c2) {
X						comp_p[c/8] |= (1 << (c%8));
X						c += 1;
X					}
X				}
X				comp_p[c/8] |= (1 << (c%8));
X		    		chrcnt += 1;
X		    	}
X		    	if (c == 0)
X		    		complain("Missing ].");
X		    	if (chrcnt == 1)
X		    		complain("Empty [].");
X		    	comp_p += 16;
X		    	break;
X		    }
X
X		case '*':
X			if (last_p == 0 || *last_p <= NOSTR)
X				goto defchar;
X
X			/* The * operator applies only to the previous
X			   character.  If we were building a chr_cnt at
X			   the time we got the *, we have to remove the
X			   last character from the chr_cnt (by decrementing
X			   *chr_cnt) and replacing it with a new STAR entry.
X
X			   If we are decrementing the count to 0, we just
X			   delete the chr_cnt entry altogether, replacing
X			   it with the STAR entry. */
X
X			if (chr_cnt) {
X				char	lastc = chr_cnt[*chr_cnt];
X 
X 			/* The * operator applies only to the previous
X 			   character.  If we were building a chr_cnt at
X 			   the time we got the *, we have to remove the
X 			   last character from the chr_cnt (by decrementing
X 			   *chr_cnt) and replacing it with a new STAR entry.
X 
X 			   If we are decrementing the count to 0, we just
X 			   delete the chr_cnt entry altogether, replacing
X 			   it with the STAR entry. */
X 
X 				if (*chr_cnt == 1) {
X 					comp_p = chr_cnt;
X 					comp_p[-1] |= STAR;
X 					*comp_p++ = lastc;
X 				} else {
X 					comp_p = chr_cnt + *chr_cnt;
X 					(*chr_cnt) -= 1;
X 					*comp_p++ = chr_cnt[-1] | STAR;
X 					*comp_p++ = lastc;
X 				}
X			} else
X				*last_p |= STAR;
X			break;
X		default:
defchar:		if (chr_cnt)
X				(*chr_cnt) += 1;
X			else {
X				*comp_p++ = (CaseIgnore) ? CINDC : NORMC;
X				chr_cnt = comp_p++;
X				*chr_cnt = 1;   /* last_p[1] = 1; */
X			}
X			*comp_p++ = c;
X			continue;
X		}
X		chr_cnt = FALSE;
X	}
outahere:
X	/* End of pattern, let's do some error checking. */
X	if (kind == OKAY_RE) {
X		*comp_p++ = CLOSEP;
X		*comp_p++ = *--parenp;
X	}
X	if (parenp != parens)
X		complain("Unmatched ()'s.");
X	if (kind == IN_CB && c == 0)	/* End of pattern with \}. */
X		complain("Missing \}.");
X	*comp_p++ = EOP;
X
X	return ret_code;
X}
X
private char	*pstrtlst[NPAR],	/* index into REbuf */
X		*pendlst[NPAR],
X		*REbolp,
X		*locs,
X		*loc1,
X		*loc2;
X
int	REbom,
X	REeom,		/* beginning and end of match */
X	REalt_num;	/* if alternatives, which one matched? */
X
private int
backref(n, linep)
register char	*linep;
X{
X	register char	*backsp,
X			*backep;
X
X	backsp = pstrtlst[n];
X	backep = pendlst[n];
X	while (*backsp++ == *linep++)
X		if (backsp >= backep)
X			return 1;
X	return 0;
X}
X
private int
member(comp_p, c, af)
register char	*comp_p;
register int	c,
X		af;
X{
X	if (c == 0)
X		return 0;	/* try to match EOL always fails */
X	if (comp_p[c/8] & (1 << (c%8)))
X		return af;
X	return !af;
X}
X
private int
REmatch(linep, comp_p)
register char	*linep,
X		*comp_p;
X{
X	char	*first_p = linep;
X	register int	n;
X
X	for (;;) switch (*comp_p++) {
X	case NORMC:
X		n = *comp_p++;
X		while (--n >= 0)
X			if (*linep++ != *comp_p++)
X				return 0;
X		continue;
X
X	case CINDC:	/* case independent comparison */
X		n = *comp_p++;
X		while (--n >= 0)
X			if (!cind_cmp(*linep++, *comp_p++))
X				return 0;
X		continue;
X
X	case EOP:
X		loc2 = linep;
X		REeom = (loc2 - REbolp);
X		return 1;	/* Success! */
X
X	case AT_BOL:
X		if (linep == REbolp)
X			continue;
X		return 0;
X
X	case AT_EOL:
X		if (*linep == 0)
X			continue;
X		return 0;
X
X	case ANYC:
X		if (*linep++ != 0)
X			continue;
X		return 0;
X
X	case AT_BOW:
X		if (ismword(*linep) && (linep == REbolp || !ismword(linep[-1])))
X			continue;
X		return 0;
X
X	case AT_EOW:
X		if ((*linep == 0 || !ismword(*linep)) &&
X		    (linep != REbolp && ismword(linep[-1])))
X			continue;
X		return 0;
X
X	case ONE_OF:
X	case NONE_OF:
X		if (member(comp_p, *linep++, comp_p[-1] == ONE_OF)) {
X			comp_p += 16;
X			continue;
X		}
X		return 0;
X
X	case OPENP:
X		pstrtlst[*comp_p++] = linep;
X		continue;
X
X	case CLOSEP:
X		pendlst[*comp_p++] = linep;
X		continue;
X
X	case BACKREF:
X		if (pstrtlst[n = *comp_p++] == 0) {
X			s_mess("\\%d was not specified.", n + 1);
X			return 0;
X		}
X		if (backref(n, linep)) {
X			linep += pendlst[n] - pstrtlst[n];
X			continue;
X		}
X		return 0;
X
X	case CURLYB:
X	    {
X	    	int	wcnt,
X	    		any;
X
X	    	wcnt = *comp_p++;
X	    	any = 0;
X
X	    	while (--wcnt >= 0) {
X	    		if (any == 0)
X	    			any = REmatch(linep, comp_p + 1);
X	    		comp_p += *comp_p;
X	    	}
X	    	if (any == 0)
X	    		return 0;
X	    	linep = loc2;
X	    	continue;
X	    }
X
X	case ANYC | STAR:
X		first_p = linep;
X		while (*linep++)
X			;
X		goto star;
X
X	case NORMC | STAR:
X		first_p = linep;
X		while (*comp_p == *linep++)
X			;
X		comp_p += 1;
X		goto star;
X
X	case CINDC | STAR:
X		first_p = linep;
X		while (cind_cmp(*comp_p, *linep++))
X			;
X		comp_p += 1;
X		goto star;
X
X	case ONE_OF | STAR:
X	case NONE_OF | STAR:
X		first_p = linep;
X		while (member(comp_p, *linep++, comp_p[-1] == (ONE_OF | STAR)))
X			;
X		comp_p += 16;
X		goto star;
X
X	case BACKREF | STAR:
X		first_p = linep;
X		n = *comp_p++;
X		while (backref(n, linep))
X			linep += pendlst[n] - pstrtlst[n];
X		while (linep >= first_p) {
X			if (REmatch(linep, comp_p))
X				return 1;
X			linep -= pendlst[n] - pstrtlst[n];
X		}
X		continue;
X
star:		do {
X			linep -= 1;
X			if (linep < locs)
X				break;
X			if (REmatch(linep, comp_p))
X				return 1;
X		} while (linep > first_p);
X		return 0;
X
X	default:
X		complain("RE error match (%d).", comp_p[-1]);
X	}
X	/* NOTREACHED. */
X}
X
private void
REreset()
X{
X	register int	i;
X
X	for (i = 0; i < NPAR; i++)
X		pstrtlst[i] = pendlst[i] = 0;
X}
X
X/* Index LINE at OFFSET, the compiled EXPR, with alternates ALTS.  If
X   lbuf_okay is nonzero it's okay to use linebuf if LINE is the current
X   line.  This should save lots of time in things like paren matching in
X   LISP mode.  Saves all that copying from linebuf to REbuf.  substitute()
X   is the guy who calls re_lindex with lbuf_okay as 0, since the substitution
X   gets placed in linebuf ... doesn't work too well when the source and
X   destination strings are the same.  I hate all these arguments!
X
X   This code is cumbersome, repetetive for reasons of efficiency.  Fast
X   search is a must as far as I am concerned. */
X
int
re_lindex(line, offset, expr, alts, lbuf_okay)
Line	*line;
char	*expr,
X	**alts;
X{
X	int	isquick;
X	register int	firstc,
X			c;
X	register char	*resp;
X
X	REreset();
X	if (lbuf_okay) {
X		REbolp = lbptr(line);
X		if (offset == -1)
X			offset = strlen(REbolp);	/* arg! */
X	} else {
X		REbolp = ltobuf(line, REbuf);
X		if (offset == -1) {	/* Reverse search, find end of line. */
X			extern int	Jr_Len;
X
X			offset = Jr_Len;	/* Just Read Len. */
X		}
X	}
X	resp = REbolp;
X	isquick = ((expr[0] == NORMC || expr[0] == CINDC) &&
X		   (alternates[1] == 0));
X	if (isquick) {
X		firstc = expr[2];
X		if (expr[0] == CINDC)
X			firstc = CaseEquiv[firstc];
X	}
X	locs = REbolp + offset;
X
X	if (REdirection == FORWARD) {
X	    do {
X		char	**altp = alts;
X
X		if (isquick) {
X			if (expr[0] == NORMC)
X				while ((c = *locs++) != 0 && c != firstc)
X					;
X			else
X				while (((c = *locs++) != 0) &&
X					(CaseEquiv[c] != firstc))
X					;
X			if (*--locs == 0)
X				break;
X		}
X		REalt_num = 1;
X		while (*altp) {
X			if (REmatch(locs, *altp++)) {
X				loc1 = locs;
X				REbom = loc1 - REbolp;
X				return 1;
X			}
X			REalt_num += 1;
X		}
X	    } while (*locs++);
X	} else {
X	    do {
X		char	**altp = alts;
X
X		if (isquick) {
X			if (expr[0] == NORMC) {
X				while (locs >= REbolp && *locs-- != firstc)
X					;
X				if (*++locs != firstc)
X					break;
X			} else {
X				while (locs >= REbolp && CaseEquiv[*locs--] != firstc)
X					;
X				if (CaseEquiv[*++locs] != firstc)
X					break;
X			}
X		}
X		REalt_num = 1;
X		while (*altp) {
X			if (REmatch(locs, *altp++)) {
X				loc1 = locs;
X				REbom = loc1 - REbolp;
X				return 1;
X			}
X			REalt_num += 1;
X		}
X	    } while (--locs >= resp);
X	}
X
X	return 0;
X}
X
int	okay_wrap = 0;	/* Do a wrap search ... not when we're
X			   parsing errors ... */
X
Bufpos *
dosearch(pattern, dir, re)
char	*pattern;
X{
X	Bufpos	*pos;
X
X	if (bobp() && eobp())	/* Can't match!  There's no buffer. */
X		return 0;
X
X	REcompile(pattern, re, compbuf, alternates);
X
X	pos = docompiled(dir, compbuf, alternates);
X	return pos;
X}
X
Bufpos *
docompiled(dir, expr, alts)
char	*expr,
X	**alts;
X{
X	static Bufpos	ret;
X	register Line	*lp;
X	register int	offset;
X	int	we_wrapped = NO;
X
X	lsave();
X	/* Search now lsave()'s so it doesn't make any assumptions on
X	   whether the the contents of curline/curchar are in linebuf.
X	   Nowhere does search write all over linebuf.  However, we have to
X	   be careful about what calls we make here, because many of them
X	   assume (and rightly so) that curline is in linebuf. */
X
X	REdirection = dir;
X	lp = curline;
X	offset = curchar;
X	if (dir == BACKWARD) {
X		if (bobp()) {
X			if (okay_wrap && WrapScan)
X				goto doit;
X			return 0;
X		}
X		/* here we simulate BackChar() */
X		if (bolp()) {
X			lp = lp->l_prev;
X			offset = strlen(lbptr(lp));
X		} else
X			offset -= 1;
X	} else if ((dir == FORWARD) &&
X		   (lbptr(lp)[offset] == '\0') &&
X		   !lastp(lp)) {
X		lp = lp->l_next;
X		offset = 0;
X	}
X
X	do {
X		if (re_lindex(lp, offset, expr, alts, YES))
X			break;
doit:		lp = (dir == FORWARD) ? lp->l_next : lp->l_prev;
X		if (lp == 0) {
X			if (okay_wrap && WrapScan) {
X				lp = (dir == FORWARD) ?
X				     curbuf->b_first : curbuf->b_last;
X				we_wrapped = YES;
X			} else
X				 break;
X		}
X		if (dir == FORWARD)
X			offset = 0;
X		else
X			offset = -1;	/* signals re_lindex ... */
X	} while (lp != curline);
X
X	if (lp == curline && we_wrapped)
X		lp = 0;
X	if (lp == 0)
X		return 0;
X	ret.p_line = lp;
X	ret.p_char = (dir == FORWARD) ? REeom : REbom;
X	return &ret;
X}
X
private char *
insert(off, endp, which)
char	*off,
X	*endp;
X{
X	register char	*pp;
X	register int	n;
X
X	n = pendlst[which] - pstrtlst[which];
X	pp = pstrtlst[which];
X	while (--n >= 0) {
X		*off++ = *pp++;
X		if (off >= endp)
X			len_error(ERROR);
X	}
X	return off;
X}
X
X/* Perform the substitution.  If DELP is nonzero the matched string is
X   deleted, i.e., the substitution string is not inserted. */
X
void
re_dosub(tobuf, delp)
char	*tobuf;
X{
X	register char	*tp,
X			*rp,
X			*repp;
X	int	c;
X	char	*endp;
X
X	tp = tobuf;
X	endp = tp + LBSIZE;
X	rp = REbuf;
X	repp = rep_str;
X
X	while (rp < loc1)
X		*tp++ = *rp++;
X
X	if (!delp) while (c = *repp++) {
X		if (c == '\\') {
X			c = *repp++;
X			if (c == '\0') {
X				*tp++ = '\\';
X	  			goto endchk;
X			} else if (c >= '1' && c <= nparens + '1') {
X				tp = insert(tp, endp, c - '0');
X				continue;
X			}
X		} else if (c == '&') {
X			tp = insert(tp, endp, 0);
X			continue;
X		}
X		*tp++ = c;
endchk:		if (tp >= endp)
X			len_error(ERROR);
X	}
X	rp = loc2;
X	loc2 = REbuf + max(1, tp - tobuf);
X	REeom = loc2 - REbuf;
X	/* At least one character past the match, to prevent an infinite
X	   number of replacements in the same position, e.g.,
X	   replace "^" with "". */
X	while (*tp++ = *rp++)
X		if (tp >= endp)
X			len_error(ERROR);
X}
X
void
putmatch(which, buf, size)
char	*buf;
X{
X	*(insert(buf, buf + size, which)) = 0;
X}
X
void
setsearch(str)
char	*str;
X{
X	strcpy(searchstr, str);
X}
X
char *
getsearch()
X{
X	return searchstr;
X}
X
void
RErecur()
X{
X	char	sbuf[sizeof searchstr],
X		cbuf[sizeof compbuf],
X		repbuf[sizeof rep_str],
X		*altbuf[NALTS];
X	int	npars;
X	Mark	*m = MakeMark(curline, REbom, M_FLOATER);
X
X	message("Type C-X C-C to continue with query replace.");
X
X	npars = nparens;
X	byte_copy(compbuf, cbuf, sizeof compbuf);
X	byte_copy(searchstr, sbuf, sizeof searchstr);
X	byte_copy(rep_str, repbuf, sizeof rep_str);
X	byte_copy((char *) alternates, (char *) altbuf, sizeof alternates);
X	Recur();
X	nparens = npars;
X	byte_copy(cbuf, compbuf, sizeof compbuf);
X	byte_copy(sbuf, searchstr, sizeof searchstr);
X	byte_copy(repbuf, rep_str, sizeof rep_str);
X	byte_copy((char *) altbuf, (char *) alternates, sizeof alternates);
X	if (!is_an_arg())
X		ToMark(m);
X	DelMark(m);
X}
X
void
ForSearch()
X{
X	search(FORWARD, UseRE, YES);
X}
X
void
RevSearch()
X{
X	search(BACKWARD, UseRE, YES);
X}
X
void
FSrchND()
X{
X	search(FORWARD, UseRE, NO);
X}
X
void
RSrchND()
X{
X	search(BACKWARD, UseRE, NO);
X}
X
private void
search(dir, re, setdefault)
X{
X	Bufpos	*newdot;
X	char	*s;
X
X	s = ask(searchstr, ProcFmt);
X	if (setdefault)
X		setsearch(s);
X	okay_wrap = YES;
X	newdot = dosearch(s, dir, re);
X	okay_wrap = NO;
X	if (newdot == 0) {
X		if (WrapScan)
X			complain("No \"%s\" in buffer.", s);
X		else
X			complain("No \"%s\" found to %s.", s,
X				 (dir == FORWARD) ? "bottom" : "top");
X	}
X	PushPntp(newdot->p_line);
X	SetDot(newdot);
X}
X
X/* Do we match PATTERN at OFFSET in BUF? */
X
int
LookingAt(pattern, buf, offset)
char	*pattern,
X	*buf;
X{
X	register char	**alt = alternates;
X
X	REcompile(pattern, 1, compbuf, alternates);
X	REreset();
X	locs = buf + offset;
X	REbolp = buf;
X
X	while (*alt)
X		if (REmatch(locs, *alt++))
X			return 1;
X	return 0;
X}
X
int
look_at(expr)
char	*expr;
X{
X	REcompile(expr, 0, compbuf, alternates);
X	REreset();
X	locs = linebuf + curchar;
X	REbolp = linebuf;
X	if (REmatch(locs, alternates[0]))
X		return 1;
X	return 0;
X}
X
END_OF_FILE
if test 18437 -ne `wc -c <'./re.c'`; then
    echo shar: \"'./re.c'\" unpacked with wrong size!
fi
# end of './re.c'
fi
echo shar: End of archive 10 \(of 21\).
cp /dev/null ark10isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 21 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.