From: grembo Date: Mon, 11 Dec 2023 05:51:13 +0000 (+0100) Subject: Add trailing letter b to bsdtar substitute pattern (#2012) X-Git-Tag: v3.7.3~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0f410f8cfb512f1c7e36f01bd141f2e929281c26;p=thirdparty%2Flibarchive.git Add trailing letter b to bsdtar substitute pattern (#2012) The letter b stands for "from (b)eginning" and specifies that a substitute expression should be matched from the beginning of the string, regardless if and where a previous substitute expression matched. Example: Transform filename from B-A to A-B and remove all underscores. Attempt without option b: bsdtar -cft -s '/\(.*\)-\(.*\)/\2-\1/gp' -s "/_//g" ab_c-d_ef ab_c-d_ef >> d_ef-ab_c With option b: bsdtar -cft -s '/\(.*\)-\(.*\)/\2-\1/gp' -s "/_//gb" ab_c-d_ef ab_c-d_ef >> def-abc --- diff --git a/tar/bsdtar.1 b/tar/bsdtar.1 index c80952600..9a94bf761 100644 --- a/tar/bsdtar.1 +++ b/tar/bsdtar.1 @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 1, 2022 +.Dd December 10, 2023 .Dt TAR 1 .Os .Sh NAME @@ -772,7 +772,7 @@ This works similar to the conv=sparse option of dd. Modify file or archive member names according to .Pa pattern . The pattern has the format -.Ar /old/new/ Ns Op ghHprRsS +.Ar /old/new/ Ns Op bghHprRsS where .Ar old is a basic regular expression, @@ -794,6 +794,9 @@ of symbolic links. The optional trailing p specifies that after a successful substitution the original path name and the new path name should be printed to standard error. +The optional trailing b specifies that the substitution should be +matched from the beginning of the string rather than from right after the +position at which the previous matching substitution ended. Optional trailing H, R, or S characters suppress substitutions for hardlink targets, regular filenames, or symlink targets, respectively. diff --git a/tar/subst.c b/tar/subst.c index 659c0b88f..9747abb90 100644 --- a/tar/subst.c +++ b/tar/subst.c @@ -49,7 +49,7 @@ struct subst_rule { struct subst_rule *next; regex_t re; char *result; - unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1; + unsigned int global:1, print:1, regular:1, symlink:1, hardlink:1, from_begin:1; }; struct substitution { @@ -129,9 +129,14 @@ add_substitution(struct bsdtar *bsdtar, const char *rule_text) rule->regular = 1; /* Rewrite regular filenames. */ rule->symlink = 1; /* Rewrite symlink targets. */ rule->hardlink = 1; /* Rewrite hardlink targets. */ + rule->from_begin = 0; /* Don't match from start. */ while (*++end_pattern) { switch (*end_pattern) { + case 'b': + case 'B': + rule->from_begin = 1; + break; case 'g': case 'G': rule->global = 1; @@ -214,6 +219,7 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, { const char *path = name; regmatch_t matches[10]; + char* buffer = NULL; size_t i, j; struct subst_rule *rule; struct substitution *subst; @@ -239,6 +245,13 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, continue; } + if (rule->from_begin && *result) { + realloc_strcat(result, name); + realloc_strcat(&buffer, *result); + name = buffer; + (*result)[0] = 0; + } + while (1) { if (regexec(&rule->re, name, 10, matches, 0)) break; @@ -278,6 +291,7 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, case '9': realloc_strncat(result, rule->result + j, i - j - 1); if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) { + free(buffer); free(*result); *result = NULL; return -1; @@ -304,6 +318,8 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, if (got_match) realloc_strcat(result, name); + free(buffer); + if (print_match) fprintf(stderr, "%s >> %s\n", path, *result); diff --git a/tar/test/test_option_s.c b/tar/test/test_option_s.c index ed68ebf72..564793b97 100644 --- a/tar/test/test_option_s.c +++ b/tar/test/test_option_s.c @@ -87,6 +87,17 @@ DEFINE_TEST(test_option_s) assertFileContents("foo", 3, "test4/in/d1/bar"); assertFileContents("bar", 3, "test4/in/d1/baz"); + /* + * Test 4b: Multiple substitutions behavior with option b). + */ + assertMakeDir("test4b", 0755); + systemf("%s -cf test4b.tar in/d1/foo in/d1/bar", + testprog); + systemf("%s -xf test4b.tar -s /oo/ar/ -s }ar}az}b -C test4b", + testprog); + assertFileContents("foo", 3, "test4b/in/d1/faz"); + assertFileContents("bar", 3, "test4b/in/d1/baz"); + /* * Test 5: Name-switching substitutions when extracting archive. */