xref: /csrg-svn/bin/pax/pat_rep.c (revision 57266)
1*57266Smuller /*-
2*57266Smuller  * Copyright (c) 1992 Keith Muller.
3*57266Smuller  * Copyright (c) 1992 The Regents of the University of California.
4*57266Smuller  * All rights reserved.
5*57266Smuller  *
6*57266Smuller  * This code is derived from software contributed to Berkeley by
7*57266Smuller  * Keith Muller of the University of California, San Diego.
8*57266Smuller  *
9*57266Smuller  * %sccs.include.redist.c%
10*57266Smuller  */
11*57266Smuller 
12*57266Smuller #ifndef lint
13*57266Smuller static char sccsid[] = "@(#)pat_rep.c	1.1 (Berkeley) 12/21/92";
14*57266Smuller #endif /* not lint */
15*57266Smuller 
16*57266Smuller #include <sys/types.h>
17*57266Smuller #include <sys/time.h>
18*57266Smuller #include <sys/stat.h>
19*57266Smuller #include <sys/param.h>
20*57266Smuller #include <stdio.h>
21*57266Smuller #include <ctype.h>
22*57266Smuller #include <string.h>
23*57266Smuller #include <unistd.h>
24*57266Smuller #include <stdlib.h>
25*57266Smuller #include <fnmatch.h>
26*57266Smuller #ifdef NET2_REGEX
27*57266Smuller #include <regexp.h>
28*57266Smuller #else
29*57266Smuller #include <regex.h>
30*57266Smuller #endif
31*57266Smuller #include "pax.h"
32*57266Smuller #include "pat_rep.h"
33*57266Smuller #include "extern.h"
34*57266Smuller 
35*57266Smuller /*
36*57266Smuller  * routines to handle pattern matching, name modification (regular expression
37*57266Smuller  * substitution and interactive renames), and destination name modification for
38*57266Smuller  * copy (-rw). Both file name and link names are adjusted as required in these
39*57266Smuller  * routines.
40*57266Smuller  */
41*57266Smuller 
42*57266Smuller #define MAXSUBEXP	10		/* max subexpressions, DO NOT CHANGE */
43*57266Smuller static PATTERN *pathead = NULL;		/* file pattern match list head */
44*57266Smuller static PATTERN *pattail = NULL;		/* file pattern match list tail */
45*57266Smuller static REPLACE *rephead = NULL;		/* replacement string list head */
46*57266Smuller static REPLACE *reptail = NULL;		/* replacement string list tail */
47*57266Smuller 
48*57266Smuller static int rep_name __P((char *, int *, int));
49*57266Smuller static int tty_rename __P((register ARCHD *));
50*57266Smuller static int fix_path __P((char *, int *, char *, int));
51*57266Smuller #ifdef NET2_REGEX
52*57266Smuller static int resub __P((regexp *, char *, char *, register char *));
53*57266Smuller #else
54*57266Smuller static int resub __P((regex_t *, regmatch_t *, char *, char *, char *));
55*57266Smuller #endif
56*57266Smuller 
57*57266Smuller /*
58*57266Smuller  * rep_add()
59*57266Smuller  *	parses the -s replacement string; compiles the regular expression
60*57266Smuller  *	and stores the compiled value and it's replacement string together in
61*57266Smuller  *	replacement string list. Input to this function is of the form:
62*57266Smuller  *		/old/new/pg
63*57266Smuller  *	The first char in the string specifies the delimiter used by this
64*57266Smuller  *	replacement string. "Old" is a regular expression in "ed" format which
65*57266Smuller  *	is compiled by regcomp() and is applied to filenames. "new" is the
66*57266Smuller  *	substitution string; p and g are options flags for printing and global
67*57266Smuller  *	replacement (over the single filename)
68*57266Smuller  * Return:
69*57266Smuller  *	0 if a proper replacement string and regular expression was added to
70*57266Smuller  *	the list of replacement patterns; -1 otherwise.
71*57266Smuller  */
72*57266Smuller 
73*57266Smuller #if __STDC__
74*57266Smuller int
75*57266Smuller rep_add(register char *str)
76*57266Smuller #else
77*57266Smuller int
78*57266Smuller rep_add(str)
79*57266Smuller 	register char *str;
80*57266Smuller #endif
81*57266Smuller {
82*57266Smuller 	register char *pt1;
83*57266Smuller 	register char *pt2;
84*57266Smuller 	register REPLACE *rep;
85*57266Smuller #	ifndef NET2_REGEX
86*57266Smuller 	register int res;
87*57266Smuller 	char rebuf[BUFSIZ];
88*57266Smuller #	endif
89*57266Smuller 
90*57266Smuller 	/*
91*57266Smuller 	 * throw out the bad parameters
92*57266Smuller 	 */
93*57266Smuller 	if ((str == NULL) || (*str == '\0')) {
94*57266Smuller 		warn(1, "Empty replacement string");
95*57266Smuller 		return(-1);
96*57266Smuller 	}
97*57266Smuller 
98*57266Smuller 	/*
99*57266Smuller 	 * first character in the string specifies what the delimiter is for
100*57266Smuller 	 * this expression
101*57266Smuller 	 */
102*57266Smuller 	if ((pt1 = strchr(str+1, *str)) == NULL) {
103*57266Smuller 		warn(1, "Invalid replacement string %s", str);
104*57266Smuller 		return(-1);
105*57266Smuller 	}
106*57266Smuller 
107*57266Smuller 	/*
108*57266Smuller 	 * allocate space for the node that handles this replacement pattern
109*57266Smuller 	 * and split out the regular expression and try to compile it
110*57266Smuller 	 */
111*57266Smuller 	if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
112*57266Smuller 		warn(1, "Unable to allocate memory for replacement string");
113*57266Smuller 		return(-1);
114*57266Smuller 	}
115*57266Smuller 
116*57266Smuller 	*pt1 = '\0';
117*57266Smuller #	ifdef NET2_REGEX
118*57266Smuller 	if ((rep->rcmp = regcomp(str+1)) == NULL) {
119*57266Smuller #	else
120*57266Smuller 	if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
121*57266Smuller 		regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
122*57266Smuller 		warn(1, "%s while compiling regular expression %s", rebuf, str);
123*57266Smuller #	endif
124*57266Smuller 		(void)free((char *)rep);
125*57266Smuller 		return(-1);
126*57266Smuller 	}
127*57266Smuller 
128*57266Smuller 	/*
129*57266Smuller 	 * put the delimiter back in case we need an error message and
130*57266Smuller 	 * locate the delimiter at the end of the replacement string
131*57266Smuller 	 * we then point the node at the new substitution string
132*57266Smuller 	 */
133*57266Smuller 	*pt1++ = *str;
134*57266Smuller 	if ((pt2 = strchr(pt1, *str)) == NULL) {
135*57266Smuller #		ifdef NET2_REGEX
136*57266Smuller 		(void)free((char *)rep->rcmp);
137*57266Smuller #		else
138*57266Smuller 		regfree(&(rep->rcmp));
139*57266Smuller #		endif
140*57266Smuller 		(void)free((char *)rep);
141*57266Smuller 		warn(1, "Invalid replacement string %s", str);
142*57266Smuller 		return(-1);
143*57266Smuller 	}
144*57266Smuller 
145*57266Smuller 	*pt2 = '\0';
146*57266Smuller 	rep->nstr = pt1;
147*57266Smuller 	pt1 = pt2++;
148*57266Smuller 	rep->flgs = 0;
149*57266Smuller 
150*57266Smuller 	/*
151*57266Smuller 	 * set the options if any
152*57266Smuller 	 */
153*57266Smuller 	while (*pt2 != '\0') {
154*57266Smuller 		switch(*pt2) {
155*57266Smuller 		case 'g':
156*57266Smuller 		case 'G':
157*57266Smuller 			rep->flgs  |= GLOB;
158*57266Smuller 			break;
159*57266Smuller 		case 'p':
160*57266Smuller 		case 'P':
161*57266Smuller 			rep->flgs  |= PRNT;
162*57266Smuller 			break;
163*57266Smuller 		default:
164*57266Smuller #			ifdef NET2_REGEX
165*57266Smuller 			(void)free((char *)rep->rcmp);
166*57266Smuller #			else
167*57266Smuller 			regfree(&(rep->rcmp));
168*57266Smuller #			endif
169*57266Smuller 			(void)free((char *)rep);
170*57266Smuller 			*pt1 = *str;
171*57266Smuller 			warn(1, "Invalid replacement string option %s", str);
172*57266Smuller 			return(-1);
173*57266Smuller 		}
174*57266Smuller 		++pt2;
175*57266Smuller 	}
176*57266Smuller 
177*57266Smuller 	/*
178*57266Smuller 	 * all done, link it in at the end
179*57266Smuller 	 */
180*57266Smuller 	rep->fow = NULL;
181*57266Smuller 	if (rephead == NULL) {
182*57266Smuller 		reptail = rephead = rep;
183*57266Smuller 		return(0);
184*57266Smuller 	}
185*57266Smuller 	reptail->fow = rep;
186*57266Smuller 	reptail = rep;
187*57266Smuller 	return(0);
188*57266Smuller }
189*57266Smuller 
190*57266Smuller /*
191*57266Smuller  * pat_add()
192*57266Smuller  *	add a pattern match to the pattern match list. Pattern matches are used
193*57266Smuller  *	to select which archive members are extracted. (They appear as
194*57266Smuller  *	arguments to pax in the list and read modes). If no patterns are
195*57266Smuller  *	supplied to pax, all members in the archive will be selected (and the
196*57266Smuller  *	pattern match list is empty).
197*57266Smuller  * Return:
198*57266Smuller  *	0 if the pattern was added to the list, -1 otherwise
199*57266Smuller  */
200*57266Smuller 
201*57266Smuller #if __STDC__
202*57266Smuller int
203*57266Smuller pat_add(char *str)
204*57266Smuller #else
205*57266Smuller int
206*57266Smuller pat_add(str)
207*57266Smuller 	char *str;
208*57266Smuller #endif
209*57266Smuller {
210*57266Smuller 	register PATTERN *pt;
211*57266Smuller 
212*57266Smuller 	/*
213*57266Smuller 	 * throw out the junk
214*57266Smuller 	 */
215*57266Smuller 	if ((str == NULL) || (*str == '\0')) {
216*57266Smuller 		warn(1, "Empty pattern string");
217*57266Smuller 		return(-1);
218*57266Smuller 	}
219*57266Smuller 
220*57266Smuller 	/*
221*57266Smuller 	 * allocate space for the pattern and store the pattern. the pattern is
222*57266Smuller 	 * part of argv so do not bother to copy it, just point at it. Add the
223*57266Smuller 	 * node to the end of the pattern list
224*57266Smuller 	 */
225*57266Smuller 	if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
226*57266Smuller 		warn(1, "Unable to allocate memory for pattern string");
227*57266Smuller 		return(-1);
228*57266Smuller 	}
229*57266Smuller 
230*57266Smuller 	pt->pstr = str;
231*57266Smuller 	pt->plen = strlen(str);
232*57266Smuller 	pt->fow = NULL;
233*57266Smuller 	pt->flgs = 0;
234*57266Smuller 	if (pathead == NULL) {
235*57266Smuller 		pattail = pathead = pt;
236*57266Smuller 		return(0);
237*57266Smuller 	}
238*57266Smuller 	pattail->fow = pt;
239*57266Smuller 	pattail = pt;
240*57266Smuller 	return(0);
241*57266Smuller }
242*57266Smuller 
243*57266Smuller /*
244*57266Smuller  * pat_chk()
245*57266Smuller  *	complain if any the user supplied pattern did not result in a match to
246*57266Smuller  *	a selected archive member.
247*57266Smuller  */
248*57266Smuller 
249*57266Smuller #if __STDC__
250*57266Smuller void
251*57266Smuller pat_chk(void)
252*57266Smuller #else
253*57266Smuller void
254*57266Smuller pat_chk()
255*57266Smuller #endif
256*57266Smuller {
257*57266Smuller 	register PATTERN *pt;
258*57266Smuller 	register int wban = 0;
259*57266Smuller 
260*57266Smuller 	/*
261*57266Smuller 	 * walk down the list checking the flags to make sure MTCH was set,
262*57266Smuller 	 * if not complain
263*57266Smuller 	 */
264*57266Smuller 	for (pt = pathead; pt != NULL; pt = pt->fow) {
265*57266Smuller 		if (pt->flgs & MTCH)
266*57266Smuller 			continue;
267*57266Smuller 		if (!wban) {
268*57266Smuller 			warn(1, "WARNING! These patterns were not matched:");
269*57266Smuller 			++wban;
270*57266Smuller 		}
271*57266Smuller 		(void)fprintf(stderr, "%s\n", pt->pstr);
272*57266Smuller 	}
273*57266Smuller }
274*57266Smuller 
275*57266Smuller /*
276*57266Smuller  * pat_sel()
277*57266Smuller  *	the archive member which matches a pattern was selected. Mark the
278*57266Smuller  *	pattern as having selected an archive member. arcn->pat points at the
279*57266Smuller  *	pattern that was matched. arcn->pat is set in pat_match()
280*57266Smuller  *
281*57266Smuller  *	NOTE: When the -c option is used, we are called when there was no match
282*57266Smuller  *	by pat_match() (that means we did match before the inverted sense of
283*57266Smuller  *	the logic). Now this seems really strange at first, but with -c  we
284*57266Smuller  *	need to keep track of those patterns that cause a archive member to NOT
285*57266Smuller  *	be selected (it found an archive member with a specified pattern)
286*57266Smuller  * Return:
287*57266Smuller  *	0 if the pattern pointed at by arcn->pat was tagged as creating a
288*57266Smuller  *	match, -1 otherwise.
289*57266Smuller  */
290*57266Smuller 
291*57266Smuller #if __STDC__
292*57266Smuller int
293*57266Smuller pat_sel(register ARCHD *arcn)
294*57266Smuller #else
295*57266Smuller int
296*57266Smuller pat_sel(arcn)
297*57266Smuller 	register ARCHD *arcn;
298*57266Smuller #endif
299*57266Smuller {
300*57266Smuller 	register PATTERN *pt;
301*57266Smuller 	register PATTERN **ppt;
302*57266Smuller 	register int len;
303*57266Smuller 
304*57266Smuller 	/*
305*57266Smuller 	 * if no patterns just return
306*57266Smuller 	 */
307*57266Smuller 	if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
308*57266Smuller 		return(0);
309*57266Smuller 
310*57266Smuller 	/*
311*57266Smuller 	 * when we are NOT limited to a single match per pattern mark the
312*57266Smuller 	 * the pattern and return
313*57266Smuller 	 */
314*57266Smuller 	if (!nflag) {
315*57266Smuller 		pt->flgs |= MTCH;
316*57266Smuller 		if (dflag || (arcn->type != PAX_DIR))
317*57266Smuller 			return(0);
318*57266Smuller 		/*
319*57266Smuller 		 * ok we matched a directory and we are allowing
320*57266Smuller 		 * subtree matches. We add this as a DIR_MTCH pattern
321*57266Smuller 		 * so all its children will match. Note we know that
322*57266Smuller 		 * when successful, pat_add() puts the pattern at the
323*57266Smuller 		 * tail (yup a kludge). In the code below will make
324*57266Smuller 		 * a dir match pattern
325*57266Smuller 		 */
326*57266Smuller 		if ((pat_add(arcn->name) < 0) || ((pt = pattail) == NULL))
327*57266Smuller 			return(-1);
328*57266Smuller 		arcn->pat = pt;
329*57266Smuller 	}
330*57266Smuller 
331*57266Smuller 	/*
332*57266Smuller 	 * we reach this point only when we allow a single selected match per
333*57266Smuller 	 * pattern, or we have to add a DIR_MATCH pattern. if the pattern
334*57266Smuller 	 * matched a directory and we do not have -d * (dflag) we are done
335*57266Smuller 	 * with this pattern. We may also be handed a file in the subtree of a
336*57266Smuller 	 * directory. in that case when we are operating with -d, this pattern
337*57266Smuller 	 * was already selected and we are done
338*57266Smuller 	 */
339*57266Smuller 	if (pt->flgs & DIR_MTCH)
340*57266Smuller 		return(0);
341*57266Smuller 
342*57266Smuller 	if (!dflag && (arcn->type == PAX_DIR)) {
343*57266Smuller 		/*
344*57266Smuller 		 * we are allowing subtree matches at directories, mark the
345*57266Smuller 		 * node as a directory match so pat_match() will only match
346*57266Smuller 		 * children of this directory (we replace the pattern with the
347*57266Smuller 		 * directory name to enforce this subtree only match)
348*57266Smuller 		 * pat_match() looks for DIR_MTCH to determine what comparison
349*57266Smuller 		 * technique to use when it checks for a pattern match
350*57266Smuller 	 	 */
351*57266Smuller 		if ((pt->pstr = strdup(arcn->name)) == NULL) {
352*57266Smuller 			warn(1, "Pattern select out of memory");
353*57266Smuller 			return(-1);
354*57266Smuller 		}
355*57266Smuller 		pt->plen = strlen(pt->pstr);
356*57266Smuller 
357*57266Smuller 		/*
358*57266Smuller 		 * strip off any trailing /, this should really never happen
359*57266Smuller 		 */
360*57266Smuller 		len = pt->plen - 1;
361*57266Smuller 		if (*(pt->pstr + len) == '/') {
362*57266Smuller 			*(pt->pstr + len) = '\0';
363*57266Smuller 			pt->plen = len;
364*57266Smuller 		}
365*57266Smuller 		pt->flgs |= DIR_MTCH | MTCH;
366*57266Smuller 		return(0);
367*57266Smuller 	}
368*57266Smuller 
369*57266Smuller 	/*
370*57266Smuller 	 * it is not a directory, we are then done with this pattern, so we
371*57266Smuller 	 * delete it from the list, as it can never be used for another match
372*57266Smuller 	 * Seems kind of strange to do for a -c, but the pax spec is really
373*57266Smuller 	 * vague on the interaction of -c -n and -d. We assume that when -c
374*57266Smuller 	 * and the pattern rejects a member (i.e. it matched it) it is done.
375*57266Smuller 	 * In effect we place the order of the flags as having -c last.
376*57266Smuller 	 */
377*57266Smuller 	pt = pathead;
378*57266Smuller 	ppt = &pathead;
379*57266Smuller 	while ((pt != NULL) && (pt != arcn->pat)) {
380*57266Smuller 		ppt = &(pt->fow);
381*57266Smuller 		pt = pt->fow;
382*57266Smuller 	}
383*57266Smuller 
384*57266Smuller 	if (pt == NULL) {
385*57266Smuller 		/*
386*57266Smuller 		 * should never happen....
387*57266Smuller 		 */
388*57266Smuller 		warn(1, "Pattern list inconsistant");
389*57266Smuller 		return(-1);
390*57266Smuller 	}
391*57266Smuller 	*ppt = pt->fow;
392*57266Smuller 	(void)free((char *)pt);
393*57266Smuller 	arcn->pat = NULL;
394*57266Smuller 	return(0);
395*57266Smuller }
396*57266Smuller 
397*57266Smuller /*
398*57266Smuller  * pat_match()
399*57266Smuller  *	see if this archive member matches any supplied pattern, if a match
400*57266Smuller  *	is found, arcn->pat is set to point at the potential pattern. Later if
401*57266Smuller  *	this archive member is "selected" we process and mark the pattern as
402*57266Smuller  *	one which matched a selected archive member (see pat_sel())
403*57266Smuller  * Return:
404*57266Smuller  *	0 if this archive member should be processed, 1 if it should be
405*57266Smuller  *	skipped and -1 if we are done with all patterns (and pax should quit
406*57266Smuller  *	looking for more members)
407*57266Smuller  */
408*57266Smuller 
409*57266Smuller #if __STDC__
410*57266Smuller int
411*57266Smuller pat_match(register ARCHD *arcn)
412*57266Smuller #else
413*57266Smuller int
414*57266Smuller pat_match(arcn)
415*57266Smuller 	register ARCHD *arcn;
416*57266Smuller #endif
417*57266Smuller {
418*57266Smuller 	register PATTERN *pt;
419*57266Smuller 
420*57266Smuller 	arcn->pat = NULL;
421*57266Smuller 
422*57266Smuller 	/*
423*57266Smuller 	 * if there are no more patterns and we have -n (and not -c) we are
424*57266Smuller 	 * done. otherwise with no patterns to match, matches all
425*57266Smuller 	 */
426*57266Smuller 	if (pathead == NULL) {
427*57266Smuller 		if (nflag && !cflag)
428*57266Smuller 			return(-1);
429*57266Smuller 		return(0);
430*57266Smuller 	}
431*57266Smuller 
432*57266Smuller 	/*
433*57266Smuller 	 * have to search down the list one at a time looking for a match.
434*57266Smuller 	 */
435*57266Smuller 	pt = pathead;
436*57266Smuller 	while (pt != NULL) {
437*57266Smuller 		/*
438*57266Smuller 		 * check for a file name match unless we have DIR_MTCH set in
439*57266Smuller 		 * this pattern then we want a prefix match
440*57266Smuller 		 */
441*57266Smuller 
442*57266Smuller 		if (pt->flgs & DIR_MTCH) {
443*57266Smuller 			/*
444*57266Smuller 			 * this pattern was matched before to a directory
445*57266Smuller 			 * as we must have -n set for this (but not -d). We can
446*57266Smuller 			 * only match CHILDREN of that directory so we must use
447*57266Smuller 			 * an exact prefix match
448*57266Smuller 			 */
449*57266Smuller 			if ((strncmp(pt->pstr, arcn->name, pt->plen) == 0) &&
450*57266Smuller 			    (arcn->name[pt->plen] == '/'))
451*57266Smuller 				break;
452*57266Smuller 		} else if (fnmatch(pt->pstr, arcn->name, 0) == 0)
453*57266Smuller 			break;
454*57266Smuller 		pt = pt->fow;
455*57266Smuller 	}
456*57266Smuller 
457*57266Smuller 	/*
458*57266Smuller 	 * return the result, remember that cflag (-c) inverts the sense of a
459*57266Smuller 	 * match
460*57266Smuller 	 */
461*57266Smuller 	if (pt == NULL)
462*57266Smuller 		return(cflag ? 0 : 1);
463*57266Smuller 
464*57266Smuller 	/*
465*57266Smuller 	 * we had a match, now when we invert the sense (-c) we reject this
466*57266Smuller 	 * member. However we have to tag the pattern a being successful, (in a
467*57266Smuller 	 * match, not in selecting a archive member) so we call pat_sel() here.
468*57266Smuller 	 */
469*57266Smuller 	arcn->pat = pt;
470*57266Smuller 	if (!cflag)
471*57266Smuller 		return(0);
472*57266Smuller 
473*57266Smuller 	if (pat_sel(arcn) < 0)
474*57266Smuller 		return(-1);
475*57266Smuller 	arcn->pat = NULL;
476*57266Smuller 	return(1);
477*57266Smuller }
478*57266Smuller 
479*57266Smuller /*
480*57266Smuller  * mod_name()
481*57266Smuller  *	modify a selected file name. first attempt to apply replacement string
482*57266Smuller  *	expressions, then apply interactive file rename. We apply replacement
483*57266Smuller  *	string expressions to both filenames and file links (if we didn't the
484*57266Smuller  *	links would point to the wrong place, and we could never be able to
485*57266Smuller  *	move an archive that has a file link in it). When we rename files
486*57266Smuller  *	interactively, we store that mapping (old name to user input name) so
487*57266Smuller  *	if we spot any file links to the old file name in the future, we will
488*57266Smuller  *	know exactly how to fix the file link.
489*57266Smuller  * Return:
490*57266Smuller  *	0 continue to  process file, 1 skip this file, -1 pax is finished
491*57266Smuller  */
492*57266Smuller 
493*57266Smuller #if __STDC__
494*57266Smuller int
495*57266Smuller mod_name(register ARCHD *arcn)
496*57266Smuller #else
497*57266Smuller int
498*57266Smuller mod_name(arcn)
499*57266Smuller 	register ARCHD *arcn;
500*57266Smuller #endif
501*57266Smuller {
502*57266Smuller 	register int res = 0;
503*57266Smuller 
504*57266Smuller 	/*
505*57266Smuller 	 * IMPORTANT: We have a problem. what do we do with symlinks?
506*57266Smuller 	 * Modifying a hard link name makes sense, as we know the file it
507*57266Smuller 	 * points at should have been seen already in the archive (and if it
508*57266Smuller 	 * wasn't seen because of a read error or a bad archive, we lose
509*57266Smuller 	 * anyway). But there are no such requirements for symlinks. On one
510*57266Smuller 	 * hand the symlink that refers to a file in the archive will have to
511*57266Smuller 	 * be modified to so it will still work at its new location in the
512*57266Smuller 	 * file system. On the other hand a symlink that points elsewhere (and
513*57266Smuller 	 * should continue to do so) should not be modified. There is clearly
514*57266Smuller 	 * no perfect solution here. So we handle them like hardlinks. Clearly
515*57266Smuller 	 * a replacement made by the interactive rename mapping is very likely
516*57266Smuller 	 * to be correct since it applies to a single file and is an exact
517*57266Smuller 	 * match. The regular expression replacements are a little harder to
518*57266Smuller 	 * justify though. We claim that the symlink name is only likely
519*57266Smuller 	 * to be replaced when it points within the file tree being moved and
520*57266Smuller 	 * in that case it should be modified. what we really need to do is to
521*57266Smuller 	 * call an oracle here. :)
522*57266Smuller 	 */
523*57266Smuller 	if (rephead != NULL) {
524*57266Smuller 		/*
525*57266Smuller 		 * we have replacement strings, modify the name and the link
526*57266Smuller 		 * name if any.
527*57266Smuller 		 */
528*57266Smuller 		if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0)
529*57266Smuller 			return(res);
530*57266Smuller 
531*57266Smuller 		if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
532*57266Smuller 		    (arcn->type == PAX_HRG)) &&
533*57266Smuller 		    ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0))
534*57266Smuller 			return(res);
535*57266Smuller 	}
536*57266Smuller 
537*57266Smuller 	if (iflag) {
538*57266Smuller 		/*
539*57266Smuller 		 * perform interactive file rename, then map the link if any
540*57266Smuller 		 */
541*57266Smuller 		if ((res = tty_rename(arcn)) != 0)
542*57266Smuller 			return(res);
543*57266Smuller 		if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
544*57266Smuller 		    (arcn->type == PAX_HRG))
545*57266Smuller 			sub_name(arcn->ln_name, &(arcn->ln_nlen));
546*57266Smuller 	}
547*57266Smuller 	return(res);
548*57266Smuller }
549*57266Smuller 
550*57266Smuller /*
551*57266Smuller  * tty_rename()
552*57266Smuller  *	Prompt the user for a replacement file name. A "." keeps the old name,
553*57266Smuller  *	a empty line skips the file, and an EOF on reading the tty, will cause
554*57266Smuller  *	pax to stop processing and exit. Otherwise the file name input, replaces
555*57266Smuller  *	the old one.
556*57266Smuller  * Return:
557*57266Smuller  *	0 process this file, 1 skip this file, -1 we need to exit pax
558*57266Smuller  */
559*57266Smuller 
560*57266Smuller #if __STDC__
561*57266Smuller static int
562*57266Smuller tty_rename(register ARCHD *arcn)
563*57266Smuller #else
564*57266Smuller static int
565*57266Smuller tty_rename(arcn)
566*57266Smuller 	register ARCHD *arcn;
567*57266Smuller #endif
568*57266Smuller {
569*57266Smuller 	char tmpname[PAXPATHLEN+2];
570*57266Smuller 	int res;
571*57266Smuller 
572*57266Smuller 	/*
573*57266Smuller 	 * prompt user for the replacement name for a file, keep trying until
574*57266Smuller 	 * we get some reasonable input. Archives may have more than one file
575*57266Smuller 	 * on them with the same name (from updates etc). We print verbose info
576*57266Smuller 	 * on the file so the user knows what is up.
577*57266Smuller 	 */
578*57266Smuller 	tty_prnt("\nATTENTION: Pax interactive file rename operation.\n");
579*57266Smuller 
580*57266Smuller 	for (;;) {
581*57266Smuller 		ls_tty(arcn);
582*57266Smuller 		tty_prnt("Input new name, or a \".\" to keep the old name, ");
583*57266Smuller 		tty_prnt("or a \"return\" to skip this file.\n");
584*57266Smuller 		tty_prnt("Input > ");
585*57266Smuller 		if (tty_read(tmpname, sizeof(tmpname)) < 0)
586*57266Smuller 			return(-1);
587*57266Smuller 		if (strcmp(tmpname, "..") == 0) {
588*57266Smuller 			tty_prnt("Try again, illegal file name: ..\n");
589*57266Smuller 			continue;
590*57266Smuller 		}
591*57266Smuller 		if (strlen(tmpname) > PAXPATHLEN) {
592*57266Smuller 			tty_prnt("Try again, file name too long\n");
593*57266Smuller 			continue;
594*57266Smuller 		}
595*57266Smuller 		break;
596*57266Smuller 	}
597*57266Smuller 
598*57266Smuller 	/*
599*57266Smuller 	 * empty file name, skips this file. a "." leaves it alone
600*57266Smuller 	 */
601*57266Smuller 	if (tmpname[0] == '\0') {
602*57266Smuller 		tty_prnt("Skipping file.\n");
603*57266Smuller 		return(1);
604*57266Smuller 	}
605*57266Smuller 	if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
606*57266Smuller 		tty_prnt("Processing continues, name unchanged.\n");
607*57266Smuller 		return(0);
608*57266Smuller 	}
609*57266Smuller 
610*57266Smuller 	/*
611*57266Smuller 	 * ok the name changed. We may run into links that point at this
612*57266Smuller 	 * file later. we have to remember where the user sent the file
613*57266Smuller 	 * in order to repair any links.
614*57266Smuller 	 */
615*57266Smuller 	tty_prnt("Processing continues, name changed to: %s\n", tmpname);
616*57266Smuller 	res = add_name(arcn->name, arcn->nlen, tmpname);
617*57266Smuller 	arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1);
618*57266Smuller 	if (res < 0)
619*57266Smuller 		return(-1);
620*57266Smuller 	return(0);
621*57266Smuller }
622*57266Smuller 
623*57266Smuller /*
624*57266Smuller  * set_dest()
625*57266Smuller  *	fix up the file name and the link name (if any) so this file will land
626*57266Smuller  *	in the destination directory (used during copy() -rw).
627*57266Smuller  * Return:
628*57266Smuller  *	0 if ok, -1 if failure (name too long)
629*57266Smuller  */
630*57266Smuller 
631*57266Smuller #if __STDC__
632*57266Smuller int
633*57266Smuller set_dest(register ARCHD *arcn, char *dest_dir, int dir_len)
634*57266Smuller #else
635*57266Smuller int
636*57266Smuller set_dest(arcn, dest_dir, dir_len)
637*57266Smuller 	register ARCHD *arcn;
638*57266Smuller 	char *dest_dir;
639*57266Smuller 	int dir_len;
640*57266Smuller #endif
641*57266Smuller {
642*57266Smuller 	if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
643*57266Smuller 		return(-1);
644*57266Smuller 
645*57266Smuller 	if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG) &&
646*57266Smuller 	    (arcn->type != PAX_SLK))
647*57266Smuller 		return(0);
648*57266Smuller 
649*57266Smuller 	if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
650*57266Smuller 		return(-1);
651*57266Smuller 	return(0);
652*57266Smuller }
653*57266Smuller 
654*57266Smuller /*
655*57266Smuller  * fix_path
656*57266Smuller  *	concatenate dir_name and or_name and store the result in or_name (if
657*57266Smuller  *	it fits). This is one ugly function.
658*57266Smuller  * Return:
659*57266Smuller  *	0 if ok, -1 if the final name is too long
660*57266Smuller  */
661*57266Smuller 
662*57266Smuller #if __STDC__
663*57266Smuller static int
664*57266Smuller fix_path( char *or_name, int *or_len, char *dir_name, int dir_len)
665*57266Smuller #else
666*57266Smuller static int
667*57266Smuller fix_path(or_name, or_len, dir_name, dir_len)
668*57266Smuller 	char *or_name;
669*57266Smuller 	int *or_len;
670*57266Smuller 	char *dir_name;
671*57266Smuller 	int dir_len;
672*57266Smuller #endif
673*57266Smuller {
674*57266Smuller 	register char *src;
675*57266Smuller 	register char *dest;
676*57266Smuller 	register char *start;
677*57266Smuller 	int len;
678*57266Smuller 
679*57266Smuller 	/*
680*57266Smuller 	 * we shift the or_name to the right enough to tack in the dir_name
681*57266Smuller 	 * at the front. We make sure we have enough space for it all before
682*57266Smuller 	 * we start. since dest always ends in a slash, we skip of or_name
683*57266Smuller 	 * if it also starts with one.
684*57266Smuller 	 */
685*57266Smuller 	start = or_name;
686*57266Smuller 	src = start + *or_len;
687*57266Smuller 	dest = src + dir_len;
688*57266Smuller 	if (*start == '/') {
689*57266Smuller 		++start;
690*57266Smuller 		--dest;
691*57266Smuller 	}
692*57266Smuller 	if ((len = dest - or_name) > PAXPATHLEN) {
693*57266Smuller 		warn(1, "File name %s/%s, too long", dir_name, start);
694*57266Smuller 		return(-1);
695*57266Smuller 	}
696*57266Smuller 	*or_len = len;
697*57266Smuller 
698*57266Smuller 	/*
699*57266Smuller 	 * enough space, shift
700*57266Smuller 	 */
701*57266Smuller 	while (src >= start)
702*57266Smuller 		*dest-- = *src--;
703*57266Smuller 	src = dir_name + dir_len - 1;
704*57266Smuller 
705*57266Smuller 	/*
706*57266Smuller 	 * splice in the destination directory name
707*57266Smuller 	 */
708*57266Smuller 	while (src >= dir_name)
709*57266Smuller 		*dest-- = *src--;
710*57266Smuller 
711*57266Smuller 	*(or_name + len) = '\0';
712*57266Smuller 	return(0);
713*57266Smuller }
714*57266Smuller 
715*57266Smuller /*
716*57266Smuller  * rep_name()
717*57266Smuller  *	walk down the list of replacement strings applying each one in order.
718*57266Smuller  *	when we find one with a successful substitution, we modify the name
719*57266Smuller  *	as specified. if required, we print the results. if the resulting name
720*57266Smuller  *	is empty, we will skip this archive member. We use the regexp(3)
721*57266Smuller  *	routines (regexp() ought to win a prize as having the most cryptic
722*57266Smuller  *	library function manual page).
723*57266Smuller  *	--Parameters--
724*57266Smuller  *	name is the file name we are going to apply the regular expressions to
725*57266Smuller  *	(and may be modified)
726*57266Smuller  *	nlen is the length of this name (and is modified to hold the length of
727*57266Smuller  *	the final string).
728*57266Smuller  *	prnt is a flag that says whether to print the final result.
729*57266Smuller  * Return:
730*57266Smuller  *	0 if substitution was successful, 1 if we are to skip the file (the name
731*57266Smuller  *	ended up empty)
732*57266Smuller  */
733*57266Smuller 
734*57266Smuller #if __STDC__
735*57266Smuller static int
736*57266Smuller rep_name(char *name, int *nlen, int prnt)
737*57266Smuller #else
738*57266Smuller static int
739*57266Smuller rep_name(name, nlen, prnt)
740*57266Smuller 	char *name;
741*57266Smuller 	int *nlen;
742*57266Smuller 	int prnt;
743*57266Smuller #endif
744*57266Smuller {
745*57266Smuller 	register REPLACE *pt;
746*57266Smuller 	register char *inpt;
747*57266Smuller 	register char *outpt;
748*57266Smuller 	register char *endpt;
749*57266Smuller 	register char *rpt;
750*57266Smuller 	register int found = 0;
751*57266Smuller 	register int res;
752*57266Smuller #	ifndef NET2_REGEX
753*57266Smuller 	regmatch_t pm[MAXSUBEXP];
754*57266Smuller #	endif
755*57266Smuller 	char nname[PAXPATHLEN+1];	/* final result of all replacements */
756*57266Smuller 	char buf1[PAXPATHLEN+1];	/* where we work on the name */
757*57266Smuller 
758*57266Smuller 	/*
759*57266Smuller 	 * copy the name into buf1, where we will work on it. We need to keep
760*57266Smuller 	 * the orig string around so we can print out the result of the final
761*57266Smuller 	 * replacement. We build up the final result in nname. inpt points at
762*57266Smuller 	 * the string we apply the regular expression to. prnt is used to
763*57266Smuller 	 * suppress printing when we handle replacements on the link field
764*57266Smuller 	 * (the user already saw that substitution go by)
765*57266Smuller 	 */
766*57266Smuller 	pt = rephead;
767*57266Smuller 	(void)strcpy(buf1, name);
768*57266Smuller 	inpt = buf1;
769*57266Smuller 	outpt = nname;
770*57266Smuller 	endpt = outpt + PAXPATHLEN;
771*57266Smuller 
772*57266Smuller 	/*
773*57266Smuller 	 * try each replacement string in order
774*57266Smuller 	 */
775*57266Smuller 	while (pt != NULL) {
776*57266Smuller 		do {
777*57266Smuller 			/*
778*57266Smuller 			 * check for a successful substitution, if not go to
779*57266Smuller 			 * the next pattern, or cleanup if we were global
780*57266Smuller 			 */
781*57266Smuller #			ifdef NET2_REGEX
782*57266Smuller 			if (regexec(pt->rcmp, inpt) == 0)
783*57266Smuller #			else
784*57266Smuller 			if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
785*57266Smuller #			endif
786*57266Smuller 				break;
787*57266Smuller 
788*57266Smuller 			/*
789*57266Smuller 			 * ok we found one. We have three parts, the prefix
790*57266Smuller 			 * which did not match, the section that did and the
791*57266Smuller 			 * tail (that also did not match). Copy the prefix to
792*57266Smuller 			 * the final output buffer (watching to make sure we
793*57266Smuller 			 * do not create a string too long).
794*57266Smuller 			 */
795*57266Smuller 			found = 1;
796*57266Smuller #			ifdef NET2_REGEX
797*57266Smuller 			rpt = pt->rcmp->startp[0];
798*57266Smuller #			else
799*57266Smuller 			rpt = inpt + pm[0].rm_so;
800*57266Smuller #			endif
801*57266Smuller 
802*57266Smuller 			while ((inpt < rpt) && (outpt < endpt))
803*57266Smuller 				*outpt++ = *inpt++;
804*57266Smuller 			if (outpt == endpt)
805*57266Smuller 				break;
806*57266Smuller 
807*57266Smuller 			/*
808*57266Smuller 			 * for the second part (which matched the regular
809*57266Smuller 			 * expression) apply the substitution using the
810*57266Smuller 			 * replacement string and place it the prefix in the
811*57266Smuller 			 * final output. If we have problems, skip it.
812*57266Smuller 			 */
813*57266Smuller #			ifdef NET2_REGEX
814*57266Smuller 			if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) {
815*57266Smuller #			else
816*57266Smuller 			if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt))
817*57266Smuller 			    < 0) {
818*57266Smuller #			endif
819*57266Smuller 				if (prnt)
820*57266Smuller 					warn(1, "Replacement name error %s",
821*57266Smuller 					    name);
822*57266Smuller 				return(1);
823*57266Smuller 			}
824*57266Smuller 			outpt += res;
825*57266Smuller 
826*57266Smuller 			/*
827*57266Smuller 			 * we set up to look again starting at the first
828*57266Smuller 			 * character in the tail (of the input string right
829*57266Smuller 			 * after the last character matched by the regular
830*57266Smuller 			 * expression (inpt always points at the first char in
831*57266Smuller 			 * the string to process). If we are not doing a global
832*57266Smuller 			 * substitution, we will use inpt to copy the tail to
833*57266Smuller 			 * the final result. Make sure we do not overrun the
834*57266Smuller 			 * output buffer
835*57266Smuller 			 */
836*57266Smuller #			ifdef NET2_REGEX
837*57266Smuller 			inpt = pt->rcmp->endp[0];
838*57266Smuller #			else
839*57266Smuller 			inpt += pm[0].rm_eo;
840*57266Smuller #			endif
841*57266Smuller 
842*57266Smuller 			if ((outpt == endpt) || (*inpt == '\0'))
843*57266Smuller 				break;
844*57266Smuller 
845*57266Smuller 			/*
846*57266Smuller 			 * if the user wants global we keep trying to
847*57266Smuller 			 * substitute until it fails, then we are done.
848*57266Smuller 			 */
849*57266Smuller 		} while (pt->flgs & GLOB);
850*57266Smuller 
851*57266Smuller 		if (found)
852*57266Smuller 			break;
853*57266Smuller 
854*57266Smuller 		/*
855*57266Smuller 		 * a successful substitution did NOT occur, try the next one
856*57266Smuller 		 */
857*57266Smuller 		pt = pt->fow;
858*57266Smuller 	}
859*57266Smuller 
860*57266Smuller 	if (found) {
861*57266Smuller 		/*
862*57266Smuller 		 * we had a substitution, copy the last tail piece (if there is
863*57266Smuller 		 * room) to the final result
864*57266Smuller 		 */
865*57266Smuller 		while ((outpt < endpt) && (*inpt != '\0'))
866*57266Smuller 			*outpt++ = *inpt++;
867*57266Smuller 
868*57266Smuller 		*outpt = '\0';
869*57266Smuller 		if ((outpt == endpt) && (*inpt != '\0')) {
870*57266Smuller 			if (prnt)
871*57266Smuller 				warn(1,"Replacement name too long %s >> %s",
872*57266Smuller 				    name, nname);
873*57266Smuller 			return(1);
874*57266Smuller 		}
875*57266Smuller 
876*57266Smuller 		/*
877*57266Smuller 		 * inform the user of the result if wanted
878*57266Smuller 		 */
879*57266Smuller 		if (prnt && (pt->flgs & PRNT)) {
880*57266Smuller 			if (*nname == '\0')
881*57266Smuller 				(void)fprintf(stderr,"%s >> <empty string>\n",
882*57266Smuller 				    name);
883*57266Smuller 			else
884*57266Smuller 				(void)fprintf(stderr,"%s >> %s\n", name, nname);
885*57266Smuller 		}
886*57266Smuller 
887*57266Smuller 		/*
888*57266Smuller 		 * if empty inform the caller this file is to be skipped
889*57266Smuller 		 * otherwise copy the new name over the orig name and return
890*57266Smuller 		 */
891*57266Smuller 		if (*nname == '\0')
892*57266Smuller 			return(1);
893*57266Smuller 		*nlen = l_strncpy(name, nname, PAXPATHLEN + 1);
894*57266Smuller 	}
895*57266Smuller 	return(0);
896*57266Smuller }
897*57266Smuller 
898*57266Smuller #ifdef NET2_REGEX
899*57266Smuller /*
900*57266Smuller  * resub()
901*57266Smuller  *	apply the replacement to the matched expression. expand out the old
902*57266Smuller  * 	style ed(1) subexpression expansion.
903*57266Smuller  * Return:
904*57266Smuller  *	-1 if error, or the number of characters added to the destination.
905*57266Smuller  */
906*57266Smuller 
907*57266Smuller #if __STDC__
908*57266Smuller static int
909*57266Smuller resub(regexp *prog, char *src, char *dest, register char *destend)
910*57266Smuller #else
911*57266Smuller static int
912*57266Smuller resub(prog, src, dest, destend)
913*57266Smuller 	regexp *prog;
914*57266Smuller 	char *src;
915*57266Smuller 	char *dest;
916*57266Smuller 	register char *destend;
917*57266Smuller #endif
918*57266Smuller {
919*57266Smuller 	register char *spt;
920*57266Smuller 	register char *dpt;
921*57266Smuller 	register char c;
922*57266Smuller 	register int no;
923*57266Smuller 	register int len;
924*57266Smuller 
925*57266Smuller 	spt = src;
926*57266Smuller 	dpt = dest;
927*57266Smuller 	while ((dpt < destend) && ((c = *spt++) != '\0')) {
928*57266Smuller 		if (c == '&')
929*57266Smuller 			no = 0;
930*57266Smuller 		else if ((c == '\\') && (*spt >= '0') && (*spt <= '9'))
931*57266Smuller 			no = *spt++ - '0';
932*57266Smuller 		else {
933*57266Smuller  			if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
934*57266Smuller  				c = *spt++;
935*57266Smuller  			*dpt++ = c;
936*57266Smuller 			continue;
937*57266Smuller 		}
938*57266Smuller  		if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) ||
939*57266Smuller 		    ((len = prog->endp[no] - prog->startp[no]) <= 0))
940*57266Smuller 			continue;
941*57266Smuller 
942*57266Smuller 		/*
943*57266Smuller 		 * copy the subexpression to the destination.
944*57266Smuller 		 * fail if we run out of space or the match string is damaged
945*57266Smuller 		 */
946*57266Smuller 		if (len > (destend - dpt))
947*57266Smuller 			len = destend - dpt;
948*57266Smuller 		if (l_strncpy(dpt, prog->startp[no], len) != len)
949*57266Smuller 			return(-1);
950*57266Smuller 		dpt += len;
951*57266Smuller 	}
952*57266Smuller 	return(dpt - dest);
953*57266Smuller }
954*57266Smuller 
955*57266Smuller #else
956*57266Smuller 
957*57266Smuller /*
958*57266Smuller  * resub()
959*57266Smuller  *	apply the replacement to the matched expression. expand out the old
960*57266Smuller  * 	style ed(1) subexpression expansion.
961*57266Smuller  * Return:
962*57266Smuller  *	-1 if error, or the number of characters added to the destination.
963*57266Smuller  */
964*57266Smuller 
965*57266Smuller #if __STDC__
966*57266Smuller static int
967*57266Smuller resub(regex_t *rp, register regmatch_t *pm, char *src, char *dest,
968*57266Smuller 	register char *destend)
969*57266Smuller #else
970*57266Smuller static int
971*57266Smuller resub(rp, pm, src, dest, destend)
972*57266Smuller 	regex_t *rp;
973*57266Smuller 	register regmatch_t *pm;
974*57266Smuller 	char *src;
975*57266Smuller 	char *dest;
976*57266Smuller 	register char *destend;
977*57266Smuller #endif
978*57266Smuller {
979*57266Smuller 	register char *spt;
980*57266Smuller 	register char *dpt;
981*57266Smuller 	register char c;
982*57266Smuller 	register regmatch_t *pmpt;
983*57266Smuller 	register int len;
984*57266Smuller 	int subexcnt;
985*57266Smuller 
986*57266Smuller 	spt =  src;
987*57266Smuller 	dpt = dest;
988*57266Smuller 	subexcnt = rp->re_nsub;
989*57266Smuller 	while ((dpt < destend) && ((c = *spt++) != '\0')) {
990*57266Smuller 		/*
991*57266Smuller 		 * see if we just have an ordinary replacement character
992*57266Smuller 		 * or we refer to a subexpression.
993*57266Smuller 		 */
994*57266Smuller 		if (c == '&') {
995*57266Smuller 			pmpt = pm;
996*57266Smuller 		} else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
997*57266Smuller 			/*
998*57266Smuller 			 * make sure there is a subexpression as specified
999*57266Smuller 			 */
1000*57266Smuller 			if ((len = *spt++ - '0') > subexcnt)
1001*57266Smuller 				return(-1);
1002*57266Smuller 			pmpt = pm + len;
1003*57266Smuller 		} else {
1004*57266Smuller  			/*
1005*57266Smuller 			 * Ordinary character, just copy it
1006*57266Smuller 			 */
1007*57266Smuller  			if ((c == '\\') && ((*spt == '\\') || (*spt == '&')))
1008*57266Smuller  				c = *spt++;
1009*57266Smuller  			*dpt++ = c;
1010*57266Smuller 			continue;
1011*57266Smuller 		}
1012*57266Smuller 
1013*57266Smuller 		/*
1014*57266Smuller 		 * continue if the subexpression is bogus
1015*57266Smuller 		 */
1016*57266Smuller 		if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
1017*57266Smuller 		    ((len = pmpt->rm_eo - pmpt->rm_so) <= 0))
1018*57266Smuller 			continue;
1019*57266Smuller 
1020*57266Smuller 		/*
1021*57266Smuller 		 * copy the subexpression to the destination.
1022*57266Smuller 		 * fail if we run out of space or the match string is damaged
1023*57266Smuller 		 */
1024*57266Smuller 		if (len > (destend - dpt))
1025*57266Smuller 			len = destend - dpt;
1026*57266Smuller 		if (l_strncpy(dpt, src + pmpt->rm_so, len) != len)
1027*57266Smuller 			return(-1);
1028*57266Smuller 		dpt += len;
1029*57266Smuller 	}
1030*57266Smuller 	return(dpt - dest);
1031*57266Smuller }
1032*57266Smuller #endif
1033