780 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			780 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| #define Extern extern
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <sys/dir.h>
 | |
| #include <limits.h>
 | |
| #include <signal.h>
 | |
| #include <errno.h>
 | |
| #include <setjmp.h>
 | |
| #include "sh.h"
 | |
| 
 | |
| /* -------- eval.c -------- */
 | |
| /* #include "sh.h" */
 | |
| /* #include "word.h" */
 | |
| 
 | |
| /*
 | |
|  * ${}
 | |
|  * `command`
 | |
|  * blank interpretation
 | |
|  * quoting
 | |
|  * glob
 | |
|  */
 | |
| 
 | |
| _PROTOTYPE(static int expand, (char *cp, struct wdblock **wbp, int f ));
 | |
| _PROTOTYPE(static char *blank, (int f ));
 | |
| _PROTOTYPE(static int dollar, (int quoted ));
 | |
| _PROTOTYPE(static int grave, (int quoted ));
 | |
| _PROTOTYPE(void globname, (char *we, char *pp ));
 | |
| _PROTOTYPE(static char *generate, (char *start1, char *end1, char *middle, char *end ));
 | |
| _PROTOTYPE(static int anyspcl, (struct wdblock *wb ));
 | |
| _PROTOTYPE(static int xstrcmp, (char *p1, char *p2 ));
 | |
| _PROTOTYPE(void glob0, (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *)));
 | |
| _PROTOTYPE(void glob1, (char *base, char *lim ));
 | |
| _PROTOTYPE(void glob2, (char *i, char *j ));
 | |
| _PROTOTYPE(void glob3, (char *i, char *j, char *k ));
 | |
| _PROTOTYPE(char *memcopy, (char *ato, char *from, int nb ));
 | |
| 
 | |
| char **
 | |
| eval(ap, f)
 | |
| register char **ap;
 | |
| int f;
 | |
| {
 | |
| 	struct wdblock *wb;
 | |
| 	char **wp;
 | |
| 	char **wf;
 | |
| 	jmp_buf ev;
 | |
| 
 | |
| 	wp = NULL;
 | |
| 	wb = NULL;
 | |
| 	wf = NULL;
 | |
| 	if (newenv(setjmp(errpt = ev)) == 0) {
 | |
| 		while (*ap && isassign(*ap))
 | |
| 			expand(*ap++, &wb, f & ~DOGLOB);
 | |
| 		if (flag['k']) {
 | |
| 			for (wf = ap; *wf; wf++) {
 | |
| 				if (isassign(*wf))
 | |
| 					expand(*wf, &wb, f & ~DOGLOB);
 | |
| 			}
 | |
| 		}
 | |
| 		for (wb = addword((char *)0, wb); *ap; ap++) {
 | |
| 			if (!flag['k'] || !isassign(*ap))
 | |
| 				expand(*ap, &wb, f & ~DOKEY);
 | |
| 		}
 | |
| 		wb = addword((char *)0, wb);
 | |
| 		wp = getwords(wb);
 | |
| 		quitenv();
 | |
| 	} else
 | |
| 		gflg = 1;
 | |
| 	return(gflg? (char **)NULL: wp);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Make the exported environment from the exported
 | |
|  * names in the dictionary. Keyword assignments
 | |
|  * will already have been done.
 | |
|  */
 | |
| char **
 | |
| makenv()
 | |
| 
 | |
| {
 | |
| 	register struct wdblock *wb;
 | |
| 	register struct var *vp;
 | |
| 
 | |
| 	wb = NULL;
 | |
| 	for (vp = vlist; vp; vp = vp->next)
 | |
| 		if (vp->status & EXPORT)
 | |
| 			wb = addword(vp->name, wb);
 | |
| 	wb = addword((char *)0, wb);
 | |
| 	return(getwords(wb));
 | |
| }
 | |
| 
 | |
| char *
 | |
| evalstr(cp, f)
 | |
| register char *cp;
 | |
| int f;
 | |
| {
 | |
| 	struct wdblock *wb;
 | |
| 
 | |
| 	wb = NULL;
 | |
| 	if (expand(cp, &wb, f)) {
 | |
| 		if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
 | |
| 			cp = "";
 | |
| 		DELETE(wb);
 | |
| 	} else
 | |
| 		cp = NULL;
 | |
| 	return(cp);
 | |
| }
 | |
| 
 | |
| static int
 | |
| expand(cp, wbp, f)
 | |
| register char *cp;
 | |
| register struct wdblock **wbp;
 | |
| int f;
 | |
| {
 | |
| 	jmp_buf ev;
 | |
| 
 | |
| 	gflg = 0;
 | |
| 	if (cp == NULL)
 | |
| 		return(0);
 | |
| 	if (!anys("$`'\"", cp) &&
 | |
| 	    !anys(ifs->value, cp) &&
 | |
| 	    ((f&DOGLOB)==0 || !anys("[*?", cp))) {
 | |
| 		cp = strsave(cp, areanum);
 | |
| 		if (f & DOTRIM)
 | |
| 			unquote(cp);
 | |
| 		*wbp = addword(cp, *wbp);
 | |
| 		return(1);
 | |
| 	}
 | |
| 	if (newenv(setjmp(errpt = ev)) == 0) {
 | |
| 		PUSHIO(aword, cp, strchar);
 | |
| 		e.iobase = e.iop;
 | |
| 		while ((cp = blank(f)) && gflg == 0) {
 | |
| 			e.linep = cp;
 | |
| 			cp = strsave(cp, areanum);
 | |
| 			if ((f&DOGLOB) == 0) {
 | |
| 				if (f & DOTRIM)
 | |
| 					unquote(cp);
 | |
| 				*wbp = addword(cp, *wbp);
 | |
| 			} else
 | |
| 				*wbp = glob(cp, *wbp);
 | |
| 		}
 | |
| 		quitenv();
 | |
| 	} else
 | |
| 		gflg = 1;
 | |
| 	return(gflg == 0);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Blank interpretation and quoting
 | |
|  */
 | |
| static char *
 | |
| blank(f)
 | |
| int f;
 | |
| {
 | |
| 	register c, c1;
 | |
| 	register char *sp;
 | |
| 	int scanequals, foundequals;
 | |
| 
 | |
| 	sp = e.linep;
 | |
| 	scanequals = f & DOKEY;
 | |
| 	foundequals = 0;
 | |
| 
 | |
| loop:
 | |
| 	switch (c = subgetc('"', foundequals)) {
 | |
| 	case 0:
 | |
| 		if (sp == e.linep)
 | |
| 			return(0);
 | |
| 		*e.linep++ = 0;
 | |
| 		return(sp);
 | |
| 
 | |
| 	default:
 | |
| 		if (f & DOBLANK && any(c, ifs->value))
 | |
| 			goto loop;
 | |
| 		break;
 | |
| 
 | |
| 	case '"':
 | |
| 	case '\'':
 | |
| 		scanequals = 0;
 | |
| 		if (INSUB())
 | |
| 			break;
 | |
| 		for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
 | |
| 			if (c == 0)
 | |
| 				break;
 | |
| 			if (c == '\'' || !any(c, "$`\""))
 | |
| 				c |= QUOTE;
 | |
| 			*e.linep++ = c;
 | |
| 		}
 | |
| 		c = 0;
 | |
| 	}
 | |
| 	unget(c);
 | |
| 	if (!letter(c))
 | |
| 		scanequals = 0;
 | |
| 	for (;;) {
 | |
| 		c = subgetc('"', foundequals);
 | |
| 		if (c == 0 ||
 | |
| 		    (f & DOBLANK && any(c, ifs->value)) ||
 | |
| 		    (!INSUB() && any(c, "\"'"))) {
 | |
| 		        scanequals = 0;
 | |
| 			unget(c);
 | |
| 			if (any(c, "\"'"))
 | |
| 				goto loop;
 | |
| 			break;
 | |
| 		}
 | |
| 		if (scanequals)
 | |
| 			if (c == '=') {
 | |
| 				foundequals = 1;
 | |
| 				scanequals  = 0;
 | |
| 			}
 | |
| 			else if (!letnum(c))
 | |
| 				scanequals = 0;
 | |
| 		*e.linep++ = c;
 | |
| 	}
 | |
| 	*e.linep++ = 0;
 | |
| 	return(sp);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Get characters, substituting for ` and $
 | |
|  */
 | |
| int
 | |
| subgetc(ec, quoted)
 | |
| register char ec;
 | |
| int quoted;
 | |
| {
 | |
| 	register char c;
 | |
| 
 | |
| again:
 | |
| 	c = getc(ec);
 | |
| 	if (!INSUB() && ec != '\'') {
 | |
| 		if (c == '`') {
 | |
| 			if (grave(quoted) == 0)
 | |
| 				return(0);
 | |
| 			e.iop->task = XGRAVE;
 | |
| 			goto again;
 | |
| 		}
 | |
| 		if (c == '$' && (c = dollar(quoted)) == 0) {
 | |
| 			e.iop->task = XDOLL;
 | |
| 			goto again;
 | |
| 		}
 | |
| 	}
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Prepare to generate the string returned by ${} substitution.
 | |
|  */
 | |
| static int
 | |
| dollar(quoted)
 | |
| int quoted;
 | |
| {
 | |
| 	int otask;
 | |
| 	struct io *oiop;
 | |
| 	char *dolp;
 | |
| 	register char *s, c, *cp;
 | |
| 	struct var *vp;
 | |
| 
 | |
| 	c = readc();
 | |
| 	s = e.linep;
 | |
| 	if (c != '{') {
 | |
| 		*e.linep++ = c;
 | |
| 		if (letter(c)) {
 | |
| 			while ((c = readc())!=0 && letnum(c))
 | |
| 				if (e.linep < elinep)
 | |
| 					*e.linep++ = c;
 | |
| 			unget(c);
 | |
| 		}
 | |
| 		c = 0;
 | |
| 	} else {
 | |
| 		oiop = e.iop;
 | |
| 		otask = e.iop->task;
 | |
| 		e.iop->task = XOTHER;
 | |
| 		while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
 | |
| 			if (e.linep < elinep)
 | |
| 				*e.linep++ = c;
 | |
| 		if (oiop == e.iop)
 | |
| 			e.iop->task = otask;
 | |
| 		if (c != '}') {
 | |
| 			err("unclosed ${");
 | |
| 			gflg++;
 | |
| 			return(c);
 | |
| 		}
 | |
| 	}
 | |
| 	if (e.linep >= elinep) {
 | |
| 		err("string in ${} too long");
 | |
| 		gflg++;
 | |
| 		e.linep -= 10;
 | |
| 	}
 | |
| 	*e.linep = 0;
 | |
| 	if (*s)
 | |
| 		for (cp = s+1; *cp; cp++)
 | |
| 			if (any(*cp, "=-+?")) {
 | |
| 				c = *cp;
 | |
| 				*cp++ = 0;
 | |
| 				break;
 | |
| 			}
 | |
| 	if (s[1] == 0 && (*s == '*' || *s == '@')) {
 | |
| 		if (dolc > 1) {
 | |
| 			/* currently this does not distinguish $* and $@ */
 | |
| 			/* should check dollar */
 | |
| 			e.linep = s;
 | |
| 			PUSHIO(awordlist, dolv+1, dolchar);
 | |
| 			return(0);
 | |
| 		} else {	/* trap the nasty ${=} */
 | |
| 			s[0] = '1';
 | |
| 			s[1] = 0;
 | |
| 		}
 | |
| 	}
 | |
| 	e.linep = s;
 | |
| 	vp = lookup(s);
 | |
| 	if ((dolp = vp->value) == null) {
 | |
| 		switch (c) {
 | |
| 		case '=':
 | |
| 			if (digit(*s)) {
 | |
| 				err("cannot use ${...=...} with $n");
 | |
| 				gflg++;
 | |
| 				break;
 | |
| 			}
 | |
| 			cp = evalstr(strsave(cp, areanum),DOSUB);
 | |
| 			setval(vp, cp);
 | |
| 			dolp = vp->value;
 | |
| 			break;
 | |
| 
 | |
| 		case '-':
 | |
| 			dolp = evalstr(strsave(cp, areanum),DOSUB);
 | |
| 			break;
 | |
| 
 | |
| 		case '?':
 | |
| 			if (*cp == 0) {
 | |
| 				prs("missing value for ");
 | |
| 				err(s);
 | |
| 			} else
 | |
| 			        err(evalstr(strsave(cp, areanum),DOSUB));
 | |
| 			gflg++;
 | |
| 			break;
 | |
| 		}
 | |
| 	} else if (c == '+') {
 | |
| 		dolp = evalstr(strsave(cp, areanum),DOSUB);
 | |
| 	}
 | |
| 	if (flag['u'] && dolp == null) {
 | |
| 		prs("unset variable: ");
 | |
| 		err(s);
 | |
| 		gflg++;
 | |
| 	}
 | |
| 	PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Run the command in `...` and read its output.
 | |
|  */
 | |
| static int
 | |
| grave(quoted)
 | |
| int quoted;
 | |
| {
 | |
|         int otask;
 | |
|         struct io *oiop;
 | |
| 	register char *cp,*s;
 | |
| 	register int i,c;
 | |
| 	int pf[2];
 | |
| 
 | |
| 	c = readc();
 | |
|         s = e.linep;
 | |
|         *e.linep++ = c;
 | |
| 	oiop = e.iop;
 | |
| 	otask = e.iop->task;
 | |
| 	e.iop->task = XOTHER;
 | |
| 	while ((c = subgetc('\'', 0))!=0 && c!='`')
 | |
| 		if (e.linep < elinep)
 | |
| 			*e.linep++ = c;
 | |
| 	if (oiop == e.iop)
 | |
| 		e.iop->task = otask;
 | |
| 	if (c != '`') {
 | |
| 		err("no closing `");
 | |
| 		return(0);
 | |
| 	}
 | |
| 	if (openpipe(pf) < 0)
 | |
| 		return(0);
 | |
| 	if ((i = fork()) == -1) {
 | |
| 		closepipe(pf);
 | |
| 		err("try again");
 | |
| 		return(0);
 | |
| 	}
 | |
| 	if (i != 0) {
 | |
| 		e.linep = s;
 | |
| 		close(pf[1]);
 | |
| 		PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
 | |
| 		return(1);
 | |
| 	}
 | |
| 	*e.linep = 0;
 | |
| 	/* allow trapped signals */
 | |
| 	for (i=0; i<=_NSIG; i++)
 | |
| 		if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
 | |
| 			signal(i, SIG_DFL);
 | |
| 	dup2(pf[1], 1);
 | |
| 	closepipe(pf);
 | |
| 	flag['e'] = 0;
 | |
| 	flag['v'] = 0;
 | |
| 	flag['n'] = 0;
 | |
| 	cp = strsave(e.linep = s, 0);
 | |
| 	areanum = 1;
 | |
| 	inithere();
 | |
| 	freearea(areanum);	/* free old space */
 | |
| 	e.oenv = NULL;
 | |
| 	e.iop = (e.iobase = iostack) - 1;
 | |
| 	unquote(cp);
 | |
| 	talking = 0;
 | |
| 	PUSHIO(aword, cp, nlchar);
 | |
| 	onecommand();
 | |
| 	exit(1);
 | |
| }
 | |
| 
 | |
| char *
 | |
| unquote(as)
 | |
| register char *as;
 | |
| {
 | |
| 	register char *s;
 | |
| 
 | |
| 	if ((s = as) != NULL)
 | |
| 		while (*s)
 | |
| 			*s++ &= ~QUOTE;
 | |
| 	return(as);
 | |
| }
 | |
| 
 | |
| /* -------- glob.c -------- */
 | |
| /* #include "sh.h" */
 | |
| 
 | |
| /*
 | |
|  * glob
 | |
|  */
 | |
| 
 | |
| #define	scopy(x) strsave((x), areanum)
 | |
| #define	BLKSIZ	512
 | |
| #define	NDENT	((BLKSIZ+sizeof(struct direct)-1)/sizeof(struct direct))
 | |
| 
 | |
| static	struct wdblock	*cl, *nl;
 | |
| static	char	spcl[] = "[?*";
 | |
| 
 | |
| struct wdblock *
 | |
| glob(cp, wb)
 | |
| char *cp;
 | |
| struct wdblock *wb;
 | |
| {
 | |
| 	register i;
 | |
| 	register char *pp;
 | |
| 
 | |
| 	if (cp == 0)
 | |
| 		return(wb);
 | |
| 	i = 0;
 | |
| 	for (pp = cp; *pp; pp++)
 | |
| 		if (any(*pp, spcl))
 | |
| 			i++;
 | |
| 		else if (!any(*pp & ~QUOTE, spcl))
 | |
| 			*pp &= ~QUOTE;
 | |
| 	if (i != 0) {
 | |
| 		for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
 | |
| 			nl = newword(cl->w_nword*2);
 | |
| 			for(i=0; i<cl->w_nword; i++) { /* for each argument */
 | |
| 				for (pp = cl->w_words[i]; *pp; pp++)
 | |
| 					if (any(*pp, spcl)) {
 | |
| 						globname(cl->w_words[i], pp);
 | |
| 						break;
 | |
| 					}
 | |
| 				if (*pp == '\0')
 | |
| 					nl = addword(scopy(cl->w_words[i]), nl);
 | |
| 			}
 | |
| 			for(i=0; i<cl->w_nword; i++)
 | |
| 				DELETE(cl->w_words[i]);
 | |
| 			DELETE(cl);
 | |
| 		}
 | |
| 		for(i=0; i<cl->w_nword; i++)
 | |
| 			unquote(cl->w_words[i]);
 | |
| 		glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
 | |
| 		if (cl->w_nword) {
 | |
| 			for (i=0; i<cl->w_nword; i++)
 | |
| 				wb = addword(cl->w_words[i], wb);
 | |
| 			DELETE(cl);
 | |
| 			return(wb);
 | |
| 		}
 | |
| 	}
 | |
| 	wb = addword(unquote(cp), wb);
 | |
| 	return(wb);
 | |
| }
 | |
| 
 | |
| void
 | |
| globname(we, pp)
 | |
| char *we;
 | |
| register char *pp;
 | |
| {
 | |
| 	register char *np, *cp;
 | |
| 	char *name, *gp, *dp;
 | |
| 	int dn, j, n, k;
 | |
| 	struct direct ent[NDENT];
 | |
| 	char dname[NAME_MAX+1];
 | |
| 	struct stat dbuf;
 | |
| 
 | |
| 	for (np = we; np != pp; pp--)
 | |
| 		if (pp[-1] == '/')
 | |
| 			break;
 | |
| 	for (dp = cp = space((int)(pp-np)+3); np < pp;)
 | |
| 		*cp++ = *np++;
 | |
| 	*cp++ = '.';
 | |
| 	*cp = '\0';
 | |
| 	for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
 | |
| 		*cp++ = *np++;
 | |
| 	*cp = '\0';
 | |
| 	dn = open(dp, 0);
 | |
| 	if (dn < 0) {
 | |
| 		DELETE(dp);
 | |
| 		DELETE(gp);
 | |
| 		return;
 | |
| 	}
 | |
| 	dname[NAME_MAX] = '\0';
 | |
| 	while ((n = read(dn, (char *)ent, sizeof(ent))) >= sizeof(*ent)) {
 | |
| 		n /= sizeof(*ent);
 | |
| 		for (j=0; j<n; j++) {
 | |
| 			if (ent[j].d_ino == 0)
 | |
| 				continue;
 | |
| 			strncpy(dname, ent[j].d_name, NAME_MAX);
 | |
| 			if (dname[0] == '.')
 | |
| 				if (*gp != '.')
 | |
| 					continue;
 | |
| 			for(k=0; k<NAME_MAX; k++)
 | |
| 				if (any(dname[k], spcl))
 | |
| 					dname[k] |= QUOTE;
 | |
| 			if (gmatch(dname, gp)) {
 | |
| 				name = generate(we, pp, dname, np);
 | |
| 				if (*np && !anys(np, spcl)) {
 | |
| 					if (stat(name,&dbuf)) {
 | |
| 						DELETE(name);
 | |
| 						continue;
 | |
| 					}
 | |
| 				}
 | |
| 				nl = addword(name, nl);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	close(dn);
 | |
| 	DELETE(dp);
 | |
| 	DELETE(gp);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * generate a pathname as below.
 | |
|  * start..end1 / middle end
 | |
|  * the slashes come for free
 | |
|  */
 | |
| static char *
 | |
| generate(start1, end1, middle, end)
 | |
| char *start1;
 | |
| register char *end1;
 | |
| char *middle, *end;
 | |
| {
 | |
| 	char *p;
 | |
| 	register char *op, *xp;
 | |
| 
 | |
| 	p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
 | |
| 	for (xp = start1; xp != end1;)
 | |
| 		*op++ = *xp++;
 | |
| 	for (xp = middle; (*op++ = *xp++) != '\0';)
 | |
| 		;
 | |
| 	op--;
 | |
| 	for (xp = end; (*op++ = *xp++) != '\0';)
 | |
| 		;
 | |
| 	return(p);
 | |
| }
 | |
| 
 | |
| static int
 | |
| anyspcl(wb)
 | |
| register struct wdblock *wb;
 | |
| {
 | |
| 	register i;
 | |
| 	register char **wd;
 | |
| 
 | |
| 	wd = wb->w_words;
 | |
| 	for (i=0; i<wb->w_nword; i++)
 | |
| 		if (anys(spcl, *wd++))
 | |
| 			return(1);
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| static int
 | |
| xstrcmp(p1, p2)
 | |
| char *p1, *p2;
 | |
| {
 | |
| 	return(strcmp(*(char **)p1, *(char **)p2));
 | |
| }
 | |
| 
 | |
| /* -------- word.c -------- */
 | |
| /* #include "sh.h" */
 | |
| /* #include "word.h" */
 | |
| 
 | |
| #define	NSTART	16	/* default number of words to allow for initially */
 | |
| 
 | |
| struct wdblock *
 | |
| newword(nw)
 | |
| register int nw;
 | |
| {
 | |
| 	register struct wdblock *wb;
 | |
| 
 | |
| 	wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
 | |
| 	wb->w_bsize = nw;
 | |
| 	wb->w_nword = 0;
 | |
| 	return(wb);
 | |
| }
 | |
| 
 | |
| struct wdblock *
 | |
| addword(wd, wb)
 | |
| char *wd;
 | |
| register struct wdblock *wb;
 | |
| {
 | |
| 	register struct wdblock *wb2;
 | |
| 	register nw;
 | |
| 
 | |
| 	if (wb == NULL)
 | |
| 		wb = newword(NSTART);
 | |
| 	if ((nw = wb->w_nword) >= wb->w_bsize) {
 | |
| 		wb2 = newword(nw * 2);
 | |
| 		memcopy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
 | |
| 		wb2->w_nword = nw;
 | |
| 		DELETE(wb);
 | |
| 		wb = wb2;
 | |
| 	}
 | |
| 	wb->w_words[wb->w_nword++] = wd;
 | |
| 	return(wb);
 | |
| }
 | |
| 
 | |
| char **
 | |
| getwords(wb)
 | |
| register struct wdblock *wb;
 | |
| {
 | |
| 	register char **wd;
 | |
| 	register nb;
 | |
| 
 | |
| 	if (wb == NULL)
 | |
| 		return((char **)NULL);
 | |
| 	if (wb->w_nword == 0) {
 | |
| 		DELETE(wb);
 | |
| 		return((char **)NULL);
 | |
| 	}
 | |
| 	wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
 | |
| 	memcopy((char *)wd, (char *)wb->w_words, nb);
 | |
| 	DELETE(wb);	/* perhaps should done by caller */
 | |
| 	return(wd);
 | |
| }
 | |
| 
 | |
| _PROTOTYPE(int (*func), (char *, char *));
 | |
| int	globv;
 | |
| 
 | |
| void
 | |
| glob0(a0, a1, a2, a3)
 | |
| char *a0;
 | |
| unsigned a1;
 | |
| int a2;
 | |
| _PROTOTYPE(int (*a3), (char *, char *));
 | |
| {
 | |
| 	func = a3;
 | |
| 	globv = a2;
 | |
| 	glob1(a0, a0 + a1 * a2);
 | |
| }
 | |
| 
 | |
| void
 | |
| glob1(base, lim)
 | |
| char *base, *lim;
 | |
| {
 | |
| 	register char *i, *j;
 | |
| 	int v2;
 | |
| 	char *lptr, *hptr;
 | |
| 	int c;
 | |
| 	unsigned n;
 | |
| 
 | |
| 
 | |
| 	v2 = globv;
 | |
| 
 | |
| top:
 | |
| 	if ((n=(int)(lim-base)) <= v2)
 | |
| 		return;
 | |
| 	n = v2 * (n / (2*v2));
 | |
| 	hptr = lptr = base+n;
 | |
| 	i = base;
 | |
| 	j = lim-v2;
 | |
| 	for(;;) {
 | |
| 		if (i < lptr) {
 | |
| 			if ((c = (*func)(i, lptr)) == 0) {
 | |
| 				glob2(i, lptr -= v2);
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (c < 0) {
 | |
| 				i += v2;
 | |
| 				continue;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| begin:
 | |
| 		if (j > hptr) {
 | |
| 			if ((c = (*func)(hptr, j)) == 0) {
 | |
| 				glob2(hptr += v2, j);
 | |
| 				goto begin;
 | |
| 			}
 | |
| 			if (c > 0) {
 | |
| 				if (i == lptr) {
 | |
| 					glob3(i, hptr += v2, j);
 | |
| 					i = lptr += v2;
 | |
| 					goto begin;
 | |
| 				}
 | |
| 				glob2(i, j);
 | |
| 				j -= v2;
 | |
| 				i += v2;
 | |
| 				continue;
 | |
| 			}
 | |
| 			j -= v2;
 | |
| 			goto begin;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		if (i == lptr) {
 | |
| 			if (lptr-base >= lim-hptr) {
 | |
| 				glob1(hptr+v2, lim);
 | |
| 				lim = lptr;
 | |
| 			} else {
 | |
| 				glob1(base, lptr);
 | |
| 				base = hptr+v2;
 | |
| 			}
 | |
| 			goto top;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		glob3(j, lptr -= v2, i);
 | |
| 		j = hptr -= v2;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void
 | |
| glob2(i, j)
 | |
| char *i, *j;
 | |
| {
 | |
| 	register char *index1, *index2, c;
 | |
| 	int m;
 | |
| 
 | |
| 	m = globv;
 | |
| 	index1 = i;
 | |
| 	index2 = j;
 | |
| 	do {
 | |
| 		c = *index1;
 | |
| 		*index1++ = *index2;
 | |
| 		*index2++ = c;
 | |
| 	} while(--m);
 | |
| }
 | |
| 
 | |
| void
 | |
| glob3(i, j, k)
 | |
| char *i, *j, *k;
 | |
| {
 | |
| 	register char *index1, *index2, *index3;
 | |
| 	int c;
 | |
| 	int m;
 | |
| 
 | |
| 	m = globv;
 | |
| 	index1 = i;
 | |
| 	index2 = j;
 | |
| 	index3 = k;
 | |
| 	do {
 | |
| 		c = *index1;
 | |
| 		*index1++ = *index3;
 | |
| 		*index3++ = *index2;
 | |
| 		*index2++ = c;
 | |
| 	} while(--m);
 | |
| }
 | |
| 
 | |
| char *
 | |
| memcopy(ato, from, nb)
 | |
| register char *ato, *from;
 | |
| register int nb;
 | |
| {
 | |
| 	register char *to;
 | |
| 
 | |
| 	to = ato;
 | |
| 	while (--nb >= 0)
 | |
| 		*to++ = *from++;
 | |
| 	return(ato);
 | |
| }
 | 
