⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expand.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)expand.c	5.1 (Berkeley) 3/7/91";#endif /* not lint *//* * Routines to expand arguments to commands.  We have to deal with * backquotes, shell variables, and file metacharacters. */#include "shell.h"#include "main.h"#include "nodes.h"#include "eval.h"#include "expand.h"#include "syntax.h"#include "parser.h"#include "jobs.h"#include "options.h"#include "var.h"#include "input.h"#include "output.h"#include "memalloc.h"#include "error.h"#include "mystring.h"#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include <dirent.h>#if USEGETPW#include <pwd.h>#endif/* * Structure specifying which parts of the string should be searched * for IFS characters. */struct ifsregion {	struct ifsregion *next;	/* next region in list */	int begoff;		/* offset of start of region */	int endoff;		/* offset of end of region */	int nulonly;		/* search for nul bytes only */};char *expdest;			/* output of current string */struct nodelist *argbackq;	/* list of back quote expressions */struct ifsregion ifsfirst;	/* first struct in list of ifs regions */struct ifsregion *ifslastp;	/* last struct in list */struct arglist exparg;		/* holds expanded arg list */#if UDIR || TILDE/* * Set if the last argument processed had /u/logname or ~logname expanded. * This variable is read by the cd command. */int didudir;#endif#ifdef __STDC__STATIC void argstr(char *, int);STATIC void expbackq(union node *, int, int);STATIC char *evalvar(char *, int);STATIC int varisset(int);STATIC void varvalue(int, int, int);STATIC void recordregion(int, int, int);STATIC void ifsbreakup(char *, struct arglist *);STATIC void expandmeta(struct strlist *);STATIC void expmeta(char *, char *);STATIC void addfname(char *);STATIC struct strlist *expsort(struct strlist *);STATIC struct strlist *msort(struct strlist *, int);STATIC int pmatch(char *, char *);#elseSTATIC void argstr();STATIC void expbackq();STATIC char *evalvar();STATIC int varisset();STATIC void varvalue();STATIC void recordregion();STATIC void ifsbreakup();STATIC void expandmeta();STATIC void expmeta();STATIC void addfname();STATIC struct strlist *expsort();STATIC struct strlist *msort();STATIC int pmatch();#endif#if UDIR || TILDE#ifdef __STDC__STATIC char *expudir(char *);#elseSTATIC char *expudir();#endif#endif /* UDIR || TILDE *//* * Expand shell variables and backquotes inside a here document. */voidexpandhere(arg, fd)	union node *arg;	/* the document */	int fd;			/* where to write the expanded version */	{	herefd = fd;	expandarg(arg, (struct arglist *)NULL, 0);	xwrite(fd, stackblock(), expdest - stackblock());}/* * Perform variable substitution and command substitution on an argument, * placing the resulting list of arguments in arglist.  If full is true, * perform splitting and file name expansion.  When arglist is NULL, perform * here document expansion. */voidexpandarg(arg, arglist, full)	union node *arg;	struct arglist *arglist;	{	struct strlist *sp;	char *p;#if UDIR || TILDE	didudir = 0;#endif	argbackq = arg->narg.backquote;	STARTSTACKSTR(expdest);	ifsfirst.next = NULL;	ifslastp = NULL;	argstr(arg->narg.text, full);	if (arglist == NULL)		return;			/* here document expanded */	STPUTC('\0', expdest);	p = grabstackstr(expdest);	exparg.lastp = &exparg.list;	if (full) {		ifsbreakup(p, &exparg);		*exparg.lastp = NULL;		exparg.lastp = &exparg.list;		expandmeta(exparg.list);	} else {		sp = (struct strlist *)stalloc(sizeof (struct strlist));		sp->text = p;		*exparg.lastp = sp;		exparg.lastp = &sp->next;	}	while (ifsfirst.next != NULL) {		struct ifsregion *ifsp;		INTOFF;		ifsp = ifsfirst.next->next;		ckfree(ifsfirst.next);		ifsfirst.next = ifsp;		INTON;	}	*exparg.lastp = NULL;	if (exparg.list) {		*arglist->lastp = exparg.list;		arglist->lastp = exparg.lastp;	}}/* * Perform variable and command substitution.  If full is set, output CTLESC * characters to allow for further processing.  If full is not set, treat * $@ like $* since no splitting will be performed. */STATIC voidargstr(p, full)	register char *p;	{	char c;	for (;;) {		switch (c = *p++) {		case '\0':		case CTLENDVAR:			goto breakloop;		case CTLESC:			if (full)				STPUTC(c, expdest);			c = *p++;			STPUTC(c, expdest);			break;		case CTLVAR:			p = evalvar(p, full);			break;		case CTLBACKQ:		case CTLBACKQ|CTLQUOTE:			expbackq(argbackq->n, c & CTLQUOTE, full);			argbackq = argbackq->next;			break;		default:			STPUTC(c, expdest);		}	}breakloop:;}/* * Expand stuff in backwards quotes. */STATIC voidexpbackq(cmd, quoted, full)	union node *cmd;	{	struct backcmd in;	int i;	char buf[128];	char *p;	char *dest = expdest;	struct ifsregion saveifs, *savelastp;	struct nodelist *saveargbackq;	char lastc;	int startloc = dest - stackblock();	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;	int saveherefd;	INTOFF;	saveifs = ifsfirst;	savelastp = ifslastp;	saveargbackq = argbackq;	saveherefd = herefd;      	herefd = -1;	p = grabstackstr(dest);	evalbackcmd(cmd, &in);	ungrabstackstr(p, dest);	ifsfirst = saveifs;	ifslastp = savelastp;	argbackq = saveargbackq;	herefd = saveherefd;	p = in.buf;	lastc = '\0';	for (;;) {		if (--in.nleft < 0) {			if (in.fd < 0)				break;			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);			TRACE(("expbackq: read returns %d\n", i));			if (i <= 0)				break;			p = buf;			in.nleft = i - 1;		}		lastc = *p++;		if (lastc != '\0') {			if (full && syntax[lastc] == CCTL)				STPUTC(CTLESC, dest);			STPUTC(lastc, dest);		}	}	if (lastc == '\n') {		STUNPUTC(dest);	}	if (in.fd >= 0)		close(in.fd);	if (in.buf)		ckfree(in.buf);	if (in.jp)		exitstatus = waitforjob(in.jp);	if (quoted == 0)		recordregion(startloc, dest - stackblock(), 0);	TRACE(("evalbackq: size=%d: \"%.*s\"\n",		(dest - stackblock()) - startloc,		(dest - stackblock()) - startloc,		stackblock() + startloc));	expdest = dest;	INTON;}/* * Expand a variable, and return a pointer to the next character in the * input string. */STATIC char *evalvar(p, full)	char *p;	{	int subtype;	int flags;	char *var;	char *val;	int c;	int set;	int special;	int startloc;	flags = *p++;	subtype = flags & VSTYPE;	var = p;	special = 0;	if (! is_name(*p))		special = 1;	p = strchr(p, '=') + 1;again: /* jump here after setting a variable with ${var=text} */	if (special) {		set = varisset(*var);		val = NULL;	} else {		val = lookupvar(var);		if (val == NULL || (flags & VSNUL) && val[0] == '\0') {			val = NULL;			set = 0;		} else			set = 1;	}	startloc = expdest - stackblock();	if (set && subtype != VSPLUS) {		/* insert the value of the variable */		if (special) {			varvalue(*var, flags & VSQUOTE, full);		} else {			char const *syntax = (flags & VSQUOTE)? DQSYNTAX : BASESYNTAX;			while (*val) {				if (full && syntax[*val] == CCTL)					STPUTC(CTLESC, expdest);				STPUTC(*val++, expdest);			}		}	}	if (subtype == VSPLUS)		set = ! set;	if (((flags & VSQUOTE) == 0 || (*var == '@' && shellparam.nparam != 1))	 && (set || subtype == VSNORMAL))		recordregion(startloc, expdest - stackblock(), flags & VSQUOTE);	if (! set && subtype != VSNORMAL) {		if (subtype == VSPLUS || subtype == VSMINUS) {			argstr(p, full);		} else {			char *startp;			int saveherefd = herefd;			herefd = -1;			argstr(p, 0);			STACKSTRNUL(expdest);			herefd = saveherefd;			startp = stackblock() + startloc;			if (subtype == VSASSIGN) {				setvar(var, startp, 0);				STADJUST(startp - expdest, expdest);				flags &=~ VSNUL;				goto again;			}			/* subtype == VSQUESTION */			if (*p != CTLENDVAR) {				outfmt(&errout, "%s\n", startp);				error((char *)NULL);			}			error("%.*s: parameter %snot set", p - var - 1,				var, (flags & VSNUL)? "null or " : nullstr);		}	}	if (subtype != VSNORMAL) {	/* skip to end of alternative */		int nesting = 1;		for (;;) {			if ((c = *p++) == CTLESC)				p++;			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {				if (set) {					if (argbackq != NULL)						argbackq = argbackq->next;				}			} else if (c == CTLVAR) {				if ((*p++ & VSTYPE) != VSNORMAL)					nesting++;			} else if (c == CTLENDVAR) {				if (--nesting == 0)					break;			}		}	}	return p;}/* * Test whether a specialized variable is set. */STATIC intvarisset(name)	char name;	{	char **ap;	if (name == '!') {		if (backgndpid == -1)			return 0;	} else if (name == '@' || name == '*') {		if (*shellparam.p == NULL)			return 0;	} else if ((unsigned)(name -= '1') <= '9' - '1') {		ap = shellparam.p;		do {			if (*ap++ == NULL)				return 0;		} while (--name >= 0);	}	return 1;}/* * Add the value of a specialized variable to the stack string. */STATIC voidvarvalue(name, quoted, allow_split)	char name;	{	int num;	char temp[32];	char *p;	int i;	extern int exitstatus;	char sep;	char **ap;	char const *syntax;	switch (name) {	case '$':		num = rootpid;		goto numvar;	case '?':		num = exitstatus;		goto numvar;	case '#':		num = shellparam.nparam;		goto numvar;	case '!':		num = backgndpid;numvar:		p = temp + 31;		temp[31] = '\0';		do {			*--p = num % 10 + '0';		} while ((num /= 10) != 0);		while (*p)			STPUTC(*p++, expdest);		break;	case '-':		for (i = 0 ; optchar[i] ; i++) {			if (optval[i])				STPUTC(optchar[i], expdest);		}		break;	case '@':		if (allow_split) {			sep = '\0';			goto allargs;		}		/* fall through */				case '*':		sep = ' ';allargs:		/* Only emit CTLESC if we will do further processing,		   i.e. if allow_split is set.  */		syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {			/* should insert CTLESC characters */			while (*p) {				if (syntax[*p] == CCTL)					STPUTC(CTLESC, expdest);				STPUTC(*p++, expdest);			}			if (*ap)				STPUTC(sep, expdest);		}		break;	case '0':		p = arg0;string:		/* Only emit CTLESC if we will do further processing,		   i.e. if allow_split is set.  */		syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX;		while (*p) {			if (syntax[*p] == CCTL)				STPUTC(CTLESC, expdest);			STPUTC(*p++, expdest);		}		break;	default:		if ((unsigned)(name -= '1') <= '9' - '1') {			p = shellparam.p[name];			goto string;		}		break;	}}/* * Record the the fact that we have to scan this region of the * string for IFS characters. */STATIC voidrecordregion(start, end, nulonly) {	register struct ifsregion *ifsp;	if (ifslastp == NULL) {		ifsp = &ifsfirst;	} else {		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));		ifslastp->next = ifsp;	}	ifslastp = ifsp;	ifslastp->next = NULL;	ifslastp->begoff = start;	ifslastp->endoff = end;	ifslastp->nulonly = nulonly;}/* * Break the argument string into pieces based upon IFS and add the * strings to the argument list.  The regions of the string to be * searched for IFS characters have been stored by recordregion. */STATIC voidifsbreakup(string, arglist)	char *string;	struct arglist *arglist;	{	struct ifsregion *ifsp;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -