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

📄 pat_rep.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Keith Muller of the University of California, San Diego. * * 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[] = "@(#)pat_rep.c	8.2 (Berkeley) 4/18/94";#endif /* not lint */#include <sys/types.h>#include <sys/time.h>#include <sys/stat.h>#include <sys/param.h>#include <stdio.h>#include <ctype.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#ifdef NET2_REGEX#include <regexp.h>#else#include <regex.h>#endif#include "pax.h"#include "pat_rep.h"#include "extern.h"/* * routines to handle pattern matching, name modification (regular expression * substitution and interactive renames), and destination name modification for * copy (-rw). Both file name and link names are adjusted as required in these * routines. */#define MAXSUBEXP	10		/* max subexpressions, DO NOT CHANGE */static PATTERN *pathead = NULL;		/* file pattern match list head */static PATTERN *pattail = NULL;		/* file pattern match list tail */static REPLACE *rephead = NULL;		/* replacement string list head */static REPLACE *reptail = NULL;		/* replacement string list tail */static int rep_name __P((char *, int *, int));static int tty_rename __P((register ARCHD *));static int fix_path __P((char *, int *, char *, int));static int fn_match __P((register char *, register char *, char **));static char * range_match __P((register char *, register int));#ifdef NET2_REGEXstatic int resub __P((regexp *, char *, char *, register char *));#elsestatic int resub __P((regex_t *, regmatch_t *, char *, char *, char *));#endif/* * rep_add() *	parses the -s replacement string; compiles the regular expression *	and stores the compiled value and it's replacement string together in *	replacement string list. Input to this function is of the form: *		/old/new/pg  *	The first char in the string specifies the delimiter used by this *	replacement string. "Old" is a regular expression in "ed" format which *	is compiled by regcomp() and is applied to filenames. "new" is the *	substitution string; p and g are options flags for printing and global *	replacement (over the single filename) * Return: *	0 if a proper replacement string and regular expression was added to *	the list of replacement patterns; -1 otherwise. */#if __STDC__intrep_add(register char *str)#elseintrep_add(str)	register char *str;#endif{	register char *pt1;	register char *pt2;	register REPLACE *rep;#	ifndef NET2_REGEX	register int res;	char rebuf[BUFSIZ];#	endif	/*	 * throw out the bad parameters	 */	if ((str == NULL) || (*str == '\0')) {		warn(1, "Empty replacement string");		return(-1);	}	/*	 * first character in the string specifies what the delimiter is for	 * this expression	 */	if ((pt1 = strchr(str+1, *str)) == NULL) {		warn(1, "Invalid replacement string %s", str);		return(-1);	}	/*	 * allocate space for the node that handles this replacement pattern	 * and split out the regular expression and try to compile it	 */	if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {		warn(1, "Unable to allocate memory for replacement string");		return(-1);	}	*pt1 = '\0';#	ifdef NET2_REGEX	if ((rep->rcmp = regcomp(str+1)) == NULL) {#	else	if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {		regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));		warn(1, "%s while compiling regular expression %s", rebuf, str);#	endif		(void)free((char *)rep);		return(-1);	}	/*	 * put the delimiter back in case we need an error message and	 * locate the delimiter at the end of the replacement string	 * we then point the node at the new substitution string	 */	*pt1++ = *str;	if ((pt2 = strchr(pt1, *str)) == NULL) {#		ifdef NET2_REGEX		(void)free((char *)rep->rcmp);#		else		regfree(&(rep->rcmp));#		endif		(void)free((char *)rep);		warn(1, "Invalid replacement string %s", str);		return(-1);	}	*pt2 = '\0';	rep->nstr = pt1;	pt1 = pt2++;	rep->flgs = 0;	/*	 * set the options if any	 */	while (*pt2 != '\0') {		switch(*pt2) {		case 'g':		case 'G':			rep->flgs  |= GLOB;			break;		case 'p':		case 'P':			rep->flgs  |= PRNT;			break;		default:#			ifdef NET2_REGEX			(void)free((char *)rep->rcmp);#			else			regfree(&(rep->rcmp));#			endif			(void)free((char *)rep);			*pt1 = *str;			warn(1, "Invalid replacement string option %s", str);			return(-1);		}		++pt2;	}	/*	 * all done, link it in at the end	 */	rep->fow = NULL;	if (rephead == NULL) {		reptail = rephead = rep;		return(0);	}	reptail->fow = rep;	reptail = rep;	return(0);}/* * pat_add() *	add a pattern match to the pattern match list. Pattern matches are used *	to select which archive members are extracted. (They appear as *	arguments to pax in the list and read modes). If no patterns are *	supplied to pax, all members in the archive will be selected (and the *	pattern match list is empty). * Return: *	0 if the pattern was added to the list, -1 otherwise */#if __STDC__intpat_add(char *str)#elseintpat_add(str)	char *str;#endif{	register PATTERN *pt;	/*	 * throw out the junk	 */	if ((str == NULL) || (*str == '\0')) {		warn(1, "Empty pattern string");		return(-1);	}	/*	 * allocate space for the pattern and store the pattern. the pattern is	 * part of argv so do not bother to copy it, just point at it. Add the	 * node to the end of the pattern list	 */	if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {		warn(1, "Unable to allocate memory for pattern string");		return(-1);	}	pt->pstr = str;	pt->pend = NULL;	pt->plen = strlen(str);	pt->fow = NULL;	pt->flgs = 0;	if (pathead == NULL) {		pattail = pathead = pt;		return(0);	}	pattail->fow = pt;	pattail = pt;	return(0);}/* * pat_chk() *	complain if any the user supplied pattern did not result in a match to *	a selected archive member. */#if __STDC__voidpat_chk(void)#elsevoidpat_chk()#endif{	register PATTERN *pt;	register int wban = 0;	/*	 * walk down the list checking the flags to make sure MTCH was set,	 * if not complain	 */	for (pt = pathead; pt != NULL; pt = pt->fow) {		if (pt->flgs & MTCH)			continue;		if (!wban) {			warn(1, "WARNING! These patterns were not matched:");			++wban;		}		(void)fprintf(stderr, "%s\n", pt->pstr);	}}/* * pat_sel() *	the archive member which matches a pattern was selected. Mark the *	pattern as having selected an archive member. arcn->pat points at the *	pattern that was matched. arcn->pat is set in pat_match() * *	NOTE: When the -c option is used, we are called when there was no match *	by pat_match() (that means we did match before the inverted sense of *	the logic). Now this seems really strange at first, but with -c  we *	need to keep track of those patterns that cause a archive member to NOT *	be selected (it found an archive member with a specified pattern) * Return: *	0 if the pattern pointed at by arcn->pat was tagged as creating a *	match, -1 otherwise. */#if __STDC__intpat_sel(register ARCHD *arcn)#elseintpat_sel(arcn)	register ARCHD *arcn;#endif{	register PATTERN *pt;	register PATTERN **ppt;	register int len;	/*	 * if no patterns just return	 */	if ((pathead == NULL) || ((pt = arcn->pat) == NULL))		return(0);	/*	 * when we are NOT limited to a single match per pattern mark the	 * pattern and return	 */	if (!nflag) {		pt->flgs |= MTCH;		return(0);	}	/*	 * we reach this point only when we allow a single selected match per	 * pattern, if the pattern matches a directory and we do not have -d 	 * (dflag) we are done with this pattern. We may also be handed a file	 * in the subtree of a directory. in that case when we are operating	 * with -d, this pattern was already selected and we are done	 */	if (pt->flgs & DIR_MTCH)		return(0);	if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {		/*		 * ok we matched a directory and we are allowing		 * subtree matches but because of the -n only its children will		 * match. This is tagged as a DIR_MTCH type.		 * WATCH IT, the code assumes that pt->pend points		 * into arcn->name and arcn->name has not been modified.		 * If not we will have a big mess. Yup this is another kludge		 */		/*		 * if this was a prefix match, remove trailing part of path		 * so we can copy it. Future matches will be exact prefix match		 */		if (pt->pend != NULL)			*pt->pend = '\0';					if ((pt->pstr = strdup(arcn->name)) == NULL) {			warn(1, "Pattern select out of memory");			if (pt->pend != NULL)				*pt->pend = '/';			pt->pend = NULL;			return(-1);		}		/*		 * put the trailing / back in the source string		 */		if (pt->pend != NULL) {			*pt->pend = '/';			pt->pend = NULL;		}		pt->plen = strlen(pt->pstr);		/*		 * strip off any trailing /, this should really never happen		 */		len = pt->plen - 1;		if (*(pt->pstr + len) == '/') {			*(pt->pstr + len) = '\0';			pt->plen = len;		} 		pt->flgs = DIR_MTCH | MTCH;		arcn->pat = pt;		return(0);	}	/*	 * we are then done with this pattern, so we delete it from the list	 * because it can never be used for another match.	 * Seems kind of strange to do for a -c, but the pax spec is really	 * vague on the interaction of -c -n and -d. We assume that when -c	 * and the pattern rejects a member (i.e. it matched it) it is done.	 * In effect we place the order of the flags as having -c last.	 */	pt = pathead;	ppt = &pathead;	while ((pt != NULL) && (pt != arcn->pat)) {		ppt = &(pt->fow);		pt = pt->fow;	}	if (pt == NULL) {		/*		 * should never happen....		 */		warn(1, "Pattern list inconsistant");		return(-1);	}	*ppt = pt->fow;	(void)free((char *)pt);	arcn->pat = NULL;	return(0);}/* * pat_match() *	see if this archive member matches any supplied pattern, if a match *	is found, arcn->pat is set to point at the potential pattern. Later if *	this archive member is "selected" we process and mark the pattern as *	one which matched a selected archive member (see pat_sel()) * Return: *	0 if this archive member should be processed, 1 if it should be  *	skipped and -1 if we are done with all patterns (and pax should quit *	looking for more members) */#if __STDC__intpat_match(register ARCHD *arcn)#elseintpat_match(arcn)	register ARCHD *arcn;#endif{	register PATTERN *pt;	arcn->pat = NULL;	/*	 * if there are no more patterns and we have -n (and not -c) we are	 * done. otherwise with no patterns to match, matches all	 */	if (pathead == NULL) {		if (nflag && !cflag)			return(-1);		return(0);	}	/*	 * have to search down the list one at a time looking for a match.	 */	pt = pathead;	while (pt != NULL) {		/*		 * check for a file name match unless we have DIR_MTCH set in		 * this pattern then we want a prefix match		 */		if (pt->flgs & DIR_MTCH) {			/*			 * this pattern was matched before to a directory			 * as we must have -n set for this (but not -d). We can			 * only match CHILDREN of that directory so we must use			 * an exact prefix match (no wildcards).			 */			if ((arcn->name[pt->plen] == '/') &&			    (strncmp(pt->pstr, arcn->name, pt->plen) == 0))				break;		} else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)			break;		pt = pt->fow;	}	/*	 * return the result, remember that cflag (-c) inverts the sense of a	 * match	 */	if (pt == NULL)		return(cflag ? 0 : 1);	/*	 * we had a match, now when we invert the sense (-c) we reject this	 * member. However we have to tag the pattern a being successful, (in a	 * match, not in selecting a archive member) so we call pat_sel() here.	 */	arcn->pat = pt;	if (!cflag)		return(0);	if (pat_sel(arcn) < 0)		return(-1);	arcn->pat = NULL;	return(1);}/* * fn_match() * Return: *	0 if this archive member should be processed, 1 if it should be  *	skipped and -1 if we are done with all patterns (and pax should quit *	looking for more members) *	Note: *pend may be changed to show where the prefix ends. */#if __STDC__static intfn_match(register char *pattern, register char *string, char **pend)#elsestatic intfn_match(pattern, string, pend)	register char *pattern;	register char *string;	char **pend;#endif{	register char c;	char test;	*pend = NULL;	for (;;) {		switch (c = *pattern++) {		case '\0':			/*			 * Ok we found an exact match			 */			if (*string == '\0')				return(0);			/*			 * Check if it is a prefix match			 */			if ((dflag == 1) || (*string != '/'))				return(-1);			/*			 * It is a prefix match, remember where the trailing			 * / is located			 */			*pend = string;			return(0);		case '?':			if ((test = *string++) == '\0')				return (-1);			break;		case '*':			c = *pattern;			/*			 * Collapse multiple *'s. 			 */			while (c == '*')				c = *++pattern;			/*			 * Optimized hack for pattern with a * at the end			 */			if (c == '\0')				return (0);			/*			 * General case, use recursion.			 */			while ((test = *string) != '\0') {				if (!fn_match(pattern, string, pend))					return (0);				++string;			}			return (-1);		case '[':			/*			 * range match			 */			if (((test = *string++) == '\0') ||			    ((pattern = range_match(pattern, test)) == NULL))				return (-1);			break;		case '\\':		default:			if (c != *string++)				return (-1);			break;		}	}

⌨️ 快捷键说明

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