xref: /csrg-svn/bin/pax/pat_rep.c (revision 66890)
157266Smuller /*-
257266Smuller  * Copyright (c) 1992 Keith Muller.
360676Sbostic  * Copyright (c) 1992, 1993
460676Sbostic  *	The Regents of the University of California.  All rights reserved.
557266Smuller  *
657266Smuller  * This code is derived from software contributed to Berkeley by
757266Smuller  * Keith Muller of the University of California, San Diego.
857266Smuller  *
957266Smuller  * %sccs.include.redist.c%
1057266Smuller  */
1157266Smuller 
1257266Smuller #ifndef lint
13*66890Sbostic static char sccsid[] = "@(#)pat_rep.c	8.2 (Berkeley) 04/18/94";
1457266Smuller #endif /* not lint */
1557266Smuller 
1657266Smuller #include <sys/types.h>
1757266Smuller #include <sys/time.h>
1857266Smuller #include <sys/stat.h>
1957266Smuller #include <sys/param.h>
2057266Smuller #include <stdio.h>
2157266Smuller #include <ctype.h>
2257266Smuller #include <string.h>
2357266Smuller #include <unistd.h>
2457266Smuller #include <stdlib.h>
2557266Smuller #ifdef NET2_REGEX
2657266Smuller #include <regexp.h>
2757266Smuller #else
2857266Smuller #include <regex.h>
2957266Smuller #endif
3057266Smuller #include "pax.h"
3157266Smuller #include "pat_rep.h"
3257266Smuller #include "extern.h"
3357266Smuller 
3457266Smuller /*
3557266Smuller  * routines to handle pattern matching, name modification (regular expression
3657266Smuller  * substitution and interactive renames), and destination name modification for
3757266Smuller  * copy (-rw). Both file name and link names are adjusted as required in these
3857266Smuller  * routines.
3957266Smuller  */
4057266Smuller 
4157266Smuller #define MAXSUBEXP	10		/* max subexpressions, DO NOT CHANGE */
4257266Smuller static PATTERN *pathead = NULL;		/* file pattern match list head */
4357266Smuller static PATTERN *pattail = NULL;		/* file pattern match list tail */
4457266Smuller static REPLACE *rephead = NULL;		/* replacement string list head */
4557266Smuller static REPLACE *reptail = NULL;		/* replacement string list tail */
4657266Smuller 
4757266Smuller static int rep_name __P((char *, int *, int));
4857266Smuller static int tty_rename __P((register ARCHD *));
4957266Smuller static int fix_path __P((char *, int *, char *, int));
50*66890Sbostic static int fn_match __P((register char *, register char *, char **));
51*66890Sbostic static char * range_match __P((register char *, register int));
5257266Smuller #ifdef NET2_REGEX
5357266Smuller static int resub __P((regexp *, char *, char *, register char *));
5457266Smuller #else
5557266Smuller static int resub __P((regex_t *, regmatch_t *, char *, char *, char *));
5657266Smuller #endif
5757266Smuller 
5857266Smuller /*
5957266Smuller  * rep_add()
6057266Smuller  *	parses the -s replacement string; compiles the regular expression
6157266Smuller  *	and stores the compiled value and it's replacement string together in
6257266Smuller  *	replacement string list. Input to this function is of the form:
6357266Smuller  *		/old/new/pg
6457266Smuller  *	The first char in the string specifies the delimiter used by this
6557266Smuller  *	replacement string. "Old" is a regular expression in "ed" format which
6657266Smuller  *	is compiled by regcomp() and is applied to filenames. "new" is the
6757266Smuller  *	substitution string; p and g are options flags for printing and global
6857266Smuller  *	replacement (over the single filename)
6957266Smuller  * Return:
7057266Smuller  *	0 if a proper replacement string and regular expression was added to
7157266Smuller  *	the list of replacement patterns; -1 otherwise.
7257266Smuller  */
7357266Smuller 
7457266Smuller #if __STDC__
7557266Smuller int
rep_add(register char * str)7657266Smuller rep_add(register char *str)
7757266Smuller #else
7857266Smuller int
7957266Smuller rep_add(str)
8057266Smuller 	register char *str;
8157266Smuller #endif
8257266Smuller {
8357266Smuller 	register char *pt1;
8457266Smuller 	register char *pt2;
8557266Smuller 	register REPLACE *rep;
8657266Smuller #	ifndef NET2_REGEX
8757266Smuller 	register int res;
8857266Smuller 	char rebuf[BUFSIZ];
8957266Smuller #	endif
9057266Smuller 
9157266Smuller 	/*
9257266Smuller 	 * throw out the bad parameters
9357266Smuller 	 */
9457266Smuller 	if ((str == NULL) || (*str == '\0')) {
9557266Smuller 		warn(1, "Empty replacement string");
9657266Smuller 		return(-1);
9757266Smuller 	}
9857266Smuller 
9957266Smuller 	/*
10057266Smuller 	 * first character in the string specifies what the delimiter is for
10157266Smuller 	 * this expression
10257266Smuller 	 */
10357266Smuller 	if ((pt1 = strchr(str+1, *str)) == NULL) {
10457266Smuller 		warn(1, "Invalid replacement string %s", str);
10557266Smuller 		return(-1);
10657266Smuller 	}
10757266Smuller 
10857266Smuller 	/*
10957266Smuller 	 * allocate space for the node that handles this replacement pattern
11057266Smuller 	 * and split out the regular expression and try to compile it
11157266Smuller 	 */
11257266Smuller 	if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
11357266Smuller 		warn(1, "Unable to allocate memory for replacement string");
11457266Smuller 		return(-1);
11557266Smuller 	}
11657266Smuller 
11757266Smuller 	*pt1 = '\0';
11857266Smuller #	ifdef NET2_REGEX
11957266Smuller 	if ((rep->rcmp = regcomp(str+1)) == NULL) {
12057266Smuller #	else
12157266Smuller 	if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
12257266Smuller 		regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
12357266Smuller 		warn(1, "%s while compiling regular expression %s", rebuf, str);
12457266Smuller #	endif
12557266Smuller 		(void)free((char *)rep);
12657266Smuller 		return(-1);
12757266Smuller 	}
12857266Smuller 
12957266Smuller 	/*
13057266Smuller 	 * put the delimiter back in case we need an error message and
13157266Smuller 	 * locate the delimiter at the end of the replacement string
13257266Smuller 	 * we then point the node at the new substitution string
13357266Smuller 	 */
13457266Smuller 	*pt1++ = *str;
13557266Smuller 	if ((pt2 = strchr(pt1, *str)) == NULL) {
13657266Smuller #		ifdef NET2_REGEX
13757266Smuller 		(void)free((char *)rep->rcmp);
13857266Smuller #		else
13957266Smuller 		regfree(&(rep->rcmp));
14057266Smuller #		endif
14157266Smuller 		(void)free((char *)rep);
14257266Smuller 		warn(1, "Invalid replacement string %s", str);
14357266Smuller 		return(-1);
14457266Smuller 	}
14557266Smuller 
14657266Smuller 	*pt2 = '\0';
14757266Smuller 	rep->nstr = pt1;
14857266Smuller 	pt1 = pt2++;
14957266Smuller 	rep->flgs = 0;
15057266Smuller 
15157266Smuller 	/*
15257266Smuller 	 * set the options if any
15357266Smuller 	 */
15457266Smuller 	while (*pt2 != '\0') {
15557266Smuller 		switch(*pt2) {
15657266Smuller 		case 'g':
15757266Smuller 		case 'G':
15857266Smuller 			rep->flgs  |= GLOB;
15957266Smuller 			break;
16057266Smuller 		case 'p':
16157266Smuller 		case 'P':
16257266Smuller 			rep->flgs  |= PRNT;
16357266Smuller 			break;
16457266Smuller 		default:
16557266Smuller #			ifdef NET2_REGEX
16657266Smuller 			(void)free((char *)rep->rcmp);
16757266Smuller #			else
16857266Smuller 			regfree(&(rep->rcmp));
16957266Smuller #			endif
17057266Smuller 			(void)free((char *)rep);
17157266Smuller 			*pt1 = *str;
17257266Smuller 			warn(1, "Invalid replacement string option %s", str);
17357266Smuller 			return(-1);
17457266Smuller 		}
17557266Smuller 		++pt2;
17657266Smuller 	}
17757266Smuller 
17857266Smuller 	/*
17957266Smuller 	 * all done, link it in at the end
18057266Smuller 	 */
18157266Smuller 	rep->fow = NULL;
18257266Smuller 	if (rephead == NULL) {
18357266Smuller 		reptail = rephead = rep;
18457266Smuller 		return(0);
18557266Smuller 	}
18657266Smuller 	reptail->fow = rep;
18757266Smuller 	reptail = rep;
18857266Smuller 	return(0);
18957266Smuller }
19057266Smuller 
19157266Smuller /*
19257266Smuller  * pat_add()
19357266Smuller  *	add a pattern match to the pattern match list. Pattern matches are used
19457266Smuller  *	to select which archive members are extracted. (They appear as
19557266Smuller  *	arguments to pax in the list and read modes). If no patterns are
19657266Smuller  *	supplied to pax, all members in the archive will be selected (and the
19757266Smuller  *	pattern match list is empty).
19857266Smuller  * Return:
19957266Smuller  *	0 if the pattern was added to the list, -1 otherwise
20057266Smuller  */
20157266Smuller 
20257266Smuller #if __STDC__
20357266Smuller int
pat_add(char * str)20457266Smuller pat_add(char *str)
20557266Smuller #else
20657266Smuller int
20757266Smuller pat_add(str)
20857266Smuller 	char *str;
20957266Smuller #endif
21057266Smuller {
21157266Smuller 	register PATTERN *pt;
21257266Smuller 
21357266Smuller 	/*
21457266Smuller 	 * throw out the junk
21557266Smuller 	 */
21657266Smuller 	if ((str == NULL) || (*str == '\0')) {
21757266Smuller 		warn(1, "Empty pattern string");
21857266Smuller 		return(-1);
21957266Smuller 	}
22057266Smuller 
22157266Smuller 	/*
22257266Smuller 	 * allocate space for the pattern and store the pattern. the pattern is
22357266Smuller 	 * part of argv so do not bother to copy it, just point at it. Add the
22457266Smuller 	 * node to the end of the pattern list
22557266Smuller 	 */
22657266Smuller 	if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
22757266Smuller 		warn(1, "Unable to allocate memory for pattern string");
22857266Smuller 		return(-1);
22957266Smuller 	}
23057266Smuller 
23157266Smuller 	pt->pstr = str;
232*66890Sbostic 	pt->pend = NULL;
23357266Smuller 	pt->plen = strlen(str);
23457266Smuller 	pt->fow = NULL;
23557266Smuller 	pt->flgs = 0;
23657266Smuller 	if (pathead == NULL) {
23757266Smuller 		pattail = pathead = pt;
23857266Smuller 		return(0);
23957266Smuller 	}
24057266Smuller 	pattail->fow = pt;
24157266Smuller 	pattail = pt;
24257266Smuller 	return(0);
24357266Smuller }
24457266Smuller 
24557266Smuller /*
24657266Smuller  * pat_chk()
24757266Smuller  *	complain if any the user supplied pattern did not result in a match to
24857266Smuller  *	a selected archive member.
24957266Smuller  */
25057266Smuller 
25157266Smuller #if __STDC__
25257266Smuller void
pat_chk(void)25357266Smuller pat_chk(void)
25457266Smuller #else
25557266Smuller void
25657266Smuller pat_chk()
25757266Smuller #endif
25857266Smuller {
25957266Smuller 	register PATTERN *pt;
26057266Smuller 	register int wban = 0;
26157266Smuller 
26257266Smuller 	/*
26357266Smuller 	 * walk down the list checking the flags to make sure MTCH was set,
26457266Smuller 	 * if not complain
26557266Smuller 	 */
26657266Smuller 	for (pt = pathead; pt != NULL; pt = pt->fow) {
26757266Smuller 		if (pt->flgs & MTCH)
26857266Smuller 			continue;
26957266Smuller 		if (!wban) {
27057266Smuller 			warn(1, "WARNING! These patterns were not matched:");
27157266Smuller 			++wban;
27257266Smuller 		}
27357266Smuller 		(void)fprintf(stderr, "%s\n", pt->pstr);
27457266Smuller 	}
27557266Smuller }
27657266Smuller 
27757266Smuller /*
27857266Smuller  * pat_sel()
27957266Smuller  *	the archive member which matches a pattern was selected. Mark the
28057266Smuller  *	pattern as having selected an archive member. arcn->pat points at the
28157266Smuller  *	pattern that was matched. arcn->pat is set in pat_match()
28257266Smuller  *
28357266Smuller  *	NOTE: When the -c option is used, we are called when there was no match
28457266Smuller  *	by pat_match() (that means we did match before the inverted sense of
28557266Smuller  *	the logic). Now this seems really strange at first, but with -c  we
28657266Smuller  *	need to keep track of those patterns that cause a archive member to NOT
28757266Smuller  *	be selected (it found an archive member with a specified pattern)
28857266Smuller  * Return:
28957266Smuller  *	0 if the pattern pointed at by arcn->pat was tagged as creating a
29057266Smuller  *	match, -1 otherwise.
29157266Smuller  */
29257266Smuller 
29357266Smuller #if __STDC__
29457266Smuller int
pat_sel(register ARCHD * arcn)29557266Smuller pat_sel(register ARCHD *arcn)
29657266Smuller #else
29757266Smuller int
29857266Smuller pat_sel(arcn)
29957266Smuller 	register ARCHD *arcn;
30057266Smuller #endif
30157266Smuller {
30257266Smuller 	register PATTERN *pt;
30357266Smuller 	register PATTERN **ppt;
30457266Smuller 	register int len;
30557266Smuller 
30657266Smuller 	/*
30757266Smuller 	 * if no patterns just return
30857266Smuller 	 */
30957266Smuller 	if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
31057266Smuller 		return(0);
31157266Smuller 
31257266Smuller 	/*
31357266Smuller 	 * when we are NOT limited to a single match per pattern mark the
314*66890Sbostic 	 * pattern and return
31557266Smuller 	 */
31657266Smuller 	if (!nflag) {
31757266Smuller 		pt->flgs |= MTCH;
318*66890Sbostic 		return(0);
31957266Smuller 	}
32057266Smuller 
32157266Smuller 	/*
32257266Smuller 	 * we reach this point only when we allow a single selected match per
323*66890Sbostic 	 * pattern, if the pattern matches a directory and we do not have -d
324*66890Sbostic 	 * (dflag) we are done with this pattern. We may also be handed a file
325*66890Sbostic 	 * in the subtree of a directory. in that case when we are operating
326*66890Sbostic 	 * with -d, this pattern was already selected and we are done
32757266Smuller 	 */
32857266Smuller 	if (pt->flgs & DIR_MTCH)
32957266Smuller 		return(0);
33057266Smuller 
331*66890Sbostic 	if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {
33257266Smuller 		/*
333*66890Sbostic 		 * ok we matched a directory and we are allowing
334*66890Sbostic 		 * subtree matches but because of the -n only its children will
335*66890Sbostic 		 * match. This is tagged as a DIR_MTCH type.
336*66890Sbostic 		 * WATCH IT, the code assumes that pt->pend points
337*66890Sbostic 		 * into arcn->name and arcn->name has not been modified.
338*66890Sbostic 		 * If not we will have a big mess. Yup this is another kludge
339*66890Sbostic 		 */
340*66890Sbostic 
341*66890Sbostic 		/*
342*66890Sbostic 		 * if this was a prefix match, remove trailing part of path
343*66890Sbostic 		 * so we can copy it. Future matches will be exact prefix match
344*66890Sbostic 		 */
345*66890Sbostic 		if (pt->pend != NULL)
346*66890Sbostic 			*pt->pend = '\0';
347*66890Sbostic 
34857266Smuller 		if ((pt->pstr = strdup(arcn->name)) == NULL) {
34957266Smuller 			warn(1, "Pattern select out of memory");
350*66890Sbostic 			if (pt->pend != NULL)
351*66890Sbostic 				*pt->pend = '/';
352*66890Sbostic 			pt->pend = NULL;
35357266Smuller 			return(-1);
35457266Smuller 		}
355*66890Sbostic 
356*66890Sbostic 		/*
357*66890Sbostic 		 * put the trailing / back in the source string
358*66890Sbostic 		 */
359*66890Sbostic 		if (pt->pend != NULL) {
360*66890Sbostic 			*pt->pend = '/';
361*66890Sbostic 			pt->pend = NULL;
362*66890Sbostic 		}
36357266Smuller 		pt->plen = strlen(pt->pstr);
36457266Smuller 
36557266Smuller 		/*
36657266Smuller 		 * strip off any trailing /, this should really never happen
36757266Smuller 		 */
36857266Smuller 		len = pt->plen - 1;
36957266Smuller 		if (*(pt->pstr + len) == '/') {
37057266Smuller 			*(pt->pstr + len) = '\0';
37157266Smuller 			pt->plen = len;
37257266Smuller 		}
373*66890Sbostic 		pt->flgs = DIR_MTCH | MTCH;
374*66890Sbostic 		arcn->pat = pt;
37557266Smuller 		return(0);
37657266Smuller 	}
37757266Smuller 
37857266Smuller 	/*
379*66890Sbostic 	 * we are then done with this pattern, so we delete it from the list
380*66890Sbostic 	 * because it can never be used for another match.
38157266Smuller 	 * Seems kind of strange to do for a -c, but the pax spec is really
38257266Smuller 	 * vague on the interaction of -c -n and -d. We assume that when -c
38357266Smuller 	 * and the pattern rejects a member (i.e. it matched it) it is done.
38457266Smuller 	 * In effect we place the order of the flags as having -c last.
38557266Smuller 	 */
38657266Smuller 	pt = pathead;
38757266Smuller 	ppt = &pathead;
38857266Smuller 	while ((pt != NULL) && (pt != arcn->pat)) {
38957266Smuller 		ppt = &(pt->fow);
39057266Smuller 		pt = pt->fow;
39157266Smuller 	}
39257266Smuller 
39357266Smuller 	if (pt == NULL) {
39457266Smuller 		/*
39557266Smuller 		 * should never happen....
39657266Smuller 		 */
39757266Smuller 		warn(1, "Pattern list inconsistant");
39857266Smuller 		return(-1);
39957266Smuller 	}
40057266Smuller 	*ppt = pt->fow;
40157266Smuller 	(void)free((char *)pt);
40257266Smuller 	arcn->pat = NULL;
40357266Smuller 	return(0);
40457266Smuller }
40557266Smuller 
40657266Smuller /*
40757266Smuller  * pat_match()
40857266Smuller  *	see if this archive member matches any supplied pattern, if a match
40957266Smuller  *	is found, arcn->pat is set to point at the potential pattern. Later if
41057266Smuller  *	this archive member is "selected" we process and mark the pattern as
41157266Smuller  *	one which matched a selected archive member (see pat_sel())
41257266Smuller  * Return:
41357266Smuller  *	0 if this archive member should be processed, 1 if it should be
41457266Smuller  *	skipped and -1 if we are done with all patterns (and pax should quit
41557266Smuller  *	looking for more members)
41657266Smuller  */
41757266Smuller 
41857266Smuller #if __STDC__
41957266Smuller int
pat_match(register ARCHD * arcn)42057266Smuller pat_match(register ARCHD *arcn)
42157266Smuller #else
42257266Smuller int
42357266Smuller pat_match(arcn)
42457266Smuller 	register ARCHD *arcn;
42557266Smuller #endif
42657266Smuller {
42757266Smuller 	register PATTERN *pt;
42857266Smuller 
42957266Smuller 	arcn->pat = NULL;
43057266Smuller 
43157266Smuller 	/*
43257266Smuller 	 * if there are no more patterns and we have -n (and not -c) we are
43357266Smuller 	 * done. otherwise with no patterns to match, matches all
43457266Smuller 	 */
43557266Smuller 	if (pathead == NULL) {
43657266Smuller 		if (nflag && !cflag)
43757266Smuller 			return(-1);
43857266Smuller 		return(0);
43957266Smuller 	}
44057266Smuller 
44157266Smuller 	/*
44257266Smuller 	 * have to search down the list one at a time looking for a match.
44357266Smuller 	 */
44457266Smuller 	pt = pathead;
44557266Smuller 	while (pt != NULL) {
44657266Smuller 		/*
44757266Smuller 		 * check for a file name match unless we have DIR_MTCH set in
44857266Smuller 		 * this pattern then we want a prefix match
44957266Smuller 		 */
45057266Smuller 		if (pt->flgs & DIR_MTCH) {
45157266Smuller 			/*
45257266Smuller 			 * this pattern was matched before to a directory
45357266Smuller 			 * as we must have -n set for this (but not -d). We can
45457266Smuller 			 * only match CHILDREN of that directory so we must use
455*66890Sbostic 			 * an exact prefix match (no wildcards).
45657266Smuller 			 */
457*66890Sbostic 			if ((arcn->name[pt->plen] == '/') &&
458*66890Sbostic 			    (strncmp(pt->pstr, arcn->name, pt->plen) == 0))
45957266Smuller 				break;
460*66890Sbostic 		} else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)
46157266Smuller 			break;
46257266Smuller 		pt = pt->fow;
46357266Smuller 	}
46457266Smuller 
46557266Smuller 	/*
46657266Smuller 	 * return the result, remember that cflag (-c) inverts the sense of a
46757266Smuller 	 * match
46857266Smuller 	 */
46957266Smuller 	if (pt == NULL)
47057266Smuller 		return(cflag ? 0 : 1);
47157266Smuller 
47257266Smuller 	/*
47357266Smuller 	 * we had a match, now when we invert the sense (-c) we reject this
47457266Smuller 	 * member. However we have to tag the pattern a being successful, (in a
47557266Smuller 	 * match, not in selecting a archive member) so we call pat_sel() here.
47657266Smuller 	 */
47757266Smuller 	arcn->pat = pt;
47857266Smuller 	if (!cflag)
47957266Smuller 		return(0);
48057266Smuller 
48157266Smuller 	if (pat_sel(arcn) < 0)
48257266Smuller 		return(-1);
48357266Smuller 	arcn->pat = NULL;
48457266Smuller 	return(1);
48557266Smuller }
48657266Smuller 
48757266Smuller /*
488*66890Sbostic  * fn_match()
489*66890Sbostic  * Return:
490*66890Sbostic  *	0 if this archive member should be processed, 1 if it should be
491*66890Sbostic  *	skipped and -1 if we are done with all patterns (and pax should quit
492*66890Sbostic  *	looking for more members)
493*66890Sbostic  *	Note: *pend may be changed to show where the prefix ends.
494*66890Sbostic  */
495*66890Sbostic 
496*66890Sbostic #if __STDC__
497*66890Sbostic static int
fn_match(register char * pattern,register char * string,char ** pend)498*66890Sbostic fn_match(register char *pattern, register char *string, char **pend)
499*66890Sbostic #else
500*66890Sbostic static int
501*66890Sbostic fn_match(pattern, string, pend)
502*66890Sbostic 	register char *pattern;
503*66890Sbostic 	register char *string;
504*66890Sbostic 	char **pend;
505*66890Sbostic #endif
506*66890Sbostic {
507*66890Sbostic 	register char c;
508*66890Sbostic 	char test;
509*66890Sbostic 
510*66890Sbostic 	*pend = NULL;
511*66890Sbostic 	for (;;) {
512*66890Sbostic 		switch (c = *pattern++) {
513*66890Sbostic 		case '\0':
514*66890Sbostic 			/*
515*66890Sbostic 			 * Ok we found an exact match
516*66890Sbostic 			 */
517*66890Sbostic 			if (*string == '\0')
518*66890Sbostic 				return(0);
519*66890Sbostic 
520*66890Sbostic 			/*
521*66890Sbostic 			 * Check if it is a prefix match
522*66890Sbostic 			 */
523*66890Sbostic 			if ((dflag == 1) || (*string != '/'))
524*66890Sbostic 				return(-1);
525*66890Sbostic 
526*66890Sbostic 			/*
527*66890Sbostic 			 * It is a prefix match, remember where the trailing
528*66890Sbostic 			 * / is located
529*66890Sbostic 			 */
530*66890Sbostic 			*pend = string;
531*66890Sbostic 			return(0);
532*66890Sbostic 		case '?':
533*66890Sbostic 			if ((test = *string++) == '\0')
534*66890Sbostic 				return (-1);
535*66890Sbostic 			break;
536*66890Sbostic 		case '*':
537*66890Sbostic 			c = *pattern;
538*66890Sbostic 			/*
539*66890Sbostic 			 * Collapse multiple *'s.
540*66890Sbostic 			 */
541*66890Sbostic 			while (c == '*')
542*66890Sbostic 				c = *++pattern;
543*66890Sbostic 
544*66890Sbostic 			/*
545*66890Sbostic 			 * Optimized hack for pattern with a * at the end
546*66890Sbostic 			 */
547*66890Sbostic 			if (c == '\0')
548*66890Sbostic 				return (0);
549*66890Sbostic 
550*66890Sbostic 			/*
551*66890Sbostic 			 * General case, use recursion.
552*66890Sbostic 			 */
553*66890Sbostic 			while ((test = *string) != '\0') {
554*66890Sbostic 				if (!fn_match(pattern, string, pend))
555*66890Sbostic 					return (0);
556*66890Sbostic 				++string;
557*66890Sbostic 			}
558*66890Sbostic 			return (-1);
559*66890Sbostic 		case '[':
560*66890Sbostic 			/*
561*66890Sbostic 			 * range match
562*66890Sbostic 			 */
563*66890Sbostic 			if (((test = *string++) == '\0') ||
564*66890Sbostic 			    ((pattern = range_match(pattern, test)) == NULL))
565*66890Sbostic 				return (-1);
566*66890Sbostic 			break;
567*66890Sbostic 		case '\\':
568*66890Sbostic 		default:
569*66890Sbostic 			if (c != *string++)
570*66890Sbostic 				return (-1);
571*66890Sbostic 			break;
572*66890Sbostic 		}
573*66890Sbostic 	}
574*66890Sbostic 	/* NOTREACHED */
575*66890Sbostic }
576*66890Sbostic 
577*66890Sbostic #ifdef __STDC__
578*66890Sbostic static char *
range_match(register char * pattern,register int test)579*66890Sbostic range_match(register char *pattern, register int test)
580*66890Sbostic #else
581*66890Sbostic static char *
582*66890Sbostic range_match(pattern, test)
583*66890Sbostic 	register char *pattern;
584*66890Sbostic 	register int test;
585*66890Sbostic #endif
586*66890Sbostic {
587*66890Sbostic 	register char c;
588*66890Sbostic 	register char c2;
589*66890Sbostic 	int negate;
590*66890Sbostic 	int ok = 0;
591*66890Sbostic 
592*66890Sbostic 	if (negate = (*pattern == '!'))
593*66890Sbostic 		++pattern;
594*66890Sbostic 
595*66890Sbostic 	while ((c = *pattern++) != ']') {
596*66890Sbostic 		/*
597*66890Sbostic 		 * Illegal pattern
598*66890Sbostic 		 */
599*66890Sbostic 		if (c == '\0')
600*66890Sbostic 			return (NULL);
601*66890Sbostic 
602*66890Sbostic 		if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') &&
603*66890Sbostic 		    (c2 != ']')) {
604*66890Sbostic 			if ((c <= test) && (test <= c2))
605*66890Sbostic 				ok = 1;
606*66890Sbostic 			pattern += 2;
607*66890Sbostic 		} else if (c == test)
608*66890Sbostic 			ok = 1;
609*66890Sbostic 	}
610*66890Sbostic 	return (ok == negate ? NULL : pattern);
611*66890Sbostic }
612*66890Sbostic 
613*66890Sbostic /*
61457266Smuller  * mod_name()
61557266Smuller  *	modify a selected file name. first attempt to apply replacement string
61657266Smuller  *	expressions, then apply interactive file rename. We apply replacement
61757266Smuller  *	string expressions to both filenames and file links (if we didn't the
61857266Smuller  *	links would point to the wrong place, and we could never be able to
61957266Smuller  *	move an archive that has a file link in it). When we rename files
62057266Smuller  *	interactively, we store that mapping (old name to user input name) so
62157266Smuller  *	if we spot any file links to the old file name in the future, we will
62257266Smuller  *	know exactly how to fix the file link.
62357266Smuller  * Return:
62457266Smuller  *	0 continue to  process file, 1 skip this file, -1 pax is finished
62557266Smuller  */
62657266Smuller 
62757266Smuller #if __STDC__
62857266Smuller int
mod_name(register ARCHD * arcn)62957266Smuller mod_name(register ARCHD *arcn)
63057266Smuller #else
63157266Smuller int
63257266Smuller mod_name(arcn)
63357266Smuller 	register ARCHD *arcn;
63457266Smuller #endif
63557266Smuller {
63657266Smuller 	register int res = 0;
63757266Smuller 
63857266Smuller 	/*
63957266Smuller 	 * IMPORTANT: We have a problem. what do we do with symlinks?
64057266Smuller 	 * Modifying a hard link name makes sense, as we know the file it
64157266Smuller 	 * points at should have been seen already in the archive (and if it
64257266Smuller 	 * wasn't seen because of a read error or a bad archive, we lose
64357266Smuller 	 * anyway). But there are no such requirements for symlinks. On one
64457266Smuller 	 * hand the symlink that refers to a file in the archive will have to
64557266Smuller 	 * be modified to so it will still work at its new location in the
64657266Smuller 	 * file system. On the other hand a symlink that points elsewhere (and
64757266Smuller 	 * should continue to do so) should not be modified. There is clearly
64857266Smuller 	 * no perfect solution here. So we handle them like hardlinks. Clearly
64957266Smuller 	 * a replacement made by the interactive rename mapping is very likely
65057266Smuller 	 * to be correct since it applies to a single file and is an exact
65157266Smuller 	 * match. The regular expression replacements are a little harder to
65257266Smuller 	 * justify though. We claim that the symlink name is only likely
65357266Smuller 	 * to be replaced when it points within the file tree being moved and
65457266Smuller 	 * in that case it should be modified. what we really need to do is to
65557266Smuller 	 * call an oracle here. :)
65657266Smuller 	 */
65757266Smuller 	if (rephead != NULL) {
65857266Smuller 		/*
65957266Smuller 		 * we have replacement strings, modify the name and the link
66057266Smuller 		 * name if any.
66157266Smuller 		 */
66257266Smuller 		if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0)
66357266Smuller 			return(res);
66457266Smuller 
66557266Smuller 		if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
66657266Smuller 		    (arcn->type == PAX_HRG)) &&
66757266Smuller 		    ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0))
66857266Smuller 			return(res);
66957266Smuller 	}
67057266Smuller 
67157266Smuller 	if (iflag) {
67257266Smuller 		/*
67357266Smuller 		 * perform interactive file rename, then map the link if any
67457266Smuller 		 */
67557266Smuller 		if ((res = tty_rename(arcn)) != 0)
67657266Smuller 			return(res);
67757266Smuller 		if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
67857266Smuller 		    (arcn->type == PAX_HRG))
67957266Smuller 			sub_name(arcn->ln_name, &(arcn->ln_nlen));
68057266Smuller 	}
68157266Smuller 	return(res);
68257266Smuller }
68357266Smuller 
68457266Smuller /*
68557266Smuller  * tty_rename()
68657266Smuller  *	Prompt the user for a replacement file name. A "." keeps the old name,
68757266Smuller  *	a empty line skips the file, and an EOF on reading the tty, will cause
68857266Smuller  *	pax to stop processing and exit. Otherwise the file name input, replaces
68957266Smuller  *	the old one.
69057266Smuller  * Return:
69157266Smuller  *	0 process this file, 1 skip this file, -1 we need to exit pax
69257266Smuller  */
69357266Smuller 
69457266Smuller #if __STDC__
69557266Smuller static int
tty_rename(register ARCHD * arcn)69657266Smuller tty_rename(register ARCHD *arcn)
69757266Smuller #else
69857266Smuller static int
69957266Smuller tty_rename(arcn)
70057266Smuller 	register ARCHD *arcn;
70157266Smuller #endif
70257266Smuller {
70357266Smuller 	char tmpname[PAXPATHLEN+2];
70457266Smuller 	int res;
70557266Smuller 
70657266Smuller 	/*
70757266Smuller 	 * prompt user for the replacement name for a file, keep trying until
70857266Smuller 	 * we get some reasonable input. Archives may have more than one file
70957266Smuller 	 * on them with the same name (from updates etc). We print verbose info
71057266Smuller 	 * on the file so the user knows what is up.
71157266Smuller 	 */
712*66890Sbostic 	tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0);
71357266Smuller 
71457266Smuller 	for (;;) {
71557266Smuller 		ls_tty(arcn);
71657266Smuller 		tty_prnt("Input new name, or a \".\" to keep the old name, ");
71757266Smuller 		tty_prnt("or a \"return\" to skip this file.\n");
71857266Smuller 		tty_prnt("Input > ");
71957266Smuller 		if (tty_read(tmpname, sizeof(tmpname)) < 0)
72057266Smuller 			return(-1);
72157266Smuller 		if (strcmp(tmpname, "..") == 0) {
72257266Smuller 			tty_prnt("Try again, illegal file name: ..\n");
72357266Smuller 			continue;
72457266Smuller 		}
72557266Smuller 		if (strlen(tmpname) > PAXPATHLEN) {
72657266Smuller 			tty_prnt("Try again, file name too long\n");
72757266Smuller 			continue;
72857266Smuller 		}
72957266Smuller 		break;
73057266Smuller 	}
73157266Smuller 
73257266Smuller 	/*
73357266Smuller 	 * empty file name, skips this file. a "." leaves it alone
73457266Smuller 	 */
73557266Smuller 	if (tmpname[0] == '\0') {
73657266Smuller 		tty_prnt("Skipping file.\n");
73757266Smuller 		return(1);
73857266Smuller 	}
73957266Smuller 	if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
74057266Smuller 		tty_prnt("Processing continues, name unchanged.\n");
74157266Smuller 		return(0);
74257266Smuller 	}
74357266Smuller 
74457266Smuller 	/*
74557266Smuller 	 * ok the name changed. We may run into links that point at this
74657266Smuller 	 * file later. we have to remember where the user sent the file
74757266Smuller 	 * in order to repair any links.
74857266Smuller 	 */
74957266Smuller 	tty_prnt("Processing continues, name changed to: %s\n", tmpname);
75057266Smuller 	res = add_name(arcn->name, arcn->nlen, tmpname);
75157266Smuller 	arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1);
75257266Smuller 	if (res < 0)
75357266Smuller 		return(-1);
75457266Smuller 	return(0);
75557266Smuller }
75657266Smuller 
75757266Smuller /*
75857266Smuller  * set_dest()
75957266Smuller  *	fix up the file name and the link name (if any) so this file will land
76057266Smuller  *	in the destination directory (used during copy() -rw).
76157266Smuller  * Return:
76257266Smuller  *	0 if ok, -1 if failure (name too long)
76357266Smuller  */
76457266Smuller 
76557266Smuller #if __STDC__
76657266Smuller int
set_dest(register ARCHD * arcn,char * dest_dir,int dir_len)76757266Smuller set_dest(register ARCHD *arcn, char *dest_dir, int dir_len)
76857266Smuller #else
76957266Smuller int
77057266Smuller set_dest(arcn, dest_dir, dir_len)
77157266Smuller 	register ARCHD *arcn;
77257266Smuller 	char *dest_dir;
77357266Smuller 	int dir_len;
77457266Smuller #endif
77557266Smuller {
77657266Smuller 	if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
77757266Smuller 		return(-1);
77857266Smuller 
77957600Smuller 	/*
78057600Smuller 	 * It is really hard to deal with symlinks here, we cannot be sure
78157600Smuller 	 * if the name they point was moved (or will be moved). It is best to
78257600Smuller 	 * leave them alone.
78357600Smuller 	 */
78457600Smuller 	if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG))
78557266Smuller 		return(0);
78657266Smuller 
78757266Smuller 	if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
78857266Smuller 		return(-1);
78957266Smuller 	return(0);
79057266Smuller }
79157266Smuller 
79257266Smuller /*
79357266Smuller  * fix_path
79457266Smuller  *	concatenate dir_name and or_name and store the result in or_name (if
79557266Smuller  *	it fits). This is one ugly function.
79657266Smuller  * Return:
79757266Smuller  *	0 if ok, -1 if the final name is too long
79857266Smuller  */
79957266Smuller 
80057266Smuller #if __STDC__
80157266Smuller static int
fix_path(char * or_name,int * or_len,char * dir_name,int dir_len)80257266Smuller fix_path( char *or_name, int *or_len, char *dir_name, int dir_len)
80357266Smuller #else
80457266Smuller static int
80557266Smuller fix_path(or_name, or_len, dir_name, dir_len)
80657266Smuller 	char *or_name;
80757266Smuller 	int *or_len;
80857266Smuller 	char *dir_name;
80957266Smuller 	int dir_len;
81057266Smuller #endif
81157266Smuller {
81257266Smuller 	register char *src;
81357266Smuller 	register char *dest;
81457266Smuller 	register char *start;
81557266Smuller 	int len;
81657266Smuller 
81757266Smuller 	/*
81857266Smuller 	 * we shift the or_name to the right enough to tack in the dir_name
81957266Smuller 	 * at the front. We make sure we have enough space for it all before
82057266Smuller 	 * we start. since dest always ends in a slash, we skip of or_name
82157266Smuller 	 * if it also starts with one.
82257266Smuller 	 */
82357266Smuller 	start = or_name;
82457266Smuller 	src = start + *or_len;
82557266Smuller 	dest = src + dir_len;
82657266Smuller 	if (*start == '/') {
82757266Smuller 		++start;
82857266Smuller 		--dest;
82957266Smuller 	}
83057266Smuller 	if ((len = dest - or_name) > PAXPATHLEN) {
83157266Smuller 		warn(1, "File name %s/%s, too long", dir_name, start);
83257266Smuller 		return(-1);
83357266Smuller 	}
83457266Smuller 	*or_len = len;
83557266Smuller 
83657266Smuller 	/*
83757266Smuller 	 * enough space, shift
83857266Smuller 	 */
83957266Smuller 	while (src >= start)
84057266Smuller 		*dest-- = *src--;
84157266Smuller 	src = dir_name + dir_len - 1;
84257266Smuller 
84357266Smuller 	/*
84457266Smuller 	 * splice in the destination directory name
84557266Smuller 	 */
84657266Smuller 	while (src >= dir_name)
84757266Smuller 		*dest-- = *src--;
84857266Smuller 
84957266Smuller 	*(or_name + len) = '\0';
85057266Smuller 	return(0);
85157266Smuller }
85257266Smuller 
85357266Smuller /*
85457266Smuller  * rep_name()
85557266Smuller  *	walk down the list of replacement strings applying each one in order.
85657266Smuller  *	when we find one with a successful substitution, we modify the name
85757266Smuller  *	as specified. if required, we print the results. if the resulting name
85857266Smuller  *	is empty, we will skip this archive member. We use the regexp(3)
85957266Smuller  *	routines (regexp() ought to win a prize as having the most cryptic
86057266Smuller  *	library function manual page).
86157266Smuller  *	--Parameters--
86257266Smuller  *	name is the file name we are going to apply the regular expressions to
86357266Smuller  *	(and may be modified)
86457266Smuller  *	nlen is the length of this name (and is modified to hold the length of
86557266Smuller  *	the final string).
86657266Smuller  *	prnt is a flag that says whether to print the final result.
86757266Smuller  * Return:
86857266Smuller  *	0 if substitution was successful, 1 if we are to skip the file (the name
86957266Smuller  *	ended up empty)
87057266Smuller  */
87157266Smuller 
87257266Smuller #if __STDC__
87357266Smuller static int
rep_name(char * name,int * nlen,int prnt)87457266Smuller rep_name(char *name, int *nlen, int prnt)
87557266Smuller #else
87657266Smuller static int
87757266Smuller rep_name(name, nlen, prnt)
87857266Smuller 	char *name;
87957266Smuller 	int *nlen;
88057266Smuller 	int prnt;
88157266Smuller #endif
88257266Smuller {
88357266Smuller 	register REPLACE *pt;
88457266Smuller 	register char *inpt;
88557266Smuller 	register char *outpt;
88657266Smuller 	register char *endpt;
88757266Smuller 	register char *rpt;
88857266Smuller 	register int found = 0;
88957266Smuller 	register int res;
89057266Smuller #	ifndef NET2_REGEX
89157266Smuller 	regmatch_t pm[MAXSUBEXP];
89257266Smuller #	endif
89357266Smuller 	char nname[PAXPATHLEN+1];	/* final result of all replacements */
89457266Smuller 	char buf1[PAXPATHLEN+1];	/* where we work on the name */
89557266Smuller 
89657266Smuller 	/*
89757266Smuller 	 * copy the name into buf1, where we will work on it. We need to keep
89857266Smuller 	 * the orig string around so we can print out the result of the final
89957266Smuller 	 * replacement. We build up the final result in nname. inpt points at
90057266Smuller 	 * the string we apply the regular expression to. prnt is used to
90157266Smuller 	 * suppress printing when we handle replacements on the link field
90257266Smuller 	 * (the user already saw that substitution go by)
90357266Smuller 	 */
90457266Smuller 	pt = rephead;
90557266Smuller 	(void)strcpy(buf1, name);
90657266Smuller 	inpt = buf1;
90757266Smuller 	outpt = nname;
90857266Smuller 	endpt = outpt + PAXPATHLEN;
90957266Smuller 
91057266Smuller 	/*
91157266Smuller 	 * try each replacement string in order
91257266Smuller 	 */
91357266Smuller 	while (pt != NULL) {
91457266Smuller 		do {
91557266Smuller 			/*
91657266Smuller 			 * check for a successful substitution, if not go to
91757266Smuller 			 * the next pattern, or cleanup if we were global
91857266Smuller 			 */
91957266Smuller #			ifdef NET2_REGEX
92057266Smuller 			if (regexec(pt->rcmp, inpt) == 0)
92157266Smuller #			else
92257266Smuller 			if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
92357266Smuller #			endif
92457266Smuller 				break;
92557266Smuller 
92657266Smuller 			/*
92757266Smuller 			 * ok we found one. We have three parts, the prefix
92857266Smuller 			 * which did not match, the section that did and the
92957266Smuller 			 * tail (that also did not match). Copy the prefix to
93057266Smuller 			 * the final output buffer (watching to make sure we
93157266Smuller 			 * do not create a string too long).
93257266Smuller 			 */
93357266Smuller 			found = 1;
93457266Smuller #			ifdef NET2_REGEX
93557266Smuller 			rpt = pt->rcmp->startp[0];
93657266Smuller #			else
93757266Smuller 			rpt = inpt + pm[0].rm_so;
93857266Smuller #			endif
93957266Smuller 
94057266Smuller 			while ((inpt < rpt) && (outpt < endpt))
94157266Smuller 				*outpt++ = *inpt++;
94257266Smuller 			if (outpt == endpt)
94357266Smuller 				break;
94457266Smuller 
94557266Smuller 			/*
94657266Smuller 			 * for the second part (which matched the regular
94757266Smuller 			 * expression) apply the substitution using the
94857266Smuller 			 * replacement string and place it the prefix in the
94957266Smuller 			 * final output. If we have problems, skip it.
95057266Smuller 			 */
95157266Smuller #			ifdef NET2_REGEX
95257266Smuller 			if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) {
95357266Smuller #			else
95457266Smuller 			if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt))
95557266Smuller 			    < 0) {
95657266Smuller #			endif
95757266Smuller 				if (prnt)
95857266Smuller 					warn(1, "Replacement name error %s",
95957266Smuller 					    name);
96057266Smuller 				return(1);
96157266Smuller 			}
96257266Smuller 			outpt += res;
96357266Smuller 
96457266Smuller 			/*
96557266Smuller 			 * we set up to look again starting at the first
96657266Smuller 			 * character in the tail (of the input string right
96757266Smuller 			 * after the last character matched by the regular
96857266Smuller 			 * expression (inpt always points at the first char in
96957266Smuller 			 * the string to process). If we are not doing a global
97057266Smuller 			 * substitution, we will use inpt to copy the tail to
97157266Smuller 			 * the final result. Make sure we do not overrun the
97257266Smuller 			 * output buffer
97357266Smuller 			 */
97457266Smuller #			ifdef NET2_REGEX
97557266Smuller 			inpt = pt->rcmp->endp[0];
97657266Smuller #			else
97757266Smuller 			inpt += pm[0].rm_eo;
97857266Smuller #			endif
97957266Smuller 
98057266Smuller 			if ((outpt == endpt) || (*inpt == '\0'))
98157266Smuller 				break;
98257266Smuller 
98357266Smuller 			/*
98457266Smuller 			 * if the user wants global we keep trying to
98557266Smuller 			 * substitute until it fails, then we are done.
98657266Smuller 			 */
98757266Smuller 		} while (pt->flgs & GLOB);
98857266Smuller 
98957266Smuller 		if (found)
99057266Smuller 			break;
99157266Smuller 
99257266Smuller 		/*
99357266Smuller 		 * a successful substitution did NOT occur, try the next one
99457266Smuller 		 */
99557266Smuller 		pt = pt->fow;
99657266Smuller 	}
99757266Smuller 
99857266Smuller 	if (found) {
99957266Smuller 		/*
100057266Smuller 		 * we had a substitution, copy the last tail piece (if there is
100157266Smuller 		 * room) to the final result
100257266Smuller 		 */
100357266Smuller 		while ((outpt < endpt) && (*inpt != '\0'))
100457266Smuller 			*outpt++ = *inpt++;
100557266Smuller 
100657266Smuller 		*outpt = '\0';
100757266Smuller 		if ((outpt == endpt) && (*inpt != '\0')) {
100857266Smuller 			if (prnt)
100957266Smuller 				warn(1,"Replacement name too long %s >> %s",
101057266Smuller 				    name, nname);
101157266Smuller 			return(1);
101257266Smuller 		}
101357266Smuller 
101457266Smuller 		/*
101557266Smuller 		 * inform the user of the result if wanted
101657266Smuller 		 */
101757266Smuller 		if (prnt && (pt->flgs & PRNT)) {
101857266Smuller 			if (*nname == '\0')
101957266Smuller 				(void)fprintf(stderr,"%s >> <empty string>\n",
102057266Smuller 				    name);
102157266Smuller 			else
102257266Smuller 				(void)fprintf(stderr,"%s >> %s\n", name, nname);
102357266Smuller 		}
102457266Smuller 
102557266Smuller 		/*
102657266Smuller 		 * if empty inform the caller this file is to be skipped
102757266Smuller 		 * otherwise copy the new name over the orig name and return
102857266Smuller 		 */
102957266Smuller 		if (*nname == '\0')
103057266Smuller 			return(1);
103157266Smuller 		*nlen = l_strncpy(name, nname, PAXPATHLEN + 1);
103257266Smuller 	}
103357266Smuller 	return(0);
103457266Smuller }
103557266Smuller 
103657266Smuller #ifdef NET2_REGEX
103757266Smuller /*
103857266Smuller  * resub()
103957266Smuller  *	apply the replacement to the matched expression. expand out the old
104057266Smuller  * 	style ed(1) subexpression expansion.
104157266Smuller  * Return:
104257266Smuller  *	-1 if error, or the number of characters added to the destination.
104357266Smuller  */
104457266Smuller 
104557266Smuller #if __STDC__
104657266Smuller static int
resub(regexp * prog,char * src,char * dest,register char * destend)104757266Smuller resub(regexp *prog, char *src, char *dest, register char *destend)
104857266Smuller #else
104957266Smuller static int
105057266Smuller resub(prog, src, dest, destend)
105157266Smuller 	regexp *prog;
105257266Smuller 	char *src;
105357266Smuller 	char *dest;
105457266Smuller 	register char *destend;
105557266Smuller #endif
105657266Smuller {
105757266Smuller 	register char *spt;
105857266Smuller 	register char *dpt;
105957266Smuller 	register char c;
106057266Smuller 	register int no;
106157266Smuller 	register int len;
106257266Smuller 
106357266Smuller 	spt = src;
106457266Smuller 	dpt = dest;
106557266Smuller 	while ((dpt < destend) && ((c = *spt++) != '\0')) {
106657266Smuller 		if (c == '&')
106757266Smuller 			no = 0;
106857266Smuller 		else if ((c == '\\') && (*spt >= '0') && (*spt <= '9'))
106957266Smuller 			no = *spt++ - '0';
107057266Smuller 		else {
107157266Smuller  			if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
107257266Smuller  				c = *spt++;
107357266Smuller  			*dpt++ = c;
107457266Smuller 			continue;
107557266Smuller 		}
107657266Smuller  		if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) ||
107757266Smuller 		    ((len = prog->endp[no] - prog->startp[no]) <= 0))
107857266Smuller 			continue;
107957266Smuller 
108057266Smuller 		/*
108157266Smuller 		 * copy the subexpression to the destination.
108257266Smuller 		 * fail if we run out of space or the match string is damaged
108357266Smuller 		 */
108457266Smuller 		if (len > (destend - dpt))
108557266Smuller 			len = destend - dpt;
108657266Smuller 		if (l_strncpy(dpt, prog->startp[no], len) != len)
108757266Smuller 			return(-1);
108857266Smuller 		dpt += len;
108957266Smuller 	}
109057266Smuller 	return(dpt - dest);
109157266Smuller }
109257266Smuller 
109357266Smuller #else
109457266Smuller 
109557266Smuller /*
109657266Smuller  * resub()
109757266Smuller  *	apply the replacement to the matched expression. expand out the old
109857266Smuller  * 	style ed(1) subexpression expansion.
109957266Smuller  * Return:
110057266Smuller  *	-1 if error, or the number of characters added to the destination.
110157266Smuller  */
110257266Smuller 
110357266Smuller #if __STDC__
110457266Smuller static int
resub(regex_t * rp,register regmatch_t * pm,char * src,char * dest,register char * destend)110557266Smuller resub(regex_t *rp, register regmatch_t *pm, char *src, char *dest,
110657266Smuller 	register char *destend)
110757266Smuller #else
110857266Smuller static int
110957266Smuller resub(rp, pm, src, dest, destend)
111057266Smuller 	regex_t *rp;
111157266Smuller 	register regmatch_t *pm;
111257266Smuller 	char *src;
111357266Smuller 	char *dest;
111457266Smuller 	register char *destend;
111557266Smuller #endif
111657266Smuller {
111757266Smuller 	register char *spt;
111857266Smuller 	register char *dpt;
111957266Smuller 	register char c;
112057266Smuller 	register regmatch_t *pmpt;
112157266Smuller 	register int len;
112257266Smuller 	int subexcnt;
112357266Smuller 
112457266Smuller 	spt =  src;
112557266Smuller 	dpt = dest;
112657266Smuller 	subexcnt = rp->re_nsub;
112757266Smuller 	while ((dpt < destend) && ((c = *spt++) != '\0')) {
112857266Smuller 		/*
112957266Smuller 		 * see if we just have an ordinary replacement character
113057266Smuller 		 * or we refer to a subexpression.
113157266Smuller 		 */
113257266Smuller 		if (c == '&') {
113357266Smuller 			pmpt = pm;
113457266Smuller 		} else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
113557266Smuller 			/*
113657266Smuller 			 * make sure there is a subexpression as specified
113757266Smuller 			 */
113857266Smuller 			if ((len = *spt++ - '0') > subexcnt)
113957266Smuller 				return(-1);
114057266Smuller 			pmpt = pm + len;
114157266Smuller 		} else {
114257266Smuller  			/*
114357266Smuller 			 * Ordinary character, just copy it
114457266Smuller 			 */
114557266Smuller  			if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
114657266Smuller  				c = *spt++;
114757266Smuller  			*dpt++ = c;
114857266Smuller 			continue;
114957266Smuller 		}
115057266Smuller 
115157266Smuller 		/*
115257266Smuller 		 * continue if the subexpression is bogus
115357266Smuller 		 */
115457266Smuller 		if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
115557266Smuller 		    ((len = pmpt->rm_eo - pmpt->rm_so) <= 0))
115657266Smuller 			continue;
115757266Smuller 
115857266Smuller 		/*
115957266Smuller 		 * copy the subexpression to the destination.
116057266Smuller 		 * fail if we run out of space or the match string is damaged
116157266Smuller 		 */
116257266Smuller 		if (len > (destend - dpt))
116357266Smuller 			len = destend - dpt;
116457266Smuller 		if (l_strncpy(dpt, src + pmpt->rm_so, len) != len)
116557266Smuller 			return(-1);
116657266Smuller 		dpt += len;
116757266Smuller 	}
116857266Smuller 	return(dpt - dest);
116957266Smuller }
117057266Smuller #endif
1171