]> Dogcows Code - chaz/tar/blobdiff - src/transform.c
Update
[chaz/tar] / src / transform.c
index acdf552cf3b88d9237152e5004a305faf3b20122..349a0d59e21c7394781a9d27b44c7df8f2a907ff 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 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"
 
-enum transform_type
+static enum transform_type
   {
     transform_none,
     transform_first,
     transform_global
   }
 transform_type = transform_none;
   {
     transform_none,
     transform_first,
     transform_global
   }
 transform_type = transform_none;
+static unsigned match_number = 0;
 static regex_t regex;
 static struct obstack stk;
 
 static regex_t regex;
 static struct obstack stk;
 
@@ -33,6 +34,16 @@ enum replace_segm_type
   {
     segm_literal,   /* Literal segment */
     segm_backref,   /* Back-reference segment */
   {
     segm_literal,   /* Literal segment */
     segm_backref,   /* Back-reference segment */
+    segm_case_ctl   /* Case control segment (GNU extension) */
+  };
+
+enum case_ctl_type
+  {
+    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 */
   };
 
 struct replace_segm
   };
 
 struct replace_segm
@@ -45,13 +56,15 @@ struct replace_segm
     {
       char *ptr;
       size_t size;
     {
       char *ptr;
       size_t size;
-    } literal;
-    size_t ref;
+    } literal;                /* type == segm_literal */   
+    size_t ref;               /* type == segm_backref */
+    enum case_ctl_type ctl;   /* type == segm_case_ctl */ 
   } v;
 };
 
   } v;
 };
 
+/* Compiled replacement expression */
 static struct replace_segm *repl_head, *repl_tail;
 static struct replace_segm *repl_head, *repl_tail;
-static segm_count;
+static size_t segm_count; /* Number of elements in the above list */
 
 static struct replace_segm *
 add_segment (void)
 
 static struct replace_segm *
 add_segment (void)
@@ -90,7 +103,7 @@ add_char_segment (int chr)
   segm->v.literal.ptr = xmalloc (2);
   segm->v.literal.ptr[0] = chr;
   segm->v.literal.ptr[1] = 0;
   segm->v.literal.ptr = xmalloc (2);
   segm->v.literal.ptr[0] = chr;
   segm->v.literal.ptr[1] = 0;
-  segm->v.literal.size = 2;
+  segm->v.literal.size = 1;
 }
 
 static void
 }
 
 static void
@@ -101,6 +114,14 @@ add_backref_segment (size_t ref)
   segm->v.ref = ref;
 }
 
   segm->v.ref = ref;
 }
 
+static void
+add_case_ctl_segment (enum case_ctl_type ctl)
+{
+  struct replace_segm *segm = add_segment ();
+  segm->type = segm_case_ctl;
+  segm->v.ctl = ctl;
+}
+
 void
 set_transform_expr (const char *expr)
 {
 void
 set_transform_expr (const char *expr)
 {
@@ -156,6 +177,12 @@ set_transform_expr (const char *expr)
        cflags |= REG_EXTENDED;
        break;
        
        cflags |= REG_EXTENDED;
        break;
        
+      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);
+       p--;
+       break;
+       
       default:
        USAGE_ERROR ((0, 0, _("Unknown flag in transform expression")));
       }
       default:
        USAGE_ERROR ((0, 0, _("Unknown flag in transform expression")));
       }
@@ -246,7 +273,39 @@ set_transform_expr (const char *expr)
              add_char_segment ('&');
              cur++;
              break;
              add_char_segment ('&');
              cur++;
              break;
-
+             
+           case 'L':
+             /* Turn the replacement to lowercase until a `\U' or `\E'
+                is found, */
+             add_case_ctl_segment (ctl_locase);
+             cur++;
+             break;
+           case 'l':
+             /* Turn the next character to lowercase, */
+             add_case_ctl_segment (ctl_locase_next);
+             cur++;
+             break;
+             
+           case 'U':
+             /* Turn the replacement to uppercase until a `\L' or `\E'
+                is found, */
+             add_case_ctl_segment (ctl_upcase);
+             cur++;
+             break;
+             
+           case 'u':
+             /* Turn the next character to uppercase, */
+             add_case_ctl_segment (ctl_upcase_next);
+             cur++;
+             break;
+             
+           case 'E':
+             /* Stop case conversion started by `\L' or `\U'. */
+             add_case_ctl_segment (ctl_stop);
+             cur++;
+             break;
+  
            default:
              /* Try to be nice */
              {
            default:
              /* Try to be nice */
              {
@@ -273,12 +332,63 @@ set_transform_expr (const char *expr)
   
 }
 
   
 }
 
+/* Run case conversion specified by CASE_CTL on array PTR of SIZE
+   characters. Returns pointer to statically allocated storage. */
+static char *
+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;
+      case_ctl_buffer = xrealloc (case_ctl_buffer, case_ctl_bufsize);
+    }
+  memcpy (case_ctl_buffer, ptr, size);
+  switch (case_ctl)
+    {
+    case ctl_upcase_next:
+      case_ctl_buffer[0] = toupper (case_ctl_buffer[0]);
+      break;
+      
+    case ctl_locase_next:
+      case_ctl_buffer[0] = tolower (case_ctl_buffer[0]);
+      break;
+      
+    case ctl_upcase:
+      for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
+       *p = toupper (*p);
+      break;
+      
+    case ctl_locase:
+      for (p = case_ctl_buffer; p < case_ctl_buffer + size; p++)
+       *p = tolower (*p);
+      break;
+
+    case ctl_stop:
+      break;
+    }
+  return case_ctl_buffer;
+}
+
 bool
 _transform_name_to_obstack (char *input)
 {
   regmatch_t *rmp;
 bool
 _transform_name_to_obstack (char *input)
 {
   regmatch_t *rmp;
-  char *p;
   int rc;
   int rc;
+  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) \
+                            {                                 \
+                              case_ctl = save_ctl;            \
+                              save_ctl = ctl_stop;            \
+                           }
   
   if (transform_type == transform_none)
     return false;
   
   if (transform_type == transform_none)
     return false;
@@ -288,34 +398,82 @@ _transform_name_to_obstack (char *input)
   while (*input)
     {
       size_t disp;
   while (*input)
     {
       size_t disp;
+      char *ptr;
       
       rc = regexec (&regex, input, regex.re_nsub + 1, rmp, 0);
       
       if (rc == 0)
        {
          struct replace_segm *segm;
       
       rc = regexec (&regex, input, regex.re_nsub + 1, rmp, 0);
       
       if (rc == 0)
        {
          struct replace_segm *segm;
-
+         
          disp = rmp[0].rm_eo;
 
          if (rmp[0].rm_so)
            obstack_grow (&stk, input, rmp[0].rm_so);
          disp = rmp[0].rm_eo;
 
          if (rmp[0].rm_so)
            obstack_grow (&stk, input, rmp[0].rm_so);
-         
+
+         nmatches++;
+         if (match_number && nmatches < match_number)
+           {
+             obstack_grow (&stk, input, disp);
+             input += disp;
+             continue;
+           }
+
          for (segm = repl_head; segm; segm = segm->next)
            {
              switch (segm->type)
                {
                case segm_literal:    /* Literal segment */
          for (segm = repl_head; segm; segm = segm->next)
            {
              switch (segm->type)
                {
                case segm_literal:    /* Literal segment */
-                 obstack_grow (&stk, segm->v.literal.ptr,
-                               segm->v.literal.size);
+                 if (case_ctl == ctl_stop)
+                   ptr = segm->v.literal.ptr;
+                 else
+                   {
+                     ptr = run_case_conv (case_ctl,
+                                          segm->v.literal.ptr,
+                                          segm->v.literal.size);
+                     CASE_CTL_RESET();
+                   }
+                 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)
                  break;
              
                case segm_backref:    /* Back-reference segment */
                  if (rmp[segm->v.ref].rm_so != -1
                      && rmp[segm->v.ref].rm_eo != -1)
-                   obstack_grow (&stk,
-                                 input + rmp[segm->v.ref].rm_so,
-                             rmp[segm->v.ref].rm_eo - rmp[segm->v.ref].rm_so);
+                   {
+                     size_t size = rmp[segm->v.ref].rm_eo
+                                     - rmp[segm->v.ref].rm_so;
+                     ptr = input + rmp[segm->v.ref].rm_so;
+                     if (case_ctl != ctl_stop)
+                       {
+                         ptr = run_case_conv (case_ctl, ptr, size);
+                         CASE_CTL_RESET();
+                       }
+                     
+                     obstack_grow (&stk, ptr, size);
+                   }
                  break;
                  break;
+
+               case segm_case_ctl:
+                 switch (segm->v.ctl)
+                   {
+                   case ctl_upcase_next:
+                   case ctl_locase_next:
+                     switch (save_ctl)
+                       {
+                       case ctl_stop:
+                       case ctl_upcase:
+                       case ctl_locase:
+                         save_ctl = case_ctl;
+                       default:
+                         break;
+                       }
+                     /*FALL THROUGH*/
+                     
+                   case ctl_upcase:
+                   case ctl_locase:
+                   case ctl_stop:
+                     case_ctl = segm->v.ctl;
+                   }
                }
            }
        }
                }
            }
        }
@@ -340,21 +498,21 @@ _transform_name_to_obstack (char *input)
 }
   
 bool
 }
   
 bool
-transform_name_fp (char **pinput, char *(*fun)(char *))
+transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat)
 {
 {
-    char *str, *p;
+    char *str;
     bool ret = _transform_name_to_obstack (*pinput);
     if (ret)
       {
        str = obstack_finish (&stk);
     bool ret = _transform_name_to_obstack (*pinput);
     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)
       {
        str = *pinput;
        *pinput = NULL;
        obstack_free (&stk, str);
       }
     else if (fun)
       {
        str = *pinput;
        *pinput = NULL;
-       assign_string (pinput, fun (str));
+       assign_string (pinput, fun (str, dat));
        free (str);
        ret = true;
       }
        free (str);
        ret = true;
       }
@@ -364,23 +522,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);
 }
 
 }
 
-#if 0
-void
-read_and_transform_loop ()
-{
-  char buf[512];
-  while (fgets (buf, sizeof buf, stdin))
-    {
-      char *p = buf + strlen (buf);
-      if (p[-1] == '\n')
-       p[-1] = 0;
-      if (transform_name (buf, &p))
-       printf ("=> %s\n", p);
-      else
-       printf ("=\n");
-    }
-}
-#endif
This page took 0.030305 seconds and 4 git commands to generate.