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