]> Dogcows Code - chaz/tar/blobdiff - src/transform.c
Update copyright years.
[chaz/tar] / src / transform.c
index fc3eb48779c599f345bb495fb50ddef94c8926fb..cd9e27ccf4f6fe624d9f401a58ffd4304bc9794b 100644 (file)
@@ -1,5 +1,5 @@
-/* This file is part of GNU tar. 
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+/* This file is part of GNU tar.
+   Copyright 2006-2008, 2013-2014 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
@@ -12,8 +12,7 @@
    Public License for more details.
 
    You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation, Inc.,
-   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <system.h>
 #include <regex.h>
@@ -34,8 +33,8 @@ enum replace_segm_type
 
 enum case_ctl_type
   {
-    ctl_stop,       /* Stop case conversion */ 
-    ctl_upcase_next,/* Turn the next character to uppercase */ 
+    ctl_stop,       /* Stop case conversion */
+    ctl_upcase_next,/* Turn the next character to uppercase */
     ctl_locase_next,/* Turn the next character to lowercase */
     ctl_upcase,     /* Turn the replacement to uppercase until ctl_stop */
     ctl_locase      /* Turn the replacement to lowercase until ctl_stop */
@@ -51,9 +50,9 @@ struct replace_segm
     {
       char *ptr;
       size_t size;
-    } literal;                /* type == segm_literal */   
+    } literal;                /* type == segm_literal */
     size_t ref;               /* type == segm_backref */
-    enum case_ctl_type ctl;   /* type == segm_case_ctl */ 
+    enum case_ctl_type ctl;   /* type == segm_case_ctl */
   } v;
 };
 
@@ -61,6 +60,7 @@ struct transform
 {
   struct transform *next;
   enum transform_type transform_type;
+  int flags;
   unsigned match_number;
   regex_t regex;
   /* Compiled replacement expression */
@@ -69,10 +69,12 @@ struct transform
 };
 
 \f
+
+static int transform_flags = XFORM_ALL;
 static struct transform *transform_head, *transform_tail;
 
 static struct transform *
-new_transform ()
+new_transform (void)
 {
   struct transform *p = xzalloc (sizeof *p);
   if (transform_tail)
@@ -131,6 +133,41 @@ add_backref_segment (struct transform *tf, size_t ref)
   segm->v.ref = ref;
 }
 
+static int
+parse_xform_flags (int *pflags, int c)
+{
+  switch (c)
+    {
+    case 'r':
+      *pflags |= XFORM_REGFILE;
+      break;
+
+    case 'R':
+      *pflags &= ~XFORM_REGFILE;
+      break;
+
+    case 'h':
+      *pflags |= XFORM_LINK;
+      break;
+
+    case 'H':
+      *pflags &= ~XFORM_LINK;
+      break;
+
+    case 's':
+      *pflags |= XFORM_SYMLINK;
+      break;
+
+    case 'S':
+      *pflags &= ~XFORM_SYMLINK;
+      break;
+
+    default:
+      return 1;
+    }
+  return 0;
+}
+
 static void
 add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl)
 {
@@ -150,7 +187,25 @@ parse_transform_expr (const char *expr)
   struct transform *tf = new_transform ();
 
   if (expr[0] != 's')
-    USAGE_ERROR ((0, 0, _("Invalid transform expression")));
+    {
+      if (strncmp (expr, "flags=", 6) == 0)
+       {
+         transform_flags = 0;
+         for (expr += 6; *expr; expr++)
+           {
+             if (*expr == ';')
+               {
+                 expr++;
+                 break;
+               }
+             if (parse_xform_flags (&transform_flags, *expr))
+               USAGE_ERROR ((0, 0, _("Unknown transform flag: %c"),
+                             *expr));
+           }
+         return expr;
+       }
+      USAGE_ERROR ((0, 0, _("Invalid transform expression")));
+    }
 
   delim = expr[1];
 
@@ -172,6 +227,7 @@ parse_transform_expr (const char *expr)
 
   /* Check flags */
   tf->transform_type = transform_first;
+  tf->flags = transform_flags;
   for (p = expr + j + 1; *p && *p != ';'; p++)
     switch (*p)
       {
@@ -186,7 +242,7 @@ parse_transform_expr (const char *expr)
       case 'x':
        cflags |= REG_EXTENDED;
        break;
-       
+
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
        tf->match_number = strtoul (p, (char**) &p, 0);
@@ -194,20 +250,21 @@ parse_transform_expr (const char *expr)
        break;
 
       default:
-       USAGE_ERROR ((0, 0, _("Unknown flag in transform expression: %c"),
-                     *p));
+       if (parse_xform_flags (&tf->flags, *p))
+         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;
 
   rc = regcomp (&tf->regex, str, cflags);
-  
+
   if (rc)
     {
       char errbuf[512];
@@ -217,7 +274,7 @@ parse_transform_expr (const char *expr)
 
   if (str[0] == '^' || str[strlen (str) - 1] == '$')
     tf->transform_type = transform_first;
-  
+
   free (str);
 
   /* Extract and compile replacement expr */
@@ -231,7 +288,7 @@ parse_transform_expr (const char *expr)
       if (*cur == '\\')
        {
          size_t n;
-         
+
          add_literal_segment (tf, beg, cur);
          switch (*++cur)
            {
@@ -252,32 +309,32 @@ parse_transform_expr (const char *expr)
              add_char_segment (tf, '\a');
              cur++;
              break;
-             
+
            case 'b':
              add_char_segment (tf, '\b');
              cur++;
              break;
-             
+
            case 'f':
              add_char_segment (tf, '\f');
              cur++;
              break;
-             
+
            case 'n':
              add_char_segment (tf, '\n');
              cur++;
              break;
-             
+
            case 'r':
              add_char_segment (tf, '\r');
              cur++;
              break;
-             
+
            case 't':
              add_char_segment (tf, '\t');
              cur++;
              break;
-             
+
            case 'v':
              add_char_segment (tf, '\v');
              cur++;
@@ -287,39 +344,39 @@ parse_transform_expr (const char *expr)
              add_char_segment (tf, '&');
              cur++;
              break;
-             
+
            case 'L':
-             /* Turn the replacement to lowercase until a `\U' or `\E'
+             /* Turn the replacement to lowercase until a '\U' or '\E'
                 is found, */
              add_case_ctl_segment (tf, ctl_locase);
              cur++;
              break;
+
            case 'l':
              /* Turn the next character to lowercase, */
              add_case_ctl_segment (tf, ctl_locase_next);
              cur++;
              break;
-             
+
            case 'U':
-             /* Turn the replacement to uppercase until a `\L' or `\E'
+             /* Turn the replacement to uppercase until a '\L' or '\E'
                 is found, */
              add_case_ctl_segment (tf, ctl_upcase);
              cur++;
              break;
-             
+
            case 'u':
              /* Turn the next character to uppercase, */
              add_case_ctl_segment (tf, ctl_upcase_next);
              cur++;
              break;
-             
+
            case 'E':
-             /* Stop case conversion started by `\L' or `\U'. */
+             /* Stop case conversion started by '\L' or '\U'. */
              add_case_ctl_segment (tf, ctl_stop);
              cur++;
              break;
-  
+
            default:
              /* Try to be nice */
              {
@@ -362,7 +419,7 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
   static char *case_ctl_buffer;
   static size_t case_ctl_bufsize;
   char *p;
-  
+
   if (case_ctl_bufsize < size)
     {
       case_ctl_bufsize = size;
@@ -372,21 +429,21 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
   switch (case_ctl)
     {
     case ctl_upcase_next:
-      case_ctl_buffer[0] = toupper (case_ctl_buffer[0]);
+      case_ctl_buffer[0] = toupper ((unsigned char) case_ctl_buffer[0]);
       break;
-      
+
     case ctl_locase_next:
-      case_ctl_buffer[0] = tolower (case_ctl_buffer[0]);
+      case_ctl_buffer[0] = tolower ((unsigned char) case_ctl_buffer[0]);
       break;
-      
+
     case ctl_upcase:
       for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
-       *p = toupper (*p);
+       *p = toupper ((unsigned char) *p);
       break;
-      
+
     case ctl_locase:
       for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
-       *p = tolower (*p);
+       *p = tolower ((unsigned char) *p);
       break;
 
     case ctl_stop:
@@ -399,7 +456,7 @@ run_case_conv (enum case_ctl_type case_ctl, char *ptr, size_t size)
 static struct obstack stk;
 static bool stk_init;
 
-void
+static void
 _single_transform_name_to_obstack (struct transform *tf, char *input)
 {
   regmatch_t *rmp;
@@ -407,7 +464,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
   size_t nmatches = 0;
   enum case_ctl_type case_ctl = ctl_stop,  /* Current case conversion op */
                      save_ctl = ctl_stop;  /* Saved case_ctl for \u and \l */
-  
+
   /* Reset case conversion after a single-char operation */
 #define CASE_CTL_RESET()  if (case_ctl == ctl_upcase_next     \
                              || case_ctl == ctl_locase_next) \
@@ -415,20 +472,20 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
                               case_ctl = save_ctl;            \
                               save_ctl = ctl_stop;            \
                            }
-  
+
   rmp = xmalloc ((tf->regex.re_nsub + 1) * sizeof (*rmp));
 
   while (*input)
     {
       size_t disp;
       char *ptr;
-      
+
       rc = regexec (&tf->regex, input, tf->regex.re_nsub + 1, rmp, 0);
-      
+
       if (rc == 0)
        {
          struct replace_segm *segm;
-         
+
          disp = rmp[0].rm_eo;
 
          if (rmp[0].rm_so)
@@ -458,7 +515,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
                    }
                  obstack_grow (&stk, ptr, segm->v.literal.size);
                  break;
-             
+
                case segm_backref:    /* Back-reference segment */
                  if (rmp[segm->v.ref].rm_so != -1
                      && rmp[segm->v.ref].rm_eo != -1)
@@ -471,7 +528,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
                          ptr = run_case_conv (case_ctl, ptr, size);
                          CASE_CTL_RESET();
                        }
-                     
+
                      obstack_grow (&stk, ptr, size);
                    }
                  break;
@@ -491,7 +548,7 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
                          break;
                        }
                      /*FALL THROUGH*/
-                     
+
                    case ctl_upcase:
                    case ctl_locase:
                    case ctl_stop:
@@ -519,31 +576,37 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
   free (rmp);
 }
 
-bool
-_transform_name_to_obstack (char *input, char **output)
+static bool
+_transform_name_to_obstack (int flags, char *input, char **output)
 {
   struct transform *tf;
+  bool alloced = false;
 
   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);
+      if (tf->flags & flags)
+       {
+         _single_transform_name_to_obstack (tf, input);
+         input = obstack_finish (&stk);
+         alloced = true;
+       }
     }
   *output = input;
-  return transform_head != NULL;
+  return alloced;
 }
-  
+
 bool
-transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat)
+transform_name_fp (char **pinput, int flags,
+                  char *(*fun)(char *, void *), void *dat)
 {
     char *str;
-    bool ret = _transform_name_to_obstack (*pinput, &str);
+    bool ret = _transform_name_to_obstack (flags, *pinput, &str);
     if (ret)
       {
        assign_string (pinput, fun ? fun (str, dat) : str);
@@ -560,8 +623,13 @@ transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat)
 }
 
 bool
-transform_name (char **pinput)
+transform_name (char **pinput, int type)
 {
-  return transform_name_fp (pinput, NULL, NULL);
+  return transform_name_fp (pinput, type, NULL, NULL);
 }
 
+bool
+transform_program_p (void)
+{
+  return transform_head != NULL;
+}
This page took 0.034316 seconds and 4 git commands to generate.