expand.c

来自「ftam等标准协议服务器和客户端的源代码。」· C语言 代码 · 共 605 行

C
605
字号
/* expand.c -- various expanisions of shell type patterns *//* * $Header: /xtel/isode/isode/others/idist/RCS/expand.c,v 9.0 1992/06/16 14:38:53 isode Rel $ * * Expansion primitives for wild card names. The tilde expansion stuff * has been moved out as both sides require that whilst only the * client requires this stuff. * * Julian Onions <jpo@cs.nott.ac.uk> * Nottingham University Computer Science * * * $Log: expand.c,v $ * Revision 9.0  1992/06/16  14:38:53  isode * Release 8.0 * *  *//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement:  ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */#ifndef lintstatic char sccsid[] = "@(#)expand.c    5.6 (Berkeley) 6/1/90";static char *rcsid = "$Header: /xtel/isode/isode/others/idist/RCS/expand.c,v 9.0 1992/06/16 14:38:53 isode Rel $";#endif#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;int	argcmp();#define sort()	qsort((char *)sortbase, &eargv[eargc] - sortbase, \		      sizeof(*sortbase), (IFP)argcmp), sortbase = &eargv[eargc]/* * 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) {		(void) 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((char *)NULL);		nl->n_name = eargv[n];		if (prev == NULL)			list = prev = nl;		else {			prev->n_next = nl;			prev = nl;		}	}	if (debug) {		(void) printf("expanded list = ");		prnames(list);	}	return(list);}expstr(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, (struct namelist *)0);		if (savec != '\0')			*tail = savec;		if (tp != NULL) {			for (; tp != NULL; tp = tp->n_next) {				(void) sprintf(buf, "%s%s%s",					       s, tp->n_name, tail);				expstr(buf);			}			return;		}		(void) 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) {					(void) 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();}staticargcmp(a1, a2)	char **a1, **a2;{	return (strcmp(*a1, *a2));}/* * If there are any Shell meta characters in the name, * expand into a list, after searching directory */expsh(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 == '{') {		(void) execbrc(cp, (char *)NULL);		return;	}	matchdir(cp);endit:	pathp = spathp;	*pathp = '\0';}matchdir(pattern)	char *pattern;{	struct stat stb;	register struct dirent *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 {				(void) strcpy(pathp, dp->d_name);				Cat(tilde, tpathp);				*pathp = '\0';			}		}	(void) closedir(dirp);	return;patherr1:	(void) closedir(dirp);patherr2:	(void) strcat(path, ": ");	(void) strcat(path, sys_errlist[errno]);	yyerror(path);}execbrc(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;			(void) strcpy(lm, pl);			(void) 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);}match(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);}amatch(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);		}	}}smatch(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;		}	}}Cat(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((unsigned)len);	if (s == NULL)		adios (NULLCP, "ran out of memory");	while (*s++ = *s1++ & TRIM)		;	s--;	while (*s++ = *s2++ & TRIM)		;}addpath(c)	char c;{	if (pathp >= lastpathp)		yyerror("Pathname too long");	else {		*pathp++ = c & TRIM;		*pathp = '\0';	}}

⌨️ 快捷键说明

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