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

📄 expand.c

📁 早期freebsd实现
💻 C
字号:
/* * Copyright (c) 1983, 1993 *	The Regents of the University of California.  All rights reserved. * * 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	8.1 (Berkeley) 6/9/93";#endif /* not lint */#include "defs.h"#define	GAVSIZ	NCARGS / 6#define LC '{'#define RC '}'static char	shchars[] = "${[*?";int	which;		/* bit mask of types to expand */int	eargc;		/* expanded arg count */char	**eargv;	/* expanded arg vectors */char	*path;char	*pathp;char	*lastpathp;char	*tilde;		/* "~user" if not expanding tilde, else "" */char	*tpathp;int	nleft;int	expany;		/* any expansions done? */char	*entp;char	**sortbase;#define sort()	qsort((char *)sortbase, &eargv[eargc] - sortbase, \		      sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]static void	Cat __P((char *, char *));static void	addpath __P((int));static int	amatch __P((char *, char *));static int	argcmp __P((const void *, const void *));static int	execbrc __P((char *, char *));static void	expsh __P((char *));static void	expstr __P((char *));static int	match __P((char *, char *));static void	matchdir __P((char *));static int	smatch __P((char *, char *));/* * Take a list of names and expand any macros, etc. * wh = E_VARS if expanding variables. * wh = E_SHELL if expanding shell characters. * wh = E_TILDE if expanding `~'. * or any of these or'ed together. * * Major portions of this were snarfed from csh/sh.glob.c. */struct namelist *expand(list, wh)	struct namelist *list;	int wh;{	register struct namelist *nl, *prev;	register int n;	char pathbuf[BUFSIZ];	char *argvbuf[GAVSIZ];	if (debug) {		printf("expand(%x, %d)\nlist = ", list, wh);		prnames(list);	}	if (wh == 0) {		register char *cp;		for (nl = list; nl != NULL; nl = nl->n_next)			for (cp = nl->n_name; *cp; cp++)				*cp = *cp & TRIM;		return(list);	}	which = wh;	path = tpathp = pathp = pathbuf;	*pathp = '\0';	lastpathp = &path[sizeof pathbuf - 2];	tilde = "";	eargc = 0;	eargv = sortbase = argvbuf;	*eargv = 0;	nleft = NCARGS - 4;	/*	 * Walk the name list and expand names into eargv[];	 */	for (nl = list; nl != NULL; nl = nl->n_next)		expstr(nl->n_name);	/*	 * Take expanded list of names from eargv[] and build a new list.	 */	list = prev = NULL;	for (n = 0; n < eargc; n++) {		nl = makenl(NULL);		nl->n_name = eargv[n];		if (prev == NULL)			list = prev = nl;		else {			prev->n_next = nl;			prev = nl;		}	}	if (debug) {		printf("expanded list = ");		prnames(list);	}	return(list);}static voidexpstr(s)	char *s;{	register char *cp, *cp1;	register struct namelist *tp;	char *tail;	char buf[BUFSIZ];	int savec, oeargc;	extern char homedir[];	if (s == NULL || *s == '\0')		return;	if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {		*cp++ = '\0';		if (*cp == '\0') {			yyerror("no variable name after '$'");			return;		}		if (*cp == LC) {			cp++;			if ((tail = index(cp, RC)) == NULL) {				yyerror("unmatched '{'");				return;			}			*tail++ = savec = '\0';			if (*cp == '\0') {				yyerror("no variable name after '$'");				return;			}		} else {			tail = cp + 1;			savec = *tail;			*tail = '\0';		}		tp = lookup(cp, NULL, 0);		if (savec != '\0')			*tail = savec;		if (tp != NULL) {			for (; tp != NULL; tp = tp->n_next) {				sprintf(buf, "%s%s%s", s, tp->n_name, tail);				expstr(buf);			}			return;		}		sprintf(buf, "%s%s", s, tail);		expstr(buf);		return;	}	if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {		Cat(s, "");		sort();		return;	}	if (*s == '~') {		cp = ++s;		if (*cp == '\0' || *cp == '/') {			tilde = "~";			cp1 = homedir;		} else {			tilde = cp1 = buf;			*cp1++ = '~';			do				*cp1++ = *cp++;			while (*cp && *cp != '/');			*cp1 = '\0';			if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {				if ((pw = getpwnam(buf+1)) == NULL) {					strcat(buf, ": unknown user name");					yyerror(buf+1);					return;				}			}			cp1 = pw->pw_dir;			s = cp;		}		for (cp = path; *cp++ = *cp1++; )			;		tpathp = pathp = cp - 1;	} else {		tpathp = pathp = path;		tilde = "";	}	*pathp = '\0';	if (!(which & E_SHELL)) {		if (which & E_TILDE)			Cat(path, s);		else			Cat(tilde, s);		sort();		return;	}	oeargc = eargc;	expany = 0;	expsh(s);	if (eargc == oeargc)		Cat(s, "");		/* "nonomatch" is set */	sort();}static intargcmp(a1, a2)	const void *a1, *a2;{	return (strcmp(*(char **)a1, *(char **)a2));}/* * If there are any Shell meta characters in the name, * expand into a list, after searching directory */static voidexpsh(s)	char *s;{	register char *cp;	register char *spathp, *oldcp;	struct stat stb;	spathp = pathp;	cp = s;	while (!any(*cp, shchars)) {		if (*cp == '\0') {			if (!expany || stat(path, &stb) >= 0) {				if (which & E_TILDE)					Cat(path, "");				else					Cat(tilde, tpathp);			}			goto endit;		}		addpath(*cp++);	}	oldcp = cp;	while (cp > s && *cp != '/')		cp--, pathp--;	if (*cp == '/')		cp++, pathp++;	*pathp = '\0';	if (*oldcp == '{') {		execbrc(cp, NULL);		return;	}	matchdir(cp);endit:	pathp = spathp;	*pathp = '\0';}static voidmatchdir(pattern)	char *pattern;{	struct stat stb;	register struct direct *dp;	DIR *dirp;	dirp = opendir(path);	if (dirp == NULL) {		if (expany)			return;		goto patherr2;	}	if (fstat(dirp->dd_fd, &stb) < 0)		goto patherr1;	if (!ISDIR(stb.st_mode)) {		errno = ENOTDIR;		goto patherr1;	}	while ((dp = readdir(dirp)) != NULL)		if (match(dp->d_name, pattern)) {			if (which & E_TILDE)				Cat(path, dp->d_name);			else {				strcpy(pathp, dp->d_name);				Cat(tilde, tpathp);				*pathp = '\0';			}		}	closedir(dirp);	return;patherr1:	closedir(dirp);patherr2:	strcat(path, ": ");	strcat(path, strerror(errno));	yyerror(path);}static intexecbrc(p, s)	char *p, *s;{	char restbuf[BUFSIZ + 2];	register char *pe, *pm, *pl;	int brclev = 0;	char *lm, savec, *spathp;	for (lm = restbuf; *p != '{'; *lm++ = *p++)		continue;	for (pe = ++p; *pe; pe++)		switch (*pe) {		case '{':			brclev++;			continue;		case '}':			if (brclev == 0)				goto pend;			brclev--;			continue;		case '[':			for (pe++; *pe && *pe != ']'; pe++)				continue;			if (!*pe)				yyerror("Missing ']'");			continue;		}pend:	if (brclev || !*pe) {		yyerror("Missing '}'");		return (0);	}	for (pl = pm = p; pm <= pe; pm++)		switch (*pm & (QUOTE|TRIM)) {		case '{':			brclev++;			continue;		case '}':			if (brclev) {				brclev--;				continue;			}			goto doit;		case ',':			if (brclev)				continue;doit:			savec = *pm;			*pm = 0;			strcpy(lm, pl);			strcat(restbuf, pe + 1);			*pm = savec;			if (s == 0) {				spathp = pathp;				expsh(restbuf);				pathp = spathp;				*pathp = 0;			} else if (amatch(s, restbuf))				return (1);			sort();			pl = pm + 1;			continue;		case '[':			for (pm++; *pm && *pm != ']'; pm++)				continue;			if (!*pm)				yyerror("Missing ']'");			continue;		}	return (0);}static intmatch(s, p)	char *s, *p;{	register int c;	register char *sentp;	char sexpany = expany;	if (*s == '.' && *p != '.')		return (0);	sentp = entp;	entp = s;	c = amatch(s, p);	entp = sentp;	expany = sexpany;	return (c);}static intamatch(s, p)	register char *s, *p;{	register int scc;	int ok, lc;	char *spathp;	struct stat stb;	int c, cc;	expany = 1;	for (;;) {		scc = *s++ & TRIM;		switch (c = *p++) {		case '{':			return (execbrc(p - 1, s - 1));		case '[':			ok = 0;			lc = 077777;			while (cc = *p++) {				if (cc == ']') {					if (ok)						break;					return (0);				}				if (cc == '-') {					if (lc <= scc && scc <= *p++)						ok++;				} else					if (scc == (lc = cc))						ok++;			}			if (cc == 0) {				yyerror("Missing ']'");				return (0);			}			continue;		case '*':			if (!*p)				return (1);			if (*p == '/') {				p++;				goto slash;			}			for (s--; *s; s++)				if (amatch(s, p))					return (1);			return (0);		case '\0':			return (scc == '\0');		default:			if ((c & TRIM) != scc)				return (0);			continue;		case '?':			if (scc == '\0')				return (0);			continue;		case '/':			if (scc)				return (0);slash:			s = entp;			spathp = pathp;			while (*s)				addpath(*s++);			addpath('/');			if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))				if (*p == '\0') {					if (which & E_TILDE)						Cat(path, "");					else						Cat(tilde, tpathp);				} else					expsh(p);			pathp = spathp;			*pathp = '\0';			return (0);		}	}}static intsmatch(s, p)	register char *s, *p;{	register int scc;	int ok, lc;	int c, cc;	for (;;) {		scc = *s++ & TRIM;		switch (c = *p++) {		case '[':			ok = 0;			lc = 077777;			while (cc = *p++) {				if (cc == ']') {					if (ok)						break;					return (0);				}				if (cc == '-') {					if (lc <= scc && scc <= *p++)						ok++;				} else					if (scc == (lc = cc))						ok++;			}			if (cc == 0) {				yyerror("Missing ']'");				return (0);			}			continue;		case '*':			if (!*p)				return (1);			for (s--; *s; s++)				if (smatch(s, p))					return (1);			return (0);		case '\0':			return (scc == '\0');		default:			if ((c & TRIM) != scc)				return (0);			continue;		case '?':			if (scc == 0)				return (0);			continue;		}	}}static voidCat(s1, s2)	register char *s1, *s2;{	int len = strlen(s1) + strlen(s2) + 1;	register char *s;	nleft -= len;	if (nleft <= 0 || ++eargc >= GAVSIZ)		yyerror("Arguments too long");	eargv[eargc] = 0;	eargv[eargc - 1] = s = malloc(len);	if (s == NULL)		fatal("ran out of memory\n");	while (*s++ = *s1++ & TRIM)		;	s--;	while (*s++ = *s2++ & TRIM)		;}static voidaddpath(c)	int c;{	if (pathp >= lastpathp)		yyerror("Pathname too long");	else {		*pathp++ = c & TRIM;		*pathp = '\0';	}}/* * Expand file names beginning with `~' into the * user's home directory path name. Return a pointer in buf to the * part corresponding to `file'. */char *exptilde(buf, file)	char buf[];	register char *file;{	register char *s1, *s2, *s3;	extern char homedir[];	if (*file != '~') {		strcpy(buf, file);		return(buf);	}	if (*++file == '\0') {		s2 = homedir;		s3 = NULL;	} else if (*file == '/') {		s2 = homedir;		s3 = file;	} else {		s3 = file;		while (*s3 && *s3 != '/')			s3++;		if (*s3 == '/')			*s3 = '\0';		else			s3 = NULL;		if (pw == NULL || strcmp(pw->pw_name, file) != 0) {			if ((pw = getpwnam(file)) == NULL) {				error("%s: unknown user name\n", file);				if (s3 != NULL)					*s3 = '/';				return(NULL);			}		}		if (s3 != NULL)			*s3 = '/';		s2 = pw->pw_dir;	}	for (s1 = buf; *s1++ = *s2++; )		;	s2 = --s1;	if (s3 != NULL) {		s2++;		while (*s1++ = *s3++)			;	}	return(s2);}

⌨️ 快捷键说明

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