pat_rep.c revision 8855
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 3. All advertising materials mentioning features or use of this software 181556Srgrimes * must display the following acknowledgement: 191556Srgrimes * This product includes software developed by the University of 201556Srgrimes * California, Berkeley and its contributors. 211556Srgrimes * 4. Neither the name of the University nor the names of its contributors 221556Srgrimes * may be used to endorse or promote products derived from this software 231556Srgrimes * without specific prior written permission. 241556Srgrimes * 251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351556Srgrimes * SUCH DAMAGE. 363044Sdg * 378855Srgrimes * $Id: pat_rep.c,v 1.3 1995/03/19 13:28:56 joerg Exp $ 381556Srgrimes */ 391556Srgrimes 401556Srgrimes#ifndef lint 411556Srgrimesstatic char sccsid[] = "@(#)pat_rep.c 8.2 (Berkeley) 4/18/94"; 421556Srgrimes#endif /* not lint */ 431556Srgrimes 441556Srgrimes#include <sys/types.h> 451556Srgrimes#include <sys/time.h> 461556Srgrimes#include <sys/stat.h> 471556Srgrimes#include <sys/param.h> 481556Srgrimes#include <stdio.h> 491556Srgrimes#include <ctype.h> 501556Srgrimes#include <string.h> 511556Srgrimes#include <unistd.h> 521556Srgrimes#include <stdlib.h> 531556Srgrimes#ifdef NET2_REGEX 541556Srgrimes#include <regexp.h> 551556Srgrimes#else 561556Srgrimes#include <regex.h> 571556Srgrimes#endif 581556Srgrimes#include "pax.h" 591556Srgrimes#include "pat_rep.h" 601556Srgrimes#include "extern.h" 611556Srgrimes 621556Srgrimes/* 631556Srgrimes * routines to handle pattern matching, name modification (regular expression 641556Srgrimes * substitution and interactive renames), and destination name modification for 651556Srgrimes * copy (-rw). Both file name and link names are adjusted as required in these 661556Srgrimes * routines. 671556Srgrimes */ 681556Srgrimes 691556Srgrimes#define MAXSUBEXP 10 /* max subexpressions, DO NOT CHANGE */ 701556Srgrimesstatic PATTERN *pathead = NULL; /* file pattern match list head */ 711556Srgrimesstatic PATTERN *pattail = NULL; /* file pattern match list tail */ 721556Srgrimesstatic REPLACE *rephead = NULL; /* replacement string list head */ 731556Srgrimesstatic REPLACE *reptail = NULL; /* replacement string list tail */ 741556Srgrimes 751556Srgrimesstatic int rep_name __P((char *, int *, int)); 761556Srgrimesstatic int tty_rename __P((register ARCHD *)); 771556Srgrimesstatic int fix_path __P((char *, int *, char *, int)); 781556Srgrimesstatic int fn_match __P((register char *, register char *, char **)); 791556Srgrimesstatic char * range_match __P((register char *, register int)); 801556Srgrimes#ifdef NET2_REGEX 811556Srgrimesstatic int resub __P((regexp *, char *, char *, register char *)); 821556Srgrimes#else 831556Srgrimesstatic int resub __P((regex_t *, regmatch_t *, char *, char *, char *)); 841556Srgrimes#endif 851556Srgrimes 861556Srgrimes/* 871556Srgrimes * rep_add() 881556Srgrimes * parses the -s replacement string; compiles the regular expression 891556Srgrimes * and stores the compiled value and it's replacement string together in 901556Srgrimes * replacement string list. Input to this function is of the form: 918855Srgrimes * /old/new/pg 921556Srgrimes * The first char in the string specifies the delimiter used by this 931556Srgrimes * replacement string. "Old" is a regular expression in "ed" format which 941556Srgrimes * is compiled by regcomp() and is applied to filenames. "new" is the 951556Srgrimes * substitution string; p and g are options flags for printing and global 961556Srgrimes * replacement (over the single filename) 971556Srgrimes * Return: 981556Srgrimes * 0 if a proper replacement string and regular expression was added to 991556Srgrimes * the list of replacement patterns; -1 otherwise. 1001556Srgrimes */ 1011556Srgrimes 1021556Srgrimes#if __STDC__ 1031556Srgrimesint 1041556Srgrimesrep_add(register char *str) 1051556Srgrimes#else 1061556Srgrimesint 1071556Srgrimesrep_add(str) 1081556Srgrimes register char *str; 1091556Srgrimes#endif 1101556Srgrimes{ 1111556Srgrimes register char *pt1; 1121556Srgrimes register char *pt2; 1131556Srgrimes register REPLACE *rep; 1141556Srgrimes# ifndef NET2_REGEX 1151556Srgrimes register int res; 1161556Srgrimes char rebuf[BUFSIZ]; 1171556Srgrimes# endif 1181556Srgrimes 1191556Srgrimes /* 1201556Srgrimes * throw out the bad parameters 1211556Srgrimes */ 1221556Srgrimes if ((str == NULL) || (*str == '\0')) { 1231556Srgrimes warn(1, "Empty replacement string"); 1241556Srgrimes return(-1); 1251556Srgrimes } 1261556Srgrimes 1271556Srgrimes /* 1281556Srgrimes * first character in the string specifies what the delimiter is for 1291556Srgrimes * this expression 1301556Srgrimes */ 1311556Srgrimes if ((pt1 = strchr(str+1, *str)) == NULL) { 1321556Srgrimes warn(1, "Invalid replacement string %s", str); 1331556Srgrimes return(-1); 1341556Srgrimes } 1351556Srgrimes 1361556Srgrimes /* 1371556Srgrimes * allocate space for the node that handles this replacement pattern 1381556Srgrimes * and split out the regular expression and try to compile it 1391556Srgrimes */ 1401556Srgrimes if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) { 1411556Srgrimes warn(1, "Unable to allocate memory for replacement string"); 1421556Srgrimes return(-1); 1431556Srgrimes } 1441556Srgrimes 1451556Srgrimes *pt1 = '\0'; 1461556Srgrimes# ifdef NET2_REGEX 1471556Srgrimes if ((rep->rcmp = regcomp(str+1)) == NULL) { 1481556Srgrimes# else 1491556Srgrimes if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) { 1501556Srgrimes regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf)); 1511556Srgrimes warn(1, "%s while compiling regular expression %s", rebuf, str); 1521556Srgrimes# endif 1531556Srgrimes (void)free((char *)rep); 1541556Srgrimes return(-1); 1551556Srgrimes } 1561556Srgrimes 1571556Srgrimes /* 1581556Srgrimes * put the delimiter back in case we need an error message and 1591556Srgrimes * locate the delimiter at the end of the replacement string 1601556Srgrimes * we then point the node at the new substitution string 1611556Srgrimes */ 1621556Srgrimes *pt1++ = *str; 1631556Srgrimes if ((pt2 = strchr(pt1, *str)) == NULL) { 1641556Srgrimes# ifdef NET2_REGEX 1651556Srgrimes (void)free((char *)rep->rcmp); 1661556Srgrimes# else 1671556Srgrimes regfree(&(rep->rcmp)); 1681556Srgrimes# endif 1691556Srgrimes (void)free((char *)rep); 1701556Srgrimes warn(1, "Invalid replacement string %s", str); 1711556Srgrimes return(-1); 1721556Srgrimes } 1731556Srgrimes 1741556Srgrimes *pt2 = '\0'; 1751556Srgrimes rep->nstr = pt1; 1761556Srgrimes pt1 = pt2++; 1771556Srgrimes rep->flgs = 0; 1781556Srgrimes 1791556Srgrimes /* 1801556Srgrimes * set the options if any 1811556Srgrimes */ 1821556Srgrimes while (*pt2 != '\0') { 1831556Srgrimes switch(*pt2) { 1841556Srgrimes case 'g': 1851556Srgrimes case 'G': 1861556Srgrimes rep->flgs |= GLOB; 1871556Srgrimes break; 1881556Srgrimes case 'p': 1891556Srgrimes case 'P': 1901556Srgrimes rep->flgs |= PRNT; 1911556Srgrimes break; 1921556Srgrimes default: 1931556Srgrimes# ifdef NET2_REGEX 1941556Srgrimes (void)free((char *)rep->rcmp); 1951556Srgrimes# else 1961556Srgrimes regfree(&(rep->rcmp)); 1971556Srgrimes# endif 1981556Srgrimes (void)free((char *)rep); 1991556Srgrimes *pt1 = *str; 2001556Srgrimes warn(1, "Invalid replacement string option %s", str); 2011556Srgrimes return(-1); 2021556Srgrimes } 2031556Srgrimes ++pt2; 2041556Srgrimes } 2051556Srgrimes 2061556Srgrimes /* 2071556Srgrimes * all done, link it in at the end 2081556Srgrimes */ 2091556Srgrimes rep->fow = NULL; 2101556Srgrimes if (rephead == NULL) { 2111556Srgrimes reptail = rephead = rep; 2121556Srgrimes return(0); 2131556Srgrimes } 2141556Srgrimes reptail->fow = rep; 2151556Srgrimes reptail = rep; 2161556Srgrimes return(0); 2171556Srgrimes} 2181556Srgrimes 2191556Srgrimes/* 2201556Srgrimes * pat_add() 2211556Srgrimes * add a pattern match to the pattern match list. Pattern matches are used 2221556Srgrimes * to select which archive members are extracted. (They appear as 2231556Srgrimes * arguments to pax in the list and read modes). If no patterns are 2241556Srgrimes * supplied to pax, all members in the archive will be selected (and the 2251556Srgrimes * pattern match list is empty). 2261556Srgrimes * Return: 2271556Srgrimes * 0 if the pattern was added to the list, -1 otherwise 2281556Srgrimes */ 2291556Srgrimes 2301556Srgrimes#if __STDC__ 2311556Srgrimesint 2321556Srgrimespat_add(char *str) 2331556Srgrimes#else 2341556Srgrimesint 2351556Srgrimespat_add(str) 2361556Srgrimes char *str; 2371556Srgrimes#endif 2381556Srgrimes{ 2391556Srgrimes register PATTERN *pt; 2401556Srgrimes 2411556Srgrimes /* 2421556Srgrimes * throw out the junk 2431556Srgrimes */ 2441556Srgrimes if ((str == NULL) || (*str == '\0')) { 2451556Srgrimes warn(1, "Empty pattern string"); 2461556Srgrimes return(-1); 2471556Srgrimes } 2481556Srgrimes 2491556Srgrimes /* 2501556Srgrimes * allocate space for the pattern and store the pattern. the pattern is 2511556Srgrimes * part of argv so do not bother to copy it, just point at it. Add the 2521556Srgrimes * node to the end of the pattern list 2531556Srgrimes */ 2541556Srgrimes if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) { 2551556Srgrimes warn(1, "Unable to allocate memory for pattern string"); 2561556Srgrimes return(-1); 2571556Srgrimes } 2581556Srgrimes 2591556Srgrimes pt->pstr = str; 2601556Srgrimes pt->pend = NULL; 2611556Srgrimes pt->plen = strlen(str); 2621556Srgrimes pt->fow = NULL; 2631556Srgrimes pt->flgs = 0; 2641556Srgrimes if (pathead == NULL) { 2651556Srgrimes pattail = pathead = pt; 2661556Srgrimes return(0); 2671556Srgrimes } 2681556Srgrimes pattail->fow = pt; 2691556Srgrimes pattail = pt; 2701556Srgrimes return(0); 2711556Srgrimes} 2721556Srgrimes 2731556Srgrimes/* 2741556Srgrimes * pat_chk() 2751556Srgrimes * complain if any the user supplied pattern did not result in a match to 2761556Srgrimes * a selected archive member. 2771556Srgrimes */ 2781556Srgrimes 2791556Srgrimes#if __STDC__ 2801556Srgrimesvoid 2811556Srgrimespat_chk(void) 2821556Srgrimes#else 2831556Srgrimesvoid 2841556Srgrimespat_chk() 2851556Srgrimes#endif 2861556Srgrimes{ 2871556Srgrimes register PATTERN *pt; 2881556Srgrimes register int wban = 0; 2891556Srgrimes 2901556Srgrimes /* 2911556Srgrimes * walk down the list checking the flags to make sure MTCH was set, 2921556Srgrimes * if not complain 2931556Srgrimes */ 2941556Srgrimes for (pt = pathead; pt != NULL; pt = pt->fow) { 2951556Srgrimes if (pt->flgs & MTCH) 2961556Srgrimes continue; 2971556Srgrimes if (!wban) { 2981556Srgrimes warn(1, "WARNING! These patterns were not matched:"); 2991556Srgrimes ++wban; 3001556Srgrimes } 3011556Srgrimes (void)fprintf(stderr, "%s\n", pt->pstr); 3021556Srgrimes } 3031556Srgrimes} 3041556Srgrimes 3051556Srgrimes/* 3061556Srgrimes * pat_sel() 3071556Srgrimes * the archive member which matches a pattern was selected. Mark the 3081556Srgrimes * pattern as having selected an archive member. arcn->pat points at the 3091556Srgrimes * pattern that was matched. arcn->pat is set in pat_match() 3101556Srgrimes * 3111556Srgrimes * NOTE: When the -c option is used, we are called when there was no match 3121556Srgrimes * by pat_match() (that means we did match before the inverted sense of 3131556Srgrimes * the logic). Now this seems really strange at first, but with -c we 3141556Srgrimes * need to keep track of those patterns that cause a archive member to NOT 3151556Srgrimes * be selected (it found an archive member with a specified pattern) 3161556Srgrimes * Return: 3171556Srgrimes * 0 if the pattern pointed at by arcn->pat was tagged as creating a 3181556Srgrimes * match, -1 otherwise. 3191556Srgrimes */ 3201556Srgrimes 3211556Srgrimes#if __STDC__ 3221556Srgrimesint 3231556Srgrimespat_sel(register ARCHD *arcn) 3241556Srgrimes#else 3251556Srgrimesint 3261556Srgrimespat_sel(arcn) 3271556Srgrimes register ARCHD *arcn; 3281556Srgrimes#endif 3291556Srgrimes{ 3301556Srgrimes register PATTERN *pt; 3311556Srgrimes register PATTERN **ppt; 3321556Srgrimes register int len; 3331556Srgrimes 3341556Srgrimes /* 3351556Srgrimes * if no patterns just return 3361556Srgrimes */ 3371556Srgrimes if ((pathead == NULL) || ((pt = arcn->pat) == NULL)) 3381556Srgrimes return(0); 3391556Srgrimes 3401556Srgrimes /* 3411556Srgrimes * when we are NOT limited to a single match per pattern mark the 3421556Srgrimes * pattern and return 3431556Srgrimes */ 3441556Srgrimes if (!nflag) { 3451556Srgrimes pt->flgs |= MTCH; 3461556Srgrimes return(0); 3471556Srgrimes } 3481556Srgrimes 3491556Srgrimes /* 3501556Srgrimes * we reach this point only when we allow a single selected match per 3518855Srgrimes * pattern, if the pattern matches a directory and we do not have -d 3521556Srgrimes * (dflag) we are done with this pattern. We may also be handed a file 3531556Srgrimes * in the subtree of a directory. in that case when we are operating 3541556Srgrimes * with -d, this pattern was already selected and we are done 3551556Srgrimes */ 3561556Srgrimes if (pt->flgs & DIR_MTCH) 3571556Srgrimes return(0); 3581556Srgrimes 3591556Srgrimes if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) { 3601556Srgrimes /* 3611556Srgrimes * ok we matched a directory and we are allowing 3621556Srgrimes * subtree matches but because of the -n only its children will 3631556Srgrimes * match. This is tagged as a DIR_MTCH type. 3641556Srgrimes * WATCH IT, the code assumes that pt->pend points 3651556Srgrimes * into arcn->name and arcn->name has not been modified. 3661556Srgrimes * If not we will have a big mess. Yup this is another kludge 3671556Srgrimes */ 3681556Srgrimes 3691556Srgrimes /* 3701556Srgrimes * if this was a prefix match, remove trailing part of path 3711556Srgrimes * so we can copy it. Future matches will be exact prefix match 3721556Srgrimes */ 3731556Srgrimes if (pt->pend != NULL) 3741556Srgrimes *pt->pend = '\0'; 3758855Srgrimes 3761556Srgrimes if ((pt->pstr = strdup(arcn->name)) == NULL) { 3771556Srgrimes warn(1, "Pattern select out of memory"); 3781556Srgrimes if (pt->pend != NULL) 3791556Srgrimes *pt->pend = '/'; 3801556Srgrimes pt->pend = NULL; 3811556Srgrimes return(-1); 3821556Srgrimes } 3831556Srgrimes 3841556Srgrimes /* 3851556Srgrimes * put the trailing / back in the source string 3861556Srgrimes */ 3871556Srgrimes if (pt->pend != NULL) { 3881556Srgrimes *pt->pend = '/'; 3891556Srgrimes pt->pend = NULL; 3901556Srgrimes } 3911556Srgrimes pt->plen = strlen(pt->pstr); 3921556Srgrimes 3931556Srgrimes /* 3941556Srgrimes * strip off any trailing /, this should really never happen 3951556Srgrimes */ 3961556Srgrimes len = pt->plen - 1; 3971556Srgrimes if (*(pt->pstr + len) == '/') { 3981556Srgrimes *(pt->pstr + len) = '\0'; 3991556Srgrimes pt->plen = len; 4008855Srgrimes } 4011556Srgrimes pt->flgs = DIR_MTCH | MTCH; 4021556Srgrimes arcn->pat = pt; 4031556Srgrimes return(0); 4041556Srgrimes } 4051556Srgrimes 4061556Srgrimes /* 4071556Srgrimes * we are then done with this pattern, so we delete it from the list 4081556Srgrimes * because it can never be used for another match. 4091556Srgrimes * Seems kind of strange to do for a -c, but the pax spec is really 4101556Srgrimes * vague on the interaction of -c -n and -d. We assume that when -c 4111556Srgrimes * and the pattern rejects a member (i.e. it matched it) it is done. 4121556Srgrimes * In effect we place the order of the flags as having -c last. 4131556Srgrimes */ 4141556Srgrimes pt = pathead; 4151556Srgrimes ppt = &pathead; 4161556Srgrimes while ((pt != NULL) && (pt != arcn->pat)) { 4171556Srgrimes ppt = &(pt->fow); 4181556Srgrimes pt = pt->fow; 4191556Srgrimes } 4201556Srgrimes 4211556Srgrimes if (pt == NULL) { 4221556Srgrimes /* 4231556Srgrimes * should never happen.... 4241556Srgrimes */ 4251556Srgrimes warn(1, "Pattern list inconsistant"); 4261556Srgrimes return(-1); 4271556Srgrimes } 4281556Srgrimes *ppt = pt->fow; 4291556Srgrimes (void)free((char *)pt); 4301556Srgrimes arcn->pat = NULL; 4311556Srgrimes return(0); 4321556Srgrimes} 4331556Srgrimes 4341556Srgrimes/* 4351556Srgrimes * pat_match() 4361556Srgrimes * see if this archive member matches any supplied pattern, if a match 4371556Srgrimes * is found, arcn->pat is set to point at the potential pattern. Later if 4381556Srgrimes * this archive member is "selected" we process and mark the pattern as 4391556Srgrimes * one which matched a selected archive member (see pat_sel()) 4401556Srgrimes * Return: 4418855Srgrimes * 0 if this archive member should be processed, 1 if it should be 4421556Srgrimes * skipped and -1 if we are done with all patterns (and pax should quit 4431556Srgrimes * looking for more members) 4441556Srgrimes */ 4451556Srgrimes 4461556Srgrimes#if __STDC__ 4471556Srgrimesint 4481556Srgrimespat_match(register ARCHD *arcn) 4491556Srgrimes#else 4501556Srgrimesint 4511556Srgrimespat_match(arcn) 4521556Srgrimes register ARCHD *arcn; 4531556Srgrimes#endif 4541556Srgrimes{ 4551556Srgrimes register PATTERN *pt; 4561556Srgrimes 4571556Srgrimes arcn->pat = NULL; 4581556Srgrimes 4591556Srgrimes /* 4601556Srgrimes * if there are no more patterns and we have -n (and not -c) we are 4611556Srgrimes * done. otherwise with no patterns to match, matches all 4621556Srgrimes */ 4631556Srgrimes if (pathead == NULL) { 4641556Srgrimes if (nflag && !cflag) 4651556Srgrimes return(-1); 4661556Srgrimes return(0); 4671556Srgrimes } 4681556Srgrimes 4691556Srgrimes /* 4701556Srgrimes * have to search down the list one at a time looking for a match. 4711556Srgrimes */ 4721556Srgrimes pt = pathead; 4731556Srgrimes while (pt != NULL) { 4741556Srgrimes /* 4751556Srgrimes * check for a file name match unless we have DIR_MTCH set in 4761556Srgrimes * this pattern then we want a prefix match 4771556Srgrimes */ 4781556Srgrimes if (pt->flgs & DIR_MTCH) { 4791556Srgrimes /* 4801556Srgrimes * this pattern was matched before to a directory 4811556Srgrimes * as we must have -n set for this (but not -d). We can 4821556Srgrimes * only match CHILDREN of that directory so we must use 4831556Srgrimes * an exact prefix match (no wildcards). 4841556Srgrimes */ 4851556Srgrimes if ((arcn->name[pt->plen] == '/') && 4861556Srgrimes (strncmp(pt->pstr, arcn->name, pt->plen) == 0)) 4871556Srgrimes break; 4881556Srgrimes } else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0) 4891556Srgrimes break; 4901556Srgrimes pt = pt->fow; 4911556Srgrimes } 4921556Srgrimes 4931556Srgrimes /* 4941556Srgrimes * return the result, remember that cflag (-c) inverts the sense of a 4951556Srgrimes * match 4961556Srgrimes */ 4971556Srgrimes if (pt == NULL) 4981556Srgrimes return(cflag ? 0 : 1); 4991556Srgrimes 5001556Srgrimes /* 5011556Srgrimes * we had a match, now when we invert the sense (-c) we reject this 5021556Srgrimes * member. However we have to tag the pattern a being successful, (in a 5031556Srgrimes * match, not in selecting a archive member) so we call pat_sel() here. 5041556Srgrimes */ 5051556Srgrimes arcn->pat = pt; 5061556Srgrimes if (!cflag) 5071556Srgrimes return(0); 5081556Srgrimes 5091556Srgrimes if (pat_sel(arcn) < 0) 5101556Srgrimes return(-1); 5111556Srgrimes arcn->pat = NULL; 5121556Srgrimes return(1); 5131556Srgrimes} 5141556Srgrimes 5151556Srgrimes/* 5161556Srgrimes * fn_match() 5171556Srgrimes * Return: 5188855Srgrimes * 0 if this archive member should be processed, 1 if it should be 5191556Srgrimes * skipped and -1 if we are done with all patterns (and pax should quit 5201556Srgrimes * looking for more members) 5211556Srgrimes * Note: *pend may be changed to show where the prefix ends. 5221556Srgrimes */ 5231556Srgrimes 5241556Srgrimes#if __STDC__ 5251556Srgrimesstatic int 5261556Srgrimesfn_match(register char *pattern, register char *string, char **pend) 5271556Srgrimes#else 5281556Srgrimesstatic int 5291556Srgrimesfn_match(pattern, string, pend) 5301556Srgrimes register char *pattern; 5311556Srgrimes register char *string; 5321556Srgrimes char **pend; 5331556Srgrimes#endif 5341556Srgrimes{ 5351556Srgrimes register char c; 5361556Srgrimes char test; 5371556Srgrimes 5381556Srgrimes *pend = NULL; 5391556Srgrimes for (;;) { 5401556Srgrimes switch (c = *pattern++) { 5411556Srgrimes case '\0': 5421556Srgrimes /* 5431556Srgrimes * Ok we found an exact match 5441556Srgrimes */ 5451556Srgrimes if (*string == '\0') 5461556Srgrimes return(0); 5471556Srgrimes 5481556Srgrimes /* 5491556Srgrimes * Check if it is a prefix match 5501556Srgrimes */ 5511556Srgrimes if ((dflag == 1) || (*string != '/')) 5521556Srgrimes return(-1); 5531556Srgrimes 5541556Srgrimes /* 5551556Srgrimes * It is a prefix match, remember where the trailing 5561556Srgrimes * / is located 5571556Srgrimes */ 5581556Srgrimes *pend = string; 5591556Srgrimes return(0); 5601556Srgrimes case '?': 5611556Srgrimes if ((test = *string++) == '\0') 5621556Srgrimes return (-1); 5631556Srgrimes break; 5641556Srgrimes case '*': 5651556Srgrimes c = *pattern; 5661556Srgrimes /* 5678855Srgrimes * Collapse multiple *'s. 5681556Srgrimes */ 5691556Srgrimes while (c == '*') 5701556Srgrimes c = *++pattern; 5711556Srgrimes 5721556Srgrimes /* 5731556Srgrimes * Optimized hack for pattern with a * at the end 5741556Srgrimes */ 5751556Srgrimes if (c == '\0') 5761556Srgrimes return (0); 5771556Srgrimes 5781556Srgrimes /* 5791556Srgrimes * General case, use recursion. 5801556Srgrimes */ 5811556Srgrimes while ((test = *string) != '\0') { 5821556Srgrimes if (!fn_match(pattern, string, pend)) 5831556Srgrimes return (0); 5841556Srgrimes ++string; 5851556Srgrimes } 5861556Srgrimes return (-1); 5871556Srgrimes case '[': 5881556Srgrimes /* 5891556Srgrimes * range match 5901556Srgrimes */ 5911556Srgrimes if (((test = *string++) == '\0') || 5921556Srgrimes ((pattern = range_match(pattern, test)) == NULL)) 5931556Srgrimes return (-1); 5941556Srgrimes break; 5951556Srgrimes case '\\': 5961556Srgrimes default: 5971556Srgrimes if (c != *string++) 5981556Srgrimes return (-1); 5991556Srgrimes break; 6001556Srgrimes } 6011556Srgrimes } 6021556Srgrimes /* NOTREACHED */ 6031556Srgrimes} 6041556Srgrimes 6051556Srgrimes#ifdef __STDC__ 6061556Srgrimesstatic char * 6071556Srgrimesrange_match(register char *pattern, register int test) 6081556Srgrimes#else 6091556Srgrimesstatic char * 6101556Srgrimesrange_match(pattern, test) 6111556Srgrimes register char *pattern; 6121556Srgrimes register int test; 6131556Srgrimes#endif 6141556Srgrimes{ 6151556Srgrimes register char c; 6161556Srgrimes register char c2; 6171556Srgrimes int negate; 6181556Srgrimes int ok = 0; 6191556Srgrimes 6207165Sjoerg if ((negate = (*pattern == '!'))) 6211556Srgrimes ++pattern; 6221556Srgrimes 6231556Srgrimes while ((c = *pattern++) != ']') { 6241556Srgrimes /* 6251556Srgrimes * Illegal pattern 6261556Srgrimes */ 6271556Srgrimes if (c == '\0') 6281556Srgrimes return (NULL); 6291556Srgrimes 6301556Srgrimes if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') && 6311556Srgrimes (c2 != ']')) { 6321556Srgrimes if ((c <= test) && (test <= c2)) 6331556Srgrimes ok = 1; 6341556Srgrimes pattern += 2; 6351556Srgrimes } else if (c == test) 6361556Srgrimes ok = 1; 6371556Srgrimes } 6381556Srgrimes return (ok == negate ? NULL : pattern); 6391556Srgrimes} 6401556Srgrimes 6411556Srgrimes/* 6421556Srgrimes * mod_name() 6431556Srgrimes * modify a selected file name. first attempt to apply replacement string 6441556Srgrimes * expressions, then apply interactive file rename. We apply replacement 6451556Srgrimes * string expressions to both filenames and file links (if we didn't the 6461556Srgrimes * links would point to the wrong place, and we could never be able to 6471556Srgrimes * move an archive that has a file link in it). When we rename files 6481556Srgrimes * interactively, we store that mapping (old name to user input name) so 6491556Srgrimes * if we spot any file links to the old file name in the future, we will 6501556Srgrimes * know exactly how to fix the file link. 6511556Srgrimes * Return: 6528855Srgrimes * 0 continue to process file, 1 skip this file, -1 pax is finished 6531556Srgrimes */ 6541556Srgrimes 6551556Srgrimes#if __STDC__ 6561556Srgrimesint 6571556Srgrimesmod_name(register ARCHD *arcn) 6581556Srgrimes#else 6591556Srgrimesint 6601556Srgrimesmod_name(arcn) 6611556Srgrimes register ARCHD *arcn; 6621556Srgrimes#endif 6631556Srgrimes{ 6641556Srgrimes register int res = 0; 6651556Srgrimes 6661556Srgrimes /* 6671556Srgrimes * IMPORTANT: We have a problem. what do we do with symlinks? 6681556Srgrimes * Modifying a hard link name makes sense, as we know the file it 6691556Srgrimes * points at should have been seen already in the archive (and if it 6701556Srgrimes * wasn't seen because of a read error or a bad archive, we lose 6711556Srgrimes * anyway). But there are no such requirements for symlinks. On one 6721556Srgrimes * hand the symlink that refers to a file in the archive will have to 6731556Srgrimes * be modified to so it will still work at its new location in the 6741556Srgrimes * file system. On the other hand a symlink that points elsewhere (and 6751556Srgrimes * should continue to do so) should not be modified. There is clearly 6761556Srgrimes * no perfect solution here. So we handle them like hardlinks. Clearly 6771556Srgrimes * a replacement made by the interactive rename mapping is very likely 6781556Srgrimes * to be correct since it applies to a single file and is an exact 6791556Srgrimes * match. The regular expression replacements are a little harder to 6801556Srgrimes * justify though. We claim that the symlink name is only likely 6811556Srgrimes * to be replaced when it points within the file tree being moved and 6821556Srgrimes * in that case it should be modified. what we really need to do is to 6831556Srgrimes * call an oracle here. :) 6841556Srgrimes */ 6851556Srgrimes if (rephead != NULL) { 6861556Srgrimes /* 6871556Srgrimes * we have replacement strings, modify the name and the link 6881556Srgrimes * name if any. 6891556Srgrimes */ 6901556Srgrimes if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0) 6911556Srgrimes return(res); 6921556Srgrimes 6931556Srgrimes if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 6941556Srgrimes (arcn->type == PAX_HRG)) && 6951556Srgrimes ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0)) 6961556Srgrimes return(res); 6971556Srgrimes } 6981556Srgrimes 6991556Srgrimes if (iflag) { 7001556Srgrimes /* 7011556Srgrimes * perform interactive file rename, then map the link if any 7021556Srgrimes */ 7031556Srgrimes if ((res = tty_rename(arcn)) != 0) 7041556Srgrimes return(res); 7051556Srgrimes if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || 7061556Srgrimes (arcn->type == PAX_HRG)) 7071556Srgrimes sub_name(arcn->ln_name, &(arcn->ln_nlen)); 7081556Srgrimes } 7091556Srgrimes return(res); 7101556Srgrimes} 7111556Srgrimes 7121556Srgrimes/* 7131556Srgrimes * tty_rename() 7141556Srgrimes * Prompt the user for a replacement file name. A "." keeps the old name, 7151556Srgrimes * a empty line skips the file, and an EOF on reading the tty, will cause 7161556Srgrimes * pax to stop processing and exit. Otherwise the file name input, replaces 7171556Srgrimes * the old one. 7181556Srgrimes * Return: 7191556Srgrimes * 0 process this file, 1 skip this file, -1 we need to exit pax 7201556Srgrimes */ 7211556Srgrimes 7221556Srgrimes#if __STDC__ 7231556Srgrimesstatic int 7241556Srgrimestty_rename(register ARCHD *arcn) 7251556Srgrimes#else 7261556Srgrimesstatic int 7271556Srgrimestty_rename(arcn) 7281556Srgrimes register ARCHD *arcn; 7291556Srgrimes#endif 7301556Srgrimes{ 7311556Srgrimes char tmpname[PAXPATHLEN+2]; 7321556Srgrimes int res; 7331556Srgrimes 7341556Srgrimes /* 7351556Srgrimes * prompt user for the replacement name for a file, keep trying until 7361556Srgrimes * we get some reasonable input. Archives may have more than one file 7371556Srgrimes * on them with the same name (from updates etc). We print verbose info 7381556Srgrimes * on the file so the user knows what is up. 7391556Srgrimes */ 7401556Srgrimes tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0); 7411556Srgrimes 7421556Srgrimes for (;;) { 7431556Srgrimes ls_tty(arcn); 7441556Srgrimes tty_prnt("Input new name, or a \".\" to keep the old name, "); 7451556Srgrimes tty_prnt("or a \"return\" to skip this file.\n"); 7461556Srgrimes tty_prnt("Input > "); 7471556Srgrimes if (tty_read(tmpname, sizeof(tmpname)) < 0) 7481556Srgrimes return(-1); 7491556Srgrimes if (strcmp(tmpname, "..") == 0) { 7501556Srgrimes tty_prnt("Try again, illegal file name: ..\n"); 7511556Srgrimes continue; 7521556Srgrimes } 7531556Srgrimes if (strlen(tmpname) > PAXPATHLEN) { 7541556Srgrimes tty_prnt("Try again, file name too long\n"); 7551556Srgrimes continue; 7561556Srgrimes } 7571556Srgrimes break; 7581556Srgrimes } 7591556Srgrimes 7601556Srgrimes /* 7611556Srgrimes * empty file name, skips this file. a "." leaves it alone 7621556Srgrimes */ 7631556Srgrimes if (tmpname[0] == '\0') { 7641556Srgrimes tty_prnt("Skipping file.\n"); 7651556Srgrimes return(1); 7661556Srgrimes } 7671556Srgrimes if ((tmpname[0] == '.') && (tmpname[1] == '\0')) { 7681556Srgrimes tty_prnt("Processing continues, name unchanged.\n"); 7691556Srgrimes return(0); 7701556Srgrimes } 7711556Srgrimes 7721556Srgrimes /* 7731556Srgrimes * ok the name changed. We may run into links that point at this 7741556Srgrimes * file later. we have to remember where the user sent the file 7751556Srgrimes * in order to repair any links. 7761556Srgrimes */ 7771556Srgrimes tty_prnt("Processing continues, name changed to: %s\n", tmpname); 7781556Srgrimes res = add_name(arcn->name, arcn->nlen, tmpname); 7791556Srgrimes arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1); 7801556Srgrimes if (res < 0) 7811556Srgrimes return(-1); 7821556Srgrimes return(0); 7831556Srgrimes} 7841556Srgrimes 7851556Srgrimes/* 7861556Srgrimes * set_dest() 7871556Srgrimes * fix up the file name and the link name (if any) so this file will land 7881556Srgrimes * in the destination directory (used during copy() -rw). 7891556Srgrimes * Return: 7901556Srgrimes * 0 if ok, -1 if failure (name too long) 7911556Srgrimes */ 7921556Srgrimes 7931556Srgrimes#if __STDC__ 7941556Srgrimesint 7951556Srgrimesset_dest(register ARCHD *arcn, char *dest_dir, int dir_len) 7961556Srgrimes#else 7971556Srgrimesint 7981556Srgrimesset_dest(arcn, dest_dir, dir_len) 7991556Srgrimes register ARCHD *arcn; 8001556Srgrimes char *dest_dir; 8011556Srgrimes int dir_len; 8021556Srgrimes#endif 8031556Srgrimes{ 8041556Srgrimes if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0) 8051556Srgrimes return(-1); 8061556Srgrimes 8071556Srgrimes /* 8081556Srgrimes * It is really hard to deal with symlinks here, we cannot be sure 8091556Srgrimes * if the name they point was moved (or will be moved). It is best to 8101556Srgrimes * leave them alone. 8111556Srgrimes */ 8121556Srgrimes if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG)) 8131556Srgrimes return(0); 8141556Srgrimes 8151556Srgrimes if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0) 8161556Srgrimes return(-1); 8171556Srgrimes return(0); 8181556Srgrimes} 8191556Srgrimes 8201556Srgrimes/* 8211556Srgrimes * fix_path 8221556Srgrimes * concatenate dir_name and or_name and store the result in or_name (if 8231556Srgrimes * it fits). This is one ugly function. 8241556Srgrimes * Return: 8251556Srgrimes * 0 if ok, -1 if the final name is too long 8261556Srgrimes */ 8271556Srgrimes 8281556Srgrimes#if __STDC__ 8291556Srgrimesstatic int 8301556Srgrimesfix_path( char *or_name, int *or_len, char *dir_name, int dir_len) 8311556Srgrimes#else 8321556Srgrimesstatic int 8331556Srgrimesfix_path(or_name, or_len, dir_name, dir_len) 8341556Srgrimes char *or_name; 8351556Srgrimes int *or_len; 8361556Srgrimes char *dir_name; 8371556Srgrimes int dir_len; 8381556Srgrimes#endif 8391556Srgrimes{ 8401556Srgrimes register char *src; 8411556Srgrimes register char *dest; 8421556Srgrimes register char *start; 8431556Srgrimes int len; 8441556Srgrimes 8451556Srgrimes /* 8461556Srgrimes * we shift the or_name to the right enough to tack in the dir_name 8471556Srgrimes * at the front. We make sure we have enough space for it all before 8481556Srgrimes * we start. since dest always ends in a slash, we skip of or_name 8491556Srgrimes * if it also starts with one. 8501556Srgrimes */ 8511556Srgrimes start = or_name; 8521556Srgrimes src = start + *or_len; 8531556Srgrimes dest = src + dir_len; 8541556Srgrimes if (*start == '/') { 8551556Srgrimes ++start; 8561556Srgrimes --dest; 8571556Srgrimes } 8581556Srgrimes if ((len = dest - or_name) > PAXPATHLEN) { 8591556Srgrimes warn(1, "File name %s/%s, too long", dir_name, start); 8601556Srgrimes return(-1); 8611556Srgrimes } 8621556Srgrimes *or_len = len; 8631556Srgrimes 8641556Srgrimes /* 8658855Srgrimes * enough space, shift 8661556Srgrimes */ 8671556Srgrimes while (src >= start) 8681556Srgrimes *dest-- = *src--; 8691556Srgrimes src = dir_name + dir_len - 1; 8701556Srgrimes 8711556Srgrimes /* 8721556Srgrimes * splice in the destination directory name 8731556Srgrimes */ 8741556Srgrimes while (src >= dir_name) 8751556Srgrimes *dest-- = *src--; 8761556Srgrimes 8771556Srgrimes *(or_name + len) = '\0'; 8781556Srgrimes return(0); 8791556Srgrimes} 8801556Srgrimes 8811556Srgrimes/* 8821556Srgrimes * rep_name() 8831556Srgrimes * walk down the list of replacement strings applying each one in order. 8841556Srgrimes * when we find one with a successful substitution, we modify the name 8851556Srgrimes * as specified. if required, we print the results. if the resulting name 8861556Srgrimes * is empty, we will skip this archive member. We use the regexp(3) 8871556Srgrimes * routines (regexp() ought to win a prize as having the most cryptic 8881556Srgrimes * library function manual page). 8891556Srgrimes * --Parameters-- 8901556Srgrimes * name is the file name we are going to apply the regular expressions to 8911556Srgrimes * (and may be modified) 8921556Srgrimes * nlen is the length of this name (and is modified to hold the length of 8931556Srgrimes * the final string). 8941556Srgrimes * prnt is a flag that says whether to print the final result. 8951556Srgrimes * Return: 8961556Srgrimes * 0 if substitution was successful, 1 if we are to skip the file (the name 8971556Srgrimes * ended up empty) 8981556Srgrimes */ 8991556Srgrimes 9001556Srgrimes#if __STDC__ 9011556Srgrimesstatic int 9021556Srgrimesrep_name(char *name, int *nlen, int prnt) 9031556Srgrimes#else 9041556Srgrimesstatic int 9051556Srgrimesrep_name(name, nlen, prnt) 9061556Srgrimes char *name; 9071556Srgrimes int *nlen; 9081556Srgrimes int prnt; 9091556Srgrimes#endif 9101556Srgrimes{ 9111556Srgrimes register REPLACE *pt; 9121556Srgrimes register char *inpt; 9131556Srgrimes register char *outpt; 9141556Srgrimes register char *endpt; 9151556Srgrimes register char *rpt; 9161556Srgrimes register int found = 0; 9171556Srgrimes register int res; 9181556Srgrimes# ifndef NET2_REGEX 9191556Srgrimes regmatch_t pm[MAXSUBEXP]; 9201556Srgrimes# endif 9211556Srgrimes char nname[PAXPATHLEN+1]; /* final result of all replacements */ 9221556Srgrimes char buf1[PAXPATHLEN+1]; /* where we work on the name */ 9231556Srgrimes 9241556Srgrimes /* 9251556Srgrimes * copy the name into buf1, where we will work on it. We need to keep 9261556Srgrimes * the orig string around so we can print out the result of the final 9271556Srgrimes * replacement. We build up the final result in nname. inpt points at 9281556Srgrimes * the string we apply the regular expression to. prnt is used to 9291556Srgrimes * suppress printing when we handle replacements on the link field 9301556Srgrimes * (the user already saw that substitution go by) 9311556Srgrimes */ 9321556Srgrimes pt = rephead; 9331556Srgrimes (void)strcpy(buf1, name); 9341556Srgrimes inpt = buf1; 9351556Srgrimes outpt = nname; 9361556Srgrimes endpt = outpt + PAXPATHLEN; 9371556Srgrimes 9381556Srgrimes /* 9391556Srgrimes * try each replacement string in order 9401556Srgrimes */ 9411556Srgrimes while (pt != NULL) { 9421556Srgrimes do { 9431556Srgrimes /* 9441556Srgrimes * check for a successful substitution, if not go to 9451556Srgrimes * the next pattern, or cleanup if we were global 9461556Srgrimes */ 9471556Srgrimes# ifdef NET2_REGEX 9481556Srgrimes if (regexec(pt->rcmp, inpt) == 0) 9491556Srgrimes# else 9501556Srgrimes if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0) 9511556Srgrimes# endif 9521556Srgrimes break; 9531556Srgrimes 9541556Srgrimes /* 9551556Srgrimes * ok we found one. We have three parts, the prefix 9561556Srgrimes * which did not match, the section that did and the 9571556Srgrimes * tail (that also did not match). Copy the prefix to 9581556Srgrimes * the final output buffer (watching to make sure we 9591556Srgrimes * do not create a string too long). 9601556Srgrimes */ 9611556Srgrimes found = 1; 9621556Srgrimes# ifdef NET2_REGEX 9631556Srgrimes rpt = pt->rcmp->startp[0]; 9641556Srgrimes# else 9651556Srgrimes rpt = inpt + pm[0].rm_so; 9661556Srgrimes# endif 9671556Srgrimes 9681556Srgrimes while ((inpt < rpt) && (outpt < endpt)) 9691556Srgrimes *outpt++ = *inpt++; 9701556Srgrimes if (outpt == endpt) 9711556Srgrimes break; 9721556Srgrimes 9731556Srgrimes /* 9741556Srgrimes * for the second part (which matched the regular 9751556Srgrimes * expression) apply the substitution using the 9761556Srgrimes * replacement string and place it the prefix in the 9771556Srgrimes * final output. If we have problems, skip it. 9781556Srgrimes */ 9791556Srgrimes# ifdef NET2_REGEX 9801556Srgrimes if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) { 9811556Srgrimes# else 9821556Srgrimes if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt)) 9831556Srgrimes < 0) { 9841556Srgrimes# endif 9851556Srgrimes if (prnt) 9861556Srgrimes warn(1, "Replacement name error %s", 9871556Srgrimes name); 9881556Srgrimes return(1); 9891556Srgrimes } 9901556Srgrimes outpt += res; 9911556Srgrimes 9921556Srgrimes /* 9931556Srgrimes * we set up to look again starting at the first 9941556Srgrimes * character in the tail (of the input string right 9951556Srgrimes * after the last character matched by the regular 9961556Srgrimes * expression (inpt always points at the first char in 9971556Srgrimes * the string to process). If we are not doing a global 9981556Srgrimes * substitution, we will use inpt to copy the tail to 9991556Srgrimes * the final result. Make sure we do not overrun the 10001556Srgrimes * output buffer 10011556Srgrimes */ 10021556Srgrimes# ifdef NET2_REGEX 10031556Srgrimes inpt = pt->rcmp->endp[0]; 10041556Srgrimes# else 10051556Srgrimes inpt += pm[0].rm_eo; 10061556Srgrimes# endif 10071556Srgrimes 10081556Srgrimes if ((outpt == endpt) || (*inpt == '\0')) 10091556Srgrimes break; 10101556Srgrimes 10111556Srgrimes /* 10121556Srgrimes * if the user wants global we keep trying to 10131556Srgrimes * substitute until it fails, then we are done. 10141556Srgrimes */ 10151556Srgrimes } while (pt->flgs & GLOB); 10161556Srgrimes 10178855Srgrimes if (found) 10181556Srgrimes break; 10191556Srgrimes 10201556Srgrimes /* 10211556Srgrimes * a successful substitution did NOT occur, try the next one 10221556Srgrimes */ 10231556Srgrimes pt = pt->fow; 10241556Srgrimes } 10251556Srgrimes 10261556Srgrimes if (found) { 10271556Srgrimes /* 10281556Srgrimes * we had a substitution, copy the last tail piece (if there is 10291556Srgrimes * room) to the final result 10301556Srgrimes */ 10311556Srgrimes while ((outpt < endpt) && (*inpt != '\0')) 10321556Srgrimes *outpt++ = *inpt++; 10331556Srgrimes 10341556Srgrimes *outpt = '\0'; 10351556Srgrimes if ((outpt == endpt) && (*inpt != '\0')) { 10361556Srgrimes if (prnt) 10371556Srgrimes warn(1,"Replacement name too long %s >> %s", 10381556Srgrimes name, nname); 10391556Srgrimes return(1); 10408855Srgrimes } 10411556Srgrimes 10421556Srgrimes /* 10431556Srgrimes * inform the user of the result if wanted 10441556Srgrimes */ 10451556Srgrimes if (prnt && (pt->flgs & PRNT)) { 10461556Srgrimes if (*nname == '\0') 10471556Srgrimes (void)fprintf(stderr,"%s >> <empty string>\n", 10481556Srgrimes name); 10498855Srgrimes else 10501556Srgrimes (void)fprintf(stderr,"%s >> %s\n", name, nname); 10511556Srgrimes } 10521556Srgrimes 10531556Srgrimes /* 10541556Srgrimes * if empty inform the caller this file is to be skipped 10551556Srgrimes * otherwise copy the new name over the orig name and return 10561556Srgrimes */ 10578855Srgrimes if (*nname == '\0') 10581556Srgrimes return(1); 10591556Srgrimes *nlen = l_strncpy(name, nname, PAXPATHLEN + 1); 10601556Srgrimes } 10611556Srgrimes return(0); 10621556Srgrimes} 10631556Srgrimes 10641556Srgrimes#ifdef NET2_REGEX 10651556Srgrimes/* 10661556Srgrimes * resub() 10671556Srgrimes * apply the replacement to the matched expression. expand out the old 10681556Srgrimes * style ed(1) subexpression expansion. 10691556Srgrimes * Return: 10701556Srgrimes * -1 if error, or the number of characters added to the destination. 10711556Srgrimes */ 10721556Srgrimes 10731556Srgrimes#if __STDC__ 10741556Srgrimesstatic int 10751556Srgrimesresub(regexp *prog, char *src, char *dest, register char *destend) 10761556Srgrimes#else 10771556Srgrimesstatic int 10781556Srgrimesresub(prog, src, dest, destend) 10791556Srgrimes regexp *prog; 10801556Srgrimes char *src; 10811556Srgrimes char *dest; 10821556Srgrimes register char *destend; 10831556Srgrimes#endif 10841556Srgrimes{ 10851556Srgrimes register char *spt; 10861556Srgrimes register char *dpt; 10871556Srgrimes register char c; 10881556Srgrimes register int no; 10891556Srgrimes register int len; 10901556Srgrimes 10911556Srgrimes spt = src; 10921556Srgrimes dpt = dest; 10931556Srgrimes while ((dpt < destend) && ((c = *spt++) != '\0')) { 10941556Srgrimes if (c == '&') 10951556Srgrimes no = 0; 10961556Srgrimes else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) 10971556Srgrimes no = *spt++ - '0'; 10981556Srgrimes else { 10991556Srgrimes if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) 11001556Srgrimes c = *spt++; 11011556Srgrimes *dpt++ = c; 11021556Srgrimes continue; 11031556Srgrimes } 11041556Srgrimes if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) || 11051556Srgrimes ((len = prog->endp[no] - prog->startp[no]) <= 0)) 11061556Srgrimes continue; 11071556Srgrimes 11081556Srgrimes /* 11091556Srgrimes * copy the subexpression to the destination. 11101556Srgrimes * fail if we run out of space or the match string is damaged 11111556Srgrimes */ 11121556Srgrimes if (len > (destend - dpt)) 11131556Srgrimes len = destend - dpt; 11141556Srgrimes if (l_strncpy(dpt, prog->startp[no], len) != len) 11151556Srgrimes return(-1); 11161556Srgrimes dpt += len; 11171556Srgrimes } 11181556Srgrimes return(dpt - dest); 11191556Srgrimes} 11201556Srgrimes 11211556Srgrimes#else 11221556Srgrimes 11231556Srgrimes/* 11241556Srgrimes * resub() 11251556Srgrimes * apply the replacement to the matched expression. expand out the old 11261556Srgrimes * style ed(1) subexpression expansion. 11271556Srgrimes * Return: 11281556Srgrimes * -1 if error, or the number of characters added to the destination. 11291556Srgrimes */ 11301556Srgrimes 11311556Srgrimes#if __STDC__ 11321556Srgrimesstatic int 11331556Srgrimesresub(regex_t *rp, register regmatch_t *pm, char *src, char *dest, 11341556Srgrimes register char *destend) 11351556Srgrimes#else 11361556Srgrimesstatic int 11371556Srgrimesresub(rp, pm, src, dest, destend) 11381556Srgrimes regex_t *rp; 11391556Srgrimes register regmatch_t *pm; 11401556Srgrimes char *src; 11411556Srgrimes char *dest; 11421556Srgrimes register char *destend; 11431556Srgrimes#endif 11441556Srgrimes{ 11451556Srgrimes register char *spt; 11461556Srgrimes register char *dpt; 11471556Srgrimes register char c; 11481556Srgrimes register regmatch_t *pmpt; 11491556Srgrimes register int len; 11501556Srgrimes int subexcnt; 11511556Srgrimes 11521556Srgrimes spt = src; 11531556Srgrimes dpt = dest; 11541556Srgrimes subexcnt = rp->re_nsub; 11551556Srgrimes while ((dpt < destend) && ((c = *spt++) != '\0')) { 11561556Srgrimes /* 11571556Srgrimes * see if we just have an ordinary replacement character 11581556Srgrimes * or we refer to a subexpression. 11591556Srgrimes */ 11601556Srgrimes if (c == '&') { 11611556Srgrimes pmpt = pm; 11621556Srgrimes } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) { 11631556Srgrimes /* 11641556Srgrimes * make sure there is a subexpression as specified 11651556Srgrimes */ 11661556Srgrimes if ((len = *spt++ - '0') > subexcnt) 11671556Srgrimes return(-1); 11681556Srgrimes pmpt = pm + len; 11691556Srgrimes } else { 11701556Srgrimes /* 11711556Srgrimes * Ordinary character, just copy it 11721556Srgrimes */ 11731556Srgrimes if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) 11741556Srgrimes c = *spt++; 11751556Srgrimes *dpt++ = c; 11761556Srgrimes continue; 11771556Srgrimes } 11781556Srgrimes 11791556Srgrimes /* 11801556Srgrimes * continue if the subexpression is bogus 11811556Srgrimes */ 11821556Srgrimes if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) || 11831556Srgrimes ((len = pmpt->rm_eo - pmpt->rm_so) <= 0)) 11841556Srgrimes continue; 11851556Srgrimes 11861556Srgrimes /* 11871556Srgrimes * copy the subexpression to the destination. 11881556Srgrimes * fail if we run out of space or the match string is damaged 11891556Srgrimes */ 11901556Srgrimes if (len > (destend - dpt)) 11911556Srgrimes len = destend - dpt; 11921556Srgrimes if (l_strncpy(dpt, src + pmpt->rm_so, len) != len) 11931556Srgrimes return(-1); 11941556Srgrimes dpt += len; 11951556Srgrimes } 11961556Srgrimes return(dpt - dest); 11971556Srgrimes} 11981556Srgrimes#endif 1199