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

📄 expand.c

📁 Android 一些工具
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	$NetBSD: expand.c,v 1.68.2.2 2005/04/07 11:37:39 tron Exp $	*//*- * Copyright (c) 1991, 1993 *	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. 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. */#include <sys/cdefs.h>#ifndef lint#if 0static char sccsid[] = "@(#)expand.c	8.5 (Berkeley) 5/15/95";#else__RCSID("$NetBSD: expand.c,v 1.68.2.2 2005/04/07 11:37:39 tron Exp $");#endif#endif /* not lint */#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <errno.h>#include <dirent.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>/* * 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 "show.h"/* * 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 inquotes;		/* 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 */STATIC void argstr(char *, int);STATIC char *exptilde(char *, int);STATIC void expbackq(union node *, int, int);STATIC int subevalvar(char *, char *, int, int, int, int);STATIC char *evalvar(char *, int);STATIC int varisset(char *, int);STATIC void varvalue(char *, int, int, int);STATIC void recordregion(int, int, int);STATIC void removerecordregions(int); STATIC void ifsbreakup(char *, struct arglist *);STATIC void ifsfree(void);STATIC void expandmeta(struct strlist *, int);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 *, int);STATIC char *cvtnum(int, char *);/* * Expand shell variables and backquotes inside a here document. */voidexpandhere(union node *arg, int fd){	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 EXP_FULL is true, * perform splitting and file name expansion.  When arglist is NULL, perform * here document expansion. */voidexpandarg(union node *arg, struct arglist *arglist, int flag){	struct strlist *sp;	char *p;	argbackq = arg->narg.backquote;	STARTSTACKSTR(expdest);	ifsfirst.next = NULL;	ifslastp = NULL;	argstr(arg->narg.text, flag);	if (arglist == NULL) {		return;			/* here document expanded */	}	STPUTC('\0', expdest);	p = grabstackstr(expdest);	exparg.lastp = &exparg.list;	/*	 * TODO - EXP_REDIR	 */	if (flag & EXP_FULL) {		ifsbreakup(p, &exparg);		*exparg.lastp = NULL;		exparg.lastp = &exparg.list;		expandmeta(exparg.list, flag);	} else {		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */			rmescapes(p);		sp = (struct strlist *)stalloc(sizeof (struct strlist));		sp->text = p;		*exparg.lastp = sp;		exparg.lastp = &sp->next;	}	ifsfree();	*exparg.lastp = NULL;	if (exparg.list) {		*arglist->lastp = exparg.list;		arglist->lastp = exparg.lastp;	}}/* * Perform variable and command substitution. * If EXP_FULL is set, output CTLESC characters to allow for further processing. * Otherwise treat $@ like $* since no splitting will be performed. */STATIC voidargstr(char *p, int flag){	char c;	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */	int firsteq = 1;	const char *ifs = 0;	int ifs_split = EXP_IFS_SPLIT;	if (flag & EXP_IFS_SPLIT)		ifs = ifsset() ? ifsval() : " \t\n";	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))		p = exptilde(p, flag);	for (;;) {		switch (c = *p++) {		case '\0':		case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */			return;		case CTLQUOTEMARK:			/* "$@" syntax adherence hack */			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')				break;			if ((flag & EXP_FULL) != 0)				STPUTC(c, expdest);			ifs_split = 0;			break;		case CTLQUOTEEND:			ifs_split = EXP_IFS_SPLIT;			break;		case CTLESC:			if (quotes)				STPUTC(c, expdest);			c = *p++;			STPUTC(c, expdest);			break;		case CTLVAR:			p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));			break;		case CTLBACKQ:		case CTLBACKQ|CTLQUOTE:			expbackq(argbackq->n, c & CTLQUOTE, flag);			argbackq = argbackq->next;			break;		case CTLENDARI:			expari(flag);			break;		case ':':		case '=':			/*			 * sort of a hack - expand tildes in variable			 * assignments (after the first '=' and after ':'s).			 */			STPUTC(c, expdest);			if (flag & EXP_VARTILDE && *p == '~') {				if (c == '=') {					if (firsteq)						firsteq = 0;					else						break;				}				p = exptilde(p, flag);			}			break;		default:			STPUTC(c, expdest);			if (flag & EXP_IFS_SPLIT & ifs_split && strchr(ifs, c) != NULL) {				/* We need to get the output split here... */				recordregion(expdest - stackblock() - 1,						expdest - stackblock(), 0);			}			break;		}	}}STATIC char *exptilde(char *p, int flag){	char c, *startp = p;	const char *home;	int quotes = flag & (EXP_FULL | EXP_CASE);	while ((c = *p) != '\0') {		switch(c) {		case CTLESC:			return (startp);		case CTLQUOTEMARK:			return (startp);		case ':':			if (flag & EXP_VARTILDE)				goto done;			break;		case '/':			goto done;		}		p++;	}done:	*p = '\0';	if (*(startp+1) == '\0') {		if ((home = lookupvar("HOME")) == NULL)			goto lose;	} else        	goto lose;	if (*home == '\0')		goto lose;	*p = c;	while ((c = *home++) != '\0') {		if (quotes && SQSYNTAX[(int)c] == CCTL)			STPUTC(CTLESC, expdest);		STPUTC(c, expdest);	}	return (p);lose:	*p = c;	return (startp);}STATIC void removerecordregions(int endoff){	if (ifslastp == NULL)		return;	if (ifsfirst.endoff > endoff) {		while (ifsfirst.next != NULL) {			struct ifsregion *ifsp;			INTOFF;			ifsp = ifsfirst.next->next;			ckfree(ifsfirst.next);			ifsfirst.next = ifsp;			INTON;		}		if (ifsfirst.begoff > endoff)			ifslastp = NULL;		else {			ifslastp = &ifsfirst;			ifsfirst.endoff = endoff;		}		return;	}		ifslastp = &ifsfirst;	while (ifslastp->next && ifslastp->next->begoff < endoff)		ifslastp=ifslastp->next;	while (ifslastp->next != NULL) {		struct ifsregion *ifsp;		INTOFF;		ifsp = ifslastp->next->next;		ckfree(ifslastp->next);		ifslastp->next = ifsp;		INTON;	}	if (ifslastp->endoff > endoff)		ifslastp->endoff = endoff;}/* * Expand arithmetic expression.  Backup to start of expression, * evaluate, place result in (backed up) result, adjust string position. */voidexpari(int flag){	char *p, *start;	int result;	int begoff;	int quotes = flag & (EXP_FULL | EXP_CASE);	int quoted;	/*	ifsfree(); */	/*	 * This routine is slightly over-complicated for	 * efficiency.  First we make sure there is	 * enough space for the result, which may be bigger	 * than the expression if we add exponentation.  Next we	 * scan backwards looking for the start of arithmetic.  If the	 * next previous character is a CTLESC character, then we	 * have to rescan starting from the beginning since CTLESC	 * characters have to be processed left to right.	 */#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10#error "integers with more than 10 digits are not supported"#endif	CHECKSTRSPACE(12 - 2, expdest);	USTPUTC('\0', expdest);	start = stackblock();	p = expdest - 1;	while (*p != CTLARI && p >= start)		--p;	if (*p != CTLARI)		error("missing CTLARI (shouldn't happen)");	if (p > start && *(p-1) == CTLESC)		for (p = start; *p != CTLARI; p++)			if (*p == CTLESC)				p++;	if (p[1] == '"')		quoted=1;	else		quoted=0;	begoff = p - start;	removerecordregions(begoff);	if (quotes)		rmescapes(p+2);	result = arith(p+2);	fmtstr(p, 12, "%d", result);	while (*p++)		;	if (quoted == 0)		recordregion(begoff, p - 1 - start, 0);	result = expdest - p + 1;	STADJUST(-result, expdest);}/* * Expand stuff in backwards quotes. */STATIC voidexpbackq(union node *cmd, int quoted, int flag){	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;	int quotes = flag & (EXP_FULL | EXP_CASE);	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 (quotes && syntax[(int)lastc] == CCTL)				STPUTC(CTLESC, dest);			STPUTC(lastc, dest);		}	}	/* Eat all trailing newlines */	p = stackblock() + startloc;	while (dest > p && dest[-1] == '\n')		STUNPUTC(dest);	if (in.fd >= 0)		close(in.fd);	if (in.buf)		ckfree(in.buf);	if (in.jp)		back_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;}STATIC intsubevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags){	char *startp;	char *loc = NULL;	char *q;	int c = 0;	int saveherefd = herefd;	struct nodelist *saveargbackq = argbackq;	int amount;	herefd = -1;	argstr(p, 0);	STACKSTRNUL(expdest);	herefd = saveherefd;	argbackq = saveargbackq;	startp = stackblock() + startloc;	if (str == NULL)	    str = stackblock() + strloc;	switch (subtype) {	case VSASSIGN:		setvar(str, startp, 0);		amount = startp - expdest;		STADJUST(amount, expdest);		varflags &= ~VSNUL;		if (c != 0)			*loc = c;		return 1;	case VSQUESTION:		if (*p != CTLENDVAR) {			outfmt(&errout, "%s\n", startp);			error((char *)NULL);		}		error("%.*s: parameter %snot set", p - str - 1,		      str, (varflags & VSNUL) ? "null or "					      : nullstr);		/* NOTREACHED */

⌨️ 快捷键说明

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