]> Dogcows Code - chaz/tar/blobdiff - src/transform.c
Bugfix.
[chaz/tar] / src / transform.c
index 525a7875134696289d502d8fdb3039ce19bc2e55..fc3eb48779c599f345bb495fb50ddef94c8926fb 100644 (file)
@@ -1,9 +1,9 @@
 /* This file is part of GNU tar. 
 /* This file is part of GNU tar. 
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
-   Free Software Foundation; either version 2, or (at your option) any later
+   Free Software Foundation; either version 3, or (at your option) any later
    version.
 
    This program is distributed in the hope that it will be useful, but
    version.
 
    This program is distributed in the hope that it will be useful, but
 #include <regex.h>
 #include "common.h"
 
 #include <regex.h>
 #include "common.h"
 
-static enum transform_type
+enum transform_type
   {
   {
-    transform_none,
     transform_first,
     transform_global
     transform_first,
     transform_global
-  }
-transform_type = transform_none;
-static unsigned match_number = 0;
-static regex_t regex;
-static struct obstack stk;
+  };
 
 enum replace_segm_type
   {
 
 enum replace_segm_type
   {
@@ -62,31 +57,53 @@ struct replace_segm
   } v;
 };
 
   } v;
 };
 
-/* Compiled replacement expression */
-static struct replace_segm *repl_head, *repl_tail;
-static segm_count; /* Number of elements in the above list */
+struct transform
+{
+  struct transform *next;
+  enum transform_type transform_type;
+  unsigned match_number;
+  regex_t regex;
+  /* Compiled replacement expression */
+  struct replace_segm *repl_head, *repl_tail;
+  size_t segm_count; /* Number of elements in the above list */
+};
+
+\f
+static struct transform *transform_head, *transform_tail;
+
+static struct transform *
+new_transform ()
+{
+  struct transform *p = xzalloc (sizeof *p);
+  if (transform_tail)
+    transform_tail->next = p;
+  else
+    transform_head = p;
+  transform_tail = p;
+  return p;
+}
 
 static struct replace_segm *
 
 static struct replace_segm *
-add_segment (void)
+add_segment (struct transform *tf)
 {
   struct replace_segm *segm = xmalloc (sizeof *segm);
   segm->next = NULL;
 {
   struct replace_segm *segm = xmalloc (sizeof *segm);
   segm->next = NULL;
-  if (repl_tail)
-    repl_tail->next = segm;
+  if (tf->repl_tail)
+    tf->repl_tail->next = segm;
   else
   else
-    repl_head = segm;
-  repl_tail = segm;
-  segm_count++;
+    tf->repl_head = segm;
+  tf->repl_tail = segm;
+  tf->segm_count++;
   return segm;
 }
 
 static void
   return segm;
 }
 
 static void
-add_literal_segment (char *str, char *end)
+add_literal_segment (struct transform *tf, char *str, char *end)
 {
   size_t len = end - str;
   if (len)
     {
 {
   size_t len = end - str;
   if (len)
     {
-      struct replace_segm *segm = add_segment ();
+      struct replace_segm *segm = add_segment (tf);
       segm->type = segm_literal;
       segm->v.literal.ptr = xmalloc (len + 1);
       memcpy (segm->v.literal.ptr, str, len);
       segm->type = segm_literal;
       segm->v.literal.ptr = xmalloc (len + 1);
       memcpy (segm->v.literal.ptr, str, len);
@@ -96,9 +113,9 @@ add_literal_segment (char *str, char *end)
 }
 
 static void
 }
 
 static void
-add_char_segment (int chr)
+add_char_segment (struct transform *tf, int chr)
 {
 {
-  struct replace_segm *segm = add_segment ();
+  struct replace_segm *segm = add_segment (tf);
   segm->type = segm_literal;
   segm->v.literal.ptr = xmalloc (2);
   segm->v.literal.ptr[0] = chr;
   segm->type = segm_literal;
   segm->v.literal.ptr = xmalloc (2);
   segm->v.literal.ptr[0] = chr;
@@ -107,37 +124,30 @@ add_char_segment (int chr)
 }
 
 static void
 }
 
 static void
-add_backref_segment (size_t ref)
+add_backref_segment (struct transform *tf, size_t ref)
 {
 {
-  struct replace_segm *segm = add_segment ();
+  struct replace_segm *segm = add_segment (tf);
   segm->type = segm_backref;
   segm->v.ref = ref;
 }
 
 static void
   segm->type = segm_backref;
   segm->v.ref = ref;
 }
 
 static void
-add_case_ctl_segment (enum case_ctl_type ctl)
+add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl)
 {
 {
-  struct replace_segm *segm = add_segment ();
+  struct replace_segm *segm = add_segment (tf);
   segm->type = segm_case_ctl;
   segm->v.ctl = ctl;
 }
 
   segm->type = segm_case_ctl;
   segm->v.ctl = ctl;
 }
 
-void
-set_transform_expr (const char *expr)
+static const char *
+parse_transform_expr (const char *expr)
 {
   int delim;
   int i, j, rc;
   char *str, *beg, *cur;
   const char *p;
   int cflags = 0;
 {
   int delim;
   int i, j, rc;
   char *str, *beg, *cur;
   const char *p;
   int cflags = 0;
-
-  if (transform_type == transform_none)
-    obstack_init (&stk);
-  else
-    {
-      /* Redefinition of the transform expression */
-      regfree (&regex);
-    }
+  struct transform *tf = new_transform ();
 
   if (expr[0] != 's')
     USAGE_ERROR ((0, 0, _("Invalid transform expression")));
 
   if (expr[0] != 's')
     USAGE_ERROR ((0, 0, _("Invalid transform expression")));
@@ -161,12 +171,12 @@ set_transform_expr (const char *expr)
     USAGE_ERROR ((0, 0, _("Invalid transform expression")));
 
   /* Check flags */
     USAGE_ERROR ((0, 0, _("Invalid transform expression")));
 
   /* Check flags */
-  transform_type = transform_first;
-  for (p = expr + j + 1; *p; p++)
+  tf->transform_type = transform_first;
+  for (p = expr + j + 1; *p && *p != ';'; p++)
     switch (*p)
       {
       case 'g':
     switch (*p)
       {
       case 'g':
-       transform_type = transform_global;
+       tf->transform_type = transform_global;
        break;
 
       case 'i':
        break;
 
       case 'i':
@@ -179,30 +189,34 @@ set_transform_expr (const char *expr)
        
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
        
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
-       match_number = strtoul (p, (char**) &p, 0);
+       tf->match_number = strtoul (p, (char**) &p, 0);
        p--;
        break;
        p--;
        break;
-       
+
       default:
       default:
-       USAGE_ERROR ((0, 0, _("Unknown flag in transform expression")));
+       USAGE_ERROR ((0, 0, _("Unknown flag in transform expression: %c"),
+                     *p));
       }
 
       }
 
+  if (*p == ';')
+    p++;
+  
   /* Extract and compile regex */
   str = xmalloc (i - 1);
   memcpy (str, expr + 2, i - 2);
   str[i - 2] = 0;
 
   /* Extract and compile regex */
   str = xmalloc (i - 1);
   memcpy (str, expr + 2, i - 2);
   str[i - 2] = 0;
 
-  rc = regcomp (&regex, str, cflags);
+  rc = regcomp (&tf->regex, str, cflags);
   
   if (rc)
     {
       char errbuf[512];
   
   if (rc)
     {
       char errbuf[512];
-      regerror (rc, &regex, errbuf, sizeof (errbuf));
+      regerror (rc, &tf->regex, errbuf, sizeof (errbuf));
       USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
     }
 
   if (str[0] == '^' || str[strlen (str) - 1] == '$')
       USAGE_ERROR ((0, 0, _("Invalid transform expression: %s"), errbuf));
     }
 
   if (str[0] == '^' || str[strlen (str) - 1] == '$')
-    transform_type = transform_first;
+    tf->transform_type = transform_first;
   
   free (str);
 
   
   free (str);
 
@@ -218,91 +232,91 @@ set_transform_expr (const char *expr)
        {
          size_t n;
          
        {
          size_t n;
          
-         add_literal_segment (beg, cur);
+         add_literal_segment (tf, beg, cur);
          switch (*++cur)
            {
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
              n = strtoul (cur, &cur, 10);
          switch (*++cur)
            {
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
              n = strtoul (cur, &cur, 10);
-             if (n > regex.re_nsub)
+             if (n > tf->regex.re_nsub)
                USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
                USAGE_ERROR ((0, 0, _("Invalid transform replacement: back reference out of range")));
-             add_backref_segment (n);
+             add_backref_segment (tf, n);
              break;
 
            case '\\':
              break;
 
            case '\\':
-             add_char_segment ('\\');
+             add_char_segment (tf, '\\');
              cur++;
              break;
 
            case 'a':
              cur++;
              break;
 
            case 'a':
-             add_char_segment ('\a');
+             add_char_segment (tf, '\a');
              cur++;
              break;
              
            case 'b':
              cur++;
              break;
              
            case 'b':
-             add_char_segment ('\b');
+             add_char_segment (tf, '\b');
              cur++;
              break;
              
            case 'f':
              cur++;
              break;
              
            case 'f':
-             add_char_segment ('\f');
+             add_char_segment (tf, '\f');
              cur++;
              break;
              
            case 'n':
              cur++;
              break;
              
            case 'n':
-             add_char_segment ('\n');
+             add_char_segment (tf, '\n');
              cur++;
              break;
              
            case 'r':
              cur++;
              break;
              
            case 'r':
-             add_char_segment ('\r');
+             add_char_segment (tf, '\r');
              cur++;
              break;
              
            case 't':
              cur++;
              break;
              
            case 't':
-             add_char_segment ('\t');
+             add_char_segment (tf, '\t');
              cur++;
              break;
              
            case 'v':
              cur++;
              break;
              
            case 'v':
-             add_char_segment ('\v');
+             add_char_segment (tf, '\v');
              cur++;
              break;
 
            case '&':
              cur++;
              break;
 
            case '&':
-             add_char_segment ('&');
+             add_char_segment (tf, '&');
              cur++;
              break;
              
            case 'L':
              /* Turn the replacement to lowercase until a `\U' or `\E'
                 is found, */
              cur++;
              break;
              
            case 'L':
              /* Turn the replacement to lowercase until a `\U' or `\E'
                 is found, */
-             add_case_ctl_segment (ctl_locase);
+             add_case_ctl_segment (tf, ctl_locase);
              cur++;
              break;
  
            case 'l':
              /* Turn the next character to lowercase, */
              cur++;
              break;
  
            case 'l':
              /* Turn the next character to lowercase, */
-             add_case_ctl_segment (ctl_locase_next);
+             add_case_ctl_segment (tf, ctl_locase_next);
              cur++;
              break;
              
            case 'U':
              /* Turn the replacement to uppercase until a `\L' or `\E'
                 is found, */
              cur++;
              break;
              
            case 'U':
              /* Turn the replacement to uppercase until a `\L' or `\E'
                 is found, */
-             add_case_ctl_segment (ctl_upcase);
+             add_case_ctl_segment (tf, ctl_upcase);
              cur++;
              break;
              
            case 'u':
              /* Turn the next character to uppercase, */
              cur++;
              break;
              
            case 'u':
              /* Turn the next character to uppercase, */
-             add_case_ctl_segment (ctl_upcase_next);
+             add_case_ctl_segment (tf, ctl_upcase_next);
              cur++;
              break;
              
            case 'E':
              /* Stop case conversion started by `\L' or `\U'. */
              cur++;
              break;
              
            case 'E':
              /* Stop case conversion started by `\L' or `\U'. */
-             add_case_ctl_segment (ctl_stop);
+             add_case_ctl_segment (tf, ctl_stop);
              cur++;
              break;
   
              cur++;
              break;
   
@@ -312,7 +326,7 @@ set_transform_expr (const char *expr)
                char buf[2];
                buf[0] = '\\';
                buf[1] = *cur;
                char buf[2];
                buf[0] = '\\';
                buf[1] = *cur;
-               add_literal_segment (buf, buf + 2);
+               add_literal_segment (tf, buf, buf + 2);
              }
              cur++;
              break;
              }
              cur++;
              break;
@@ -321,15 +335,23 @@ set_transform_expr (const char *expr)
        }
       else if (*cur == '&')
        {
        }
       else if (*cur == '&')
        {
-         add_literal_segment (beg, cur);
-         add_backref_segment (0);
+         add_literal_segment (tf, beg, cur);
+         add_backref_segment (tf, 0);
          beg = ++cur;
        }
       else
        cur++;
     }
          beg = ++cur;
        }
       else
        cur++;
     }
-  add_literal_segment (beg, cur);
-  
+  add_literal_segment (tf, beg, cur);
+
+  return p;
+}
+
+void
+set_transform_expr (const char *expr)
+{
+  while (*expr)
+    expr = parse_transform_expr (expr);
 }
 
 /* Run case conversion specified by CASE_CTL on array PTR of SIZE
 }
 
 /* Run case conversion specified by CASE_CTL on array PTR of SIZE
@@ -373,11 +395,14 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
   return case_ctl_buffer;
 }
 
   return case_ctl_buffer;
 }
 
-bool
-_transform_name_to_obstack (char *input)
+\f
+static struct obstack stk;
+static bool stk_init;
+
+void
+_single_transform_name_to_obstack (struct transform *tf, char *input)
 {
   regmatch_t *rmp;
 {
   regmatch_t *rmp;
-  char *p;
   int rc;
   size_t nmatches = 0;
   enum case_ctl_type case_ctl = ctl_stop,  /* Current case conversion op */
   int rc;
   size_t nmatches = 0;
   enum case_ctl_type case_ctl = ctl_stop,  /* Current case conversion op */
@@ -391,17 +416,14 @@ _transform_name_to_obstack (char *input)
                               save_ctl = ctl_stop;            \
                            }
   
                               save_ctl = ctl_stop;            \
                            }
   
-  if (transform_type == transform_none)
-    return false;
-
-  rmp = xmalloc ((regex.re_nsub + 1) * sizeof (*rmp));
+  rmp = xmalloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
 
   while (*input)
     {
       size_t disp;
       char *ptr;
       
 
   while (*input)
     {
       size_t disp;
       char *ptr;
       
-      rc = regexec (&regex, input, regex.re_nsub + 1, rmp, 0);
+      rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0);
       
       if (rc == 0)
        {
       
       if (rc == 0)
        {
@@ -413,14 +435,14 @@ _transform_name_to_obstack (char *input)
            obstack_grow (&stk, input, rmp[0].rm_so);
 
          nmatches++;
            obstack_grow (&stk, input, rmp[0].rm_so);
 
          nmatches++;
-         if (match_number && nmatches < match_number)
+         if (tf->match_number && nmatches < tf->match_number)
            {
              obstack_grow (&stk, input, disp);
              input += disp;
              continue;
            }
 
            {
              obstack_grow (&stk, input, disp);
              input += disp;
              continue;
            }
 
-         for (segm = repl_head; segm; segm = segm->next)
+         for (segm = tf->repl_head; segm; segm = segm->next)
            {
              switch (segm->type)
                {
            {
              switch (segm->type)
                {
@@ -486,7 +508,7 @@ _transform_name_to_obstack (char *input)
 
       input += disp;
 
 
       input += disp;
 
-      if (transform_type == transform_first)
+      if (tf->transform_type == transform_first)
        {
          obstack_grow (&stk, input, strlen (input));
          break;
        {
          obstack_grow (&stk, input, strlen (input));
          break;
@@ -495,25 +517,42 @@ _transform_name_to_obstack (char *input)
 
   obstack_1grow (&stk, 0);
   free (rmp);
 
   obstack_1grow (&stk, 0);
   free (rmp);
-  return true;
+}
+
+bool
+_transform_name_to_obstack (char *input, char **output)
+{
+  struct transform *tf;
+
+  if (!stk_init)
+    {
+      obstack_init (&stk);
+      stk_init = true;
+    }
+  
+  for (tf = transform_head; tf; tf = tf->next)
+    {
+      _single_transform_name_to_obstack (tf, input);
+      input = obstack_finish (&stk);
+    }
+  *output = input;
+  return transform_head != NULL;
 }
   
 bool
 }
   
 bool
-transform_name_fp (char **pinput, char *(*fun)(char *))
+transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat)
 {
 {
-    char *str, *p;
-    bool ret = _transform_name_to_obstack (*pinput);
+    char *str;
+    bool ret = _transform_name_to_obstack (*pinput, &str);
     if (ret)
       {
     if (ret)
       {
-       str = obstack_finish (&stk);
-       assign_string (pinput, fun ? fun (str) : str);
+       assign_string (pinput, fun ? fun (str, dat) : str);
        obstack_free (&stk, str);
       }
     else if (fun)
       {
        obstack_free (&stk, str);
       }
     else if (fun)
       {
-       str = *pinput;
        *pinput = NULL;
        *pinput = NULL;
-       assign_string (pinput, fun (str));
+       assign_string (pinput, fun (str, dat));
        free (str);
        ret = true;
       }
        free (str);
        ret = true;
       }
@@ -523,6 +562,6 @@ transform_name_fp (char **pinput, char *(*fun)(char *))
 bool
 transform_name (char **pinput)
 {
 bool
 transform_name (char **pinput)
 {
-  return transform_name_fp (pinput, NULL);
+  return transform_name_fp (pinput, NULL, NULL);
 }
 
 }
 
This page took 0.035213 seconds and 4 git commands to generate.