Browse Source

* NEWS, configure.ac: Version 1.20.91
* doc/tar.texi: Document transformation scope flags.
* src/common.h (transform_symlinks_option): Remove in favor of
transformation scope flags.
(XFORM_REGFILE, XFORM_LINK, XFORM_SYMLINK, XFORM_ALL): New macros.
(transform_name, transform_member_name, transform_name_fp): Take
an additional argument, specifying scope flags.
* src/create.c: Reflect changes to transform_name.
* src/extract.c (extract_link, extract_symlink): Remove calls to
transform_member_name. It is done in read_header.
* src/list.c (decode_xform): Reflect change in data type of 2nd
argument.
(transform_member_name): 2nd arg is int.
(decode_header): Transform file name and link target names.
* src/tar.c: Remove --transform-symlinks.
* src/transform.c (struct transform): New member `flags'.
(transform_flags): New variable.
(parse_transform_expr): Parse transformation scope flags. Allow to
set global flags using `flags=' syntax.
(_transform_name_to_obstack, transform_name_fp)
(transform_name): Take an additional argument, specifying scope
flags.

Sergey Poznyakoff 16 years ago
parent
commit
b4ec8aedf9
11 changed files with 237 additions and 119 deletions
  1. 25 0
      ChangeLog
  2. 30 11
      NEWS
  3. 1 1
      configure.ac
  4. 75 54
      doc/tar.texi
  5. 2 0
      lib/.cvsignore
  6. 8 12
      src/common.h
  7. 2 3
      src/create.c
  8. 0 3
      src/extract.c
  9. 16 7
      src/list.c
  10. 0 14
      src/tar.c
  11. 78 14
      src/transform.c

+ 25 - 0
ChangeLog

@@ -1,3 +1,28 @@
+2008-10-30  Sergey Poznyakoff  <[email protected]>
+
+	* NEWS, configure.ac: Version 1.20.91
+	* doc/tar.texi: Document transformation scope flags.
+	* src/common.h (transform_symlinks_option): Remove in favor of
+	transformation scope flags.
+	(XFORM_REGFILE, XFORM_LINK, XFORM_SYMLINK, XFORM_ALL): New macros.
+	(transform_name, transform_member_name, transform_name_fp): Take
+	an additional argument, specifying scope flags.
+	* src/create.c: Reflect changes to transform_name.
+	* src/extract.c (extract_link, extract_symlink): Remove calls to
+	transform_member_name. It is done in read_header.
+	* src/list.c (decode_xform): Reflect change in data type of 2nd
+	argument. 
+	(transform_member_name): 2nd arg is int.
+	(decode_header): Transform file name and link target names.
+	* src/tar.c: Remove --transform-symlinks.
+	* src/transform.c (struct transform): New member `flags'.
+	(transform_flags): New variable.
+	(parse_transform_expr): Parse transformation scope flags. Allow to
+	set global flags using `flags=' syntax.
+	(_transform_name_to_obstack, transform_name_fp)
+	(transform_name): Take an additional argument, specifying scope
+	flags. 
+
 2008-10-19  Sergey Poznyakoff  <[email protected]>
 2008-10-19  Sergey Poznyakoff  <[email protected]>
 
 
 	* THANKS: Add Ed Leaver.
 	* THANKS: Add Ed Leaver.

+ 30 - 11
NEWS

@@ -1,8 +1,8 @@
-GNU tar NEWS - User visible changes. 2008-10-22
+GNU tar NEWS - User visible changes. 2008-10-30
 Please send GNU tar bug reports to <[email protected]>
 Please send GNU tar bug reports to <[email protected]>
 
 
 
 
-version 1.20.90 (CVS)
+version 1.20.91 (CVS)
 
 
 * New short option -J
 * New short option -J
 
 
@@ -28,21 +28,40 @@ back to using archive suffix to determine it.
 Using --exclude-vcs handles also files used internally by Bazaar,
 Using --exclude-vcs handles also files used internally by Bazaar,
 Mercurial and Darcs.
 Mercurial and Darcs.
 
 
-* The --transform-symlink option.
+* Transformation scope flags
 
 
-The effect of the --transform option on the symbolic links targets is
-controlled by --transform-symlink and --no-transform-symlink options.
-By default, transformations do not apply to symlink targets,
-which corresponds to the behavior of version 1.19.  To apply
-transformations to symlink targets as well, use --transform-symlink
-option.  The --no-transform-symlink option cancels the effect of any
-prior --transform-symlink.
+Name transformation expressions understand additional flags that
+control type of archive members affected by them.  The flags are:
+
+ - r
+   Apply transformation to regular archive members.
+
+ - s
+   Apply transformation to symbolic link targets.
+
+ - h  
+   Apply transformation to hard link targets.
+
+Corresponding upper-case letters negate the flag meaning, so that
+`H' means ``do not apply transformation to hard link targets.''
+
+The scope flags are listed in the third part of an `s' expression,
+e.g.:
+
+   tar --transform 's|^|/usr/local/|S'
+
+Default is `rsh', which means that transformations are applied to
+both regular archive members and to the targets of symbolic and hard
+links.  If several transform expressions are used, the default flags
+can be changed using `flags=' statement before the expressions, e.g.:
+
+   tar --transform 'flags=S;s|^|/usr/local/|S'
 
 
 * Bugfixes
 * Bugfixes
 
 
 ** The --null option disabled handling of tar options in list files.  This
 ** The --null option disabled handling of tar options in list files.  This
 is fixed.
 is fixed.
-** Fixed record size autodetection.  If the detected record size differs from
+** Fixed record size autodetection.  If detected record size differs from
 the expected value (either default, or set on the command line), tar
 the expected value (either default, or set on the command line), tar
 always prints a warning if verbosity level is set to 1 or greater,
 always prints a warning if verbosity level is set to 1 or greater,
 i.e. if either -t or -v option is given.
 i.e. if either -t or -v option is given.

+ 1 - 1
configure.ac

@@ -18,7 +18,7 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301, USA.
 # 02110-1301, USA.
 
 
-AC_INIT([GNU tar], [1.20.90], [[email protected]])
+AC_INIT([GNU tar], [1.20.91], [[email protected]])
 AC_CONFIG_SRCDIR([src/tar.c])
 AC_CONFIG_SRCDIR([src/tar.c])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h:config.hin])
 AC_CONFIG_HEADERS([config.h:config.hin])

+ 75 - 54
doc/tar.texi

@@ -2905,13 +2905,6 @@ characters set by the previous @option{--quote-chars} option
 With this option, @command{tar} will not recurse into directories.
 With this option, @command{tar} will not recurse into directories.
 @xref{recurse}.
 @xref{recurse}.
 
 
-@opsummary{no-transform-symlinks}
-@item --no-transform-symlinks
-Cancel the effect of any prior @command{--transform-symlinks} option
-(see below) and return to the default behavior of applying name
-transformation expression only to the names of files (archive
-members), not to target of symbolic links.
-
 @opsummary{no-same-owner}
 @opsummary{no-same-owner}
 @item --no-same-owner
 @item --no-same-owner
 @itemx -o
 @itemx -o
@@ -3292,11 +3285,6 @@ To see transformed member names in verbose listings, use
 @option{--show-transformed-names} option
 @option{--show-transformed-names} option
 (@pxref{show-transformed-names}).
 (@pxref{show-transformed-names}).
 
 
-@opsummary{transform-symlinks}
-@item --transform-symlinks
-Apply @command{--transform} option to symbolic link targets
-(@pxref{transform}).
-
 @opsummary{uncompress}
 @opsummary{uncompress}
 @item --uncompress
 @item --uncompress
 
 
@@ -7605,8 +7593,8 @@ The option @option{--strip=2} instructs @command{tar} to strip the
 two leading components (@file{usr/} and @file{include/}) off the file
 two leading components (@file{usr/} and @file{include/}) off the file
 name.
 name.
 
 
-If you add to the above invocation @option{--verbose} (@option{-v})
-option, you will note that the verbose listing still contains the
+If you add the @option{--verbose} (@option{-v}) option to the invocation
+above, you will note that the verbose listing still contains the
 full file name, with the two removed components still in place.  This
 full file name, with the two removed components still in place.  This
 can be inconvenient, so @command{tar} provides a special option for
 can be inconvenient, so @command{tar} provides a special option for
 altering this behavior:
 altering this behavior:
@@ -7631,7 +7619,7 @@ stdlib.h
 @end group
 @end group
 @end smallexample
 @end smallexample
 
 
-Notice that in both cases the file is @file{stdlib.h} extracted to the
+Notice that in both cases the file @file{stdlib.h} is extracted to the
 current working directory, @option{--show-transformed-names} affects
 current working directory, @option{--show-transformed-names} affects
 only the way its name is displayed.
 only the way its name is displayed.
 
 
@@ -7677,6 +7665,21 @@ replacement for each file name part that matches @var{regexp}.  Both
 @var{regexp} and @var{replace} are described in detail in
 @var{regexp} and @var{replace} are described in detail in
 @ref{The "s" Command, The "s" Command, The `s' Command, sed, GNU sed}.
 @ref{The "s" Command, The "s" Command, The `s' Command, sed, GNU sed}.
 
 
+Any delimiter can be used in lieue of @samp{/}, the only requirement being
+that it be used consistently throughout the expression. For example,
+the following two expressions are equivalent:
+
+@smallexample
+@group
+s/one/two/
+s,one,two,
+@end group
+@end smallexample
+
+Changing delimiters is often useful when the @var{regex} contains
+slashes.  For example, it is more convenient to write @code{s,/,-,} than
+@code{s/\//-/}.
+
 As in @command{sed}, you can give several replace expressions,
 As in @command{sed}, you can give several replace expressions,
 separated by a semicolon.
 separated by a semicolon.
 
 
@@ -7707,21 +7710,41 @@ the interaction is defined to be: ignore matches before the
 
 
 @end table
 @end table
 
 
-Any delimiter can be used in lieue of @samp{/}, the only requirement being
-that it be used consistently throughout the expression. For example,
-the following two expressions are equivalent:
+In addition, several @dfn{transformation scope} flags are supported,
+that control to what files transformations apply.  These are:
+
+@table @samp
+@item r
+Apply transformation to regular archive members.
+
+@item R
+Do not apply transformation to regular archive members.
+
+@item s
+Apply transformation to symbolic link targets.
+
+@item S
+Do not apply transformation to symbolic link targets.
+
+@item h
+Apply transformation to hard link targets.
+
+@item H
+Do not apply transformation to hard link targets.
+@end table
+
+Default is @samp{rsh}, which means to apply tranformations to both archive
+members and targets of symbolic and hard links.
+
+Default scope flags can also be changed using @samp{flags=} statement
+in the transform expression.  The flags set this way remain in force
+until next @samp{flags=} statement or end of expression, whichever
+occurs first.  For example:
 
 
 @smallexample
 @smallexample
-@group
-s/one/two/
-s,one,two,
-@end group
+  --transform 'flags=S;s|^|/usr/local/|'
 @end smallexample
 @end smallexample
 
 
-Changing delimiters is often useful when the @var{regex} contains
-slashes.  For example, it is more convenient to write @code{s,/,-,} than
-@code{s/\//-/}.
-
 Here are several examples of @option{--transform} usage:
 Here are several examples of @option{--transform} usage:
 
 
 @enumerate
 @enumerate
@@ -7738,61 +7761,59 @@ $ @kbd{tar --transform='s,usr/,usr/local/,' -x -f arch.tar}
 $ @kbd{tar --transform='s,/*[^/]*/[^/]*/,,' -x -f arch.tar}
 $ @kbd{tar --transform='s,/*[^/]*/[^/]*/,,' -x -f arch.tar}
 @end smallexample
 @end smallexample
 
 
+@item Convert each file name to lower case:
+
+@smallexample
+$ @kbd{tar --transform 's/.*/\L&/' -x -f arch.tar}
+@end smallexample
+
 @item Prepend @file{/prefix/}  to each file name:
 @item Prepend @file{/prefix/}  to each file name:
 
 
 @smallexample
 @smallexample
 $ @kbd{tar --transform 's,^,/prefix/,' -x -f arch.tar}
 $ @kbd{tar --transform 's,^,/prefix/,' -x -f arch.tar}
 @end smallexample
 @end smallexample
 
 
-@item Convert each file name to lower case:
+@item Archive the @file{/lib} directory, prepending @samp{/usr/local}
+to each archive member:
 
 
 @smallexample
 @smallexample
-$ @kbd{tar --transform 's/.*/\L&/' -x -f arch.tar}
+$ @kbd{tar --transform 's,^,/usr/local/,S' -c -f arch.tar /lib}
 @end smallexample
 @end smallexample
-
 @end enumerate
 @end enumerate
 
 
-The @option{--transform} option applies only to member names.  It does
-not apply to symbolic link targets.  In many cases, this is the
-desired behavior.  Consider for example, archiving the @file{/lib}
-directory: 
+Notice the use of flags in the last example.  The @file{/lib}
+directory often contains many symbolic links to files within it.
+It may look, for example, like this:
 
 
 @smallexample
 @smallexample
-$ @kbd{tar -vv -c -f archive /lib}
-tar: Removing leading `/' from member names
+$ @kbd{ls -l}
 drwxr-xr-x root/root       0 2008-07-08 16:20 /lib/
 drwxr-xr-x root/root       0 2008-07-08 16:20 /lib/
 -rwxr-xr-x root/root 1250840 2008-05-25 07:44 /lib/libc-2.3.2.so
 -rwxr-xr-x root/root 1250840 2008-05-25 07:44 /lib/libc-2.3.2.so
 lrwxrwxrwx root/root       0 2008-06-24 17:12 /lib/libc.so.6 -> libc-2.3.2.so
 lrwxrwxrwx root/root       0 2008-06-24 17:12 /lib/libc.so.6 -> libc-2.3.2.so
 ...
 ...
 @end smallexample
 @end smallexample
 
 
-Now, you can use our example above to extract it into @file{/usr/local}:
+Using the expression @samp{s,^,/usr/local/,} would mean adding
+@samp{/usr/local} to both regular archive members and to link
+targets. In this case, @file{/lib/libc.so.6} would become:
+
+@smallexample
+  /usr/local/lib/libc.so.6 -> /usr/local/libc-2.3.2.so
+@end smallexample
+
+This is definitely not desired.  To avoid this, the @samp{S} flag
+are used, which excludes symbolic link targets from filename
+transformations.  The result is:
 
 
 @smallexample
 @smallexample
-$ @kbd{tar --transform 's,^,/usr/local/,' \
-  --show-transformed -v -x -f archive}
+$ @kbd{tar --transform 's,^,/usr/local/,S', -c -v -f arch.tar \
+       --show-transformed /lib}
 drwxr-xr-x root/root       0 2008-07-08 16:20 /usr/local/lib/
 drwxr-xr-x root/root       0 2008-07-08 16:20 /usr/local/lib/
 -rwxr-xr-x root/root 1250840 2008-05-25 07:44 /usr/local/lib/libc-2.3.2.so
 -rwxr-xr-x root/root 1250840 2008-05-25 07:44 /usr/local/lib/libc-2.3.2.so
 lrwxrwxrwx root/root       0 2008-06-24 17:12 /usr/local/lib/libc.so.6 ->
 lrwxrwxrwx root/root       0 2008-06-24 17:12 /usr/local/lib/libc.so.6 ->
 libc-2.3.2.so
 libc-2.3.2.so
 @end smallexample
 @end smallexample
 
 
-As you see, it correctly extracts @file{libc.so.6} as a symbolic link
-to @file{libc-2.3.2.so}.
-
-However, sometimes you may need to transform symbolic link targets as
-well.  To do so, @GNUTAR provides an additional option:
-
-@table @option
-@opindex transform-symlinks
-@item --transform-symlinks
-Apply @command{--transform} option to symbolic link targets.
-
-@opindex no-transform-symlinks
-@itemx --no-transform-symlinks
-Cancel the effect of the previous @option{--transform-symlinks} option.
-@end table
-
 Unlike @option{--strip-components}, @option{--transform} can be used
 Unlike @option{--strip-components}, @option{--transform} can be used
 in any @GNUTAR{} operation mode.  For example, the following command
 in any @GNUTAR{} operation mode.  For example, the following command
 adds files to the archive while replacing the leading @file{usr/}
 adds files to the archive while replacing the leading @file{usr/}

+ 2 - 0
lib/.cvsignore

@@ -35,6 +35,7 @@ chdir-long.h
 chown.c
 chown.c
 close-stream.c
 close-stream.c
 close-stream.h
 close-stream.h
+close.c
 closeout.c
 closeout.c
 closeout.h
 closeout.h
 config.charset
 config.charset
@@ -59,6 +60,7 @@ fchdir.c
 fchmodat.c
 fchmodat.c
 fchown-stub.c
 fchown-stub.c
 fchownat.c
 fchownat.c
+fclose.c
 fcntl--.h
 fcntl--.h
 fcntl-safer.h
 fcntl-safer.h
 fcntl.h
 fcntl.h

+ 8 - 12
src/common.h

@@ -346,9 +346,6 @@ GLOBAL bool unquote_option;
 
 
 GLOBAL bool test_label_option; /* Test archive volume label and exit */
 GLOBAL bool test_label_option; /* Test archive volume label and exit */
 
 
-/* Apply transformations to symlink targets as well. */
-GLOBAL bool transform_symlinks_option;
-
 /* Show file or archive names after transformation.
 /* Show file or archive names after transformation.
    In particular, when creating archive in verbose mode, list member names
    In particular, when creating archive in verbose mode, list member names
    as stored in the archive */
    as stored in the archive */
@@ -738,17 +735,16 @@ bool string_ascii_p (const char *str);
 bool utf8_convert (bool to_utf, char const *input, char **output);
 bool utf8_convert (bool to_utf, char const *input, char **output);
 
 
 /* Module transform.c */
 /* Module transform.c */
-typedef enum
-  {
-    xform_regfile,
-    xform_link,
-    xform_symlink
-  } xform_type;
+#define XFORM_REGFILE  0x01
+#define XFORM_LINK     0x02
+#define XFORM_SYMLINK  0x04
+#define XFORM_ALL      (XFORM_REGFILE|XFORM_LINK|XFORM_SYMLINK)
 
 
 void set_transform_expr (const char *expr);
 void set_transform_expr (const char *expr);
-bool transform_name (char **pinput);
-bool transform_member_name (char **pinput, xform_type type);
-bool transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *);
+bool transform_name (char **pinput, int type);
+bool transform_member_name (char **pinput, int type);
+bool transform_name_fp (char **pinput, int type,
+			char *(*fun)(char *, void *), void *);
 
 
 /* Module suffix.c */
 /* Module suffix.c */
 void set_comression_program_by_suffix (const char *name, const char *defprog);
 void set_comression_program_by_suffix (const char *name, const char *defprog);

+ 2 - 3
src/create.c

@@ -1495,7 +1495,7 @@ dump_file0 (struct tar_stat_info *st, const char *p,
   assign_string (&st->file_name,
   assign_string (&st->file_name,
                  safer_name_suffix (p, false, absolute_names_option));
                  safer_name_suffix (p, false, absolute_names_option));
 
 
-  transform_name (&st->file_name);
+  transform_name (&st->file_name, XFORM_REGFILE);
 
 
   if (deref_stat (dereference_option, p, &st->stat) != 0)
   if (deref_stat (dereference_option, p, &st->stat) != 0)
     {
     {
@@ -1705,8 +1705,7 @@ dump_file0 (struct tar_stat_info *st, const char *p,
 	}
 	}
       buffer[size] = '\0';
       buffer[size] = '\0';
       assign_string (&st->link_name, buffer);
       assign_string (&st->link_name, buffer);
-      if (transform_symlinks_option)
-	transform_name (&st->link_name);
+      transform_name (&st->link_name, XFORM_SYMLINK);
       if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
       if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
 	write_long_link (st);
 	write_long_link (st);
 
 

+ 0 - 3
src/extract.c

@@ -917,7 +917,6 @@ extract_link (char *file_name, int typeflag)
   int interdir_made = 0;
   int interdir_made = 0;
   char const *link_name;
   char const *link_name;
 
 
-  transform_member_name (&current_stat_info.link_name, xform_link);
   link_name = current_stat_info.link_name;
   link_name = current_stat_info.link_name;
   
   
   if (! absolute_names_option && contains_dot_dot (link_name))
   if (! absolute_names_option && contains_dot_dot (link_name))
@@ -974,8 +973,6 @@ extract_symlink (char *file_name, int typeflag)
   int status;
   int status;
   int interdir_made = 0;
   int interdir_made = 0;
 
 
-  transform_member_name (&current_stat_info.link_name, xform_symlink);
-
   if (! absolute_names_option
   if (! absolute_names_option
       && (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name)
       && (IS_ABSOLUTE_FILE_NAME (current_stat_info.link_name)
 	  || contains_dot_dot (current_stat_info.link_name)))
 	  || contains_dot_dot (current_stat_info.link_name)))

+ 16 - 7
src/list.c

@@ -472,11 +472,11 @@ read_header (bool raw_extended_headers)
 static char *
 static char *
 decode_xform (char *file_name, void *data)
 decode_xform (char *file_name, void *data)
 {
 {
-  xform_type type = *(xform_type*)data;
+  int type = *(int*)data;
 
 
   switch (type)
   switch (type)
     {
     {
-    case xform_symlink:
+    case XFORM_SYMLINK:
       /* FIXME: It is not quite clear how and to which extent are the symbolic
       /* FIXME: It is not quite clear how and to which extent are the symbolic
 	 links subject to filename transformation.  In the absence of another
 	 links subject to filename transformation.  In the absence of another
 	 solution, symbolic links are exempt from component stripping and
 	 solution, symbolic links are exempt from component stripping and
@@ -484,11 +484,11 @@ decode_xform (char *file_name, void *data)
 	 proper. */ 
 	 proper. */ 
       return file_name;
       return file_name;
       
       
-    case xform_link:
+    case XFORM_LINK:
       file_name = safer_name_suffix (file_name, true, absolute_names_option);
       file_name = safer_name_suffix (file_name, true, absolute_names_option);
       break;
       break;
       
       
-    case xform_regfile:
+    case XFORM_REGFILE:
       file_name = safer_name_suffix (file_name, false, absolute_names_option);
       file_name = safer_name_suffix (file_name, false, absolute_names_option);
       break;
       break;
     }
     }
@@ -505,9 +505,9 @@ decode_xform (char *file_name, void *data)
 }
 }
 
 
 bool
 bool
-transform_member_name (char **pinput, xform_type type)
+transform_member_name (char **pinput, int type)
 {
 {
-  return transform_name_fp (pinput, decode_xform, &type);
+  return transform_name_fp (pinput, type, decode_xform, &type);
 }
 }
 
 
 #define ISOCTAL(c) ((c)>='0'&&(c)<='7')
 #define ISOCTAL(c) ((c)>='0'&&(c)<='7')
@@ -628,7 +628,16 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
 	stat_info->is_dumpdir = true;
 	stat_info->is_dumpdir = true;
     }
     }
 
 
-  transform_member_name (&stat_info->file_name, xform_regfile);
+  transform_member_name (&stat_info->file_name, XFORM_REGFILE);
+  switch (header->header.typeflag)
+    {
+    case SYMTYPE:
+      transform_member_name (&stat_info->link_name, XFORM_SYMLINK);
+      break;
+      
+    case LNKTYPE:
+      transform_member_name (&stat_info->link_name, XFORM_LINK);
+    }
 }
 }
 
 
 /* Convert buffer at WHERE0 of size DIGS from external format to
 /* Convert buffer at WHERE0 of size DIGS from external format to

+ 0 - 14
src/tar.c

@@ -287,7 +287,6 @@ enum
   NO_RECURSION_OPTION,
   NO_RECURSION_OPTION,
   NO_SAME_OWNER_OPTION,
   NO_SAME_OWNER_OPTION,
   NO_SAME_PERMISSIONS_OPTION,
   NO_SAME_PERMISSIONS_OPTION,
-  NO_TRANSFORM_SYMLINKS_OPTION,
   NO_UNQUOTE_OPTION,
   NO_UNQUOTE_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_OPTION,
   NO_WILDCARDS_OPTION,
@@ -322,7 +321,6 @@ enum
   TOTALS_OPTION,
   TOTALS_OPTION,
   TO_COMMAND_OPTION,
   TO_COMMAND_OPTION,
   TRANSFORM_OPTION,
   TRANSFORM_OPTION,
-  TRANSFORM_SYMLINKS_OPTION,
   UNQUOTE_OPTION,
   UNQUOTE_OPTION,
   USAGE_OPTION,
   USAGE_OPTION,
   USE_COMPRESS_PROGRAM_OPTION,
   USE_COMPRESS_PROGRAM_OPTION,
@@ -689,10 +687,6 @@ static struct argp_option options[] = {
   {"transform", TRANSFORM_OPTION, N_("EXPRESSION"), 0,
   {"transform", TRANSFORM_OPTION, N_("EXPRESSION"), 0,
    N_("use sed replace EXPRESSION to transform file names"), GRID+1 },
    N_("use sed replace EXPRESSION to transform file names"), GRID+1 },
   {"xform", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
   {"xform", 0, 0, OPTION_ALIAS, NULL, GRID+1 },
-  {"transform-symlinks", TRANSFORM_SYMLINKS_OPTION, NULL, 0,
-   N_("apply transformations to symlink targets"), GRID+1 },
-  {"no-transform-symlinks", NO_TRANSFORM_SYMLINKS_OPTION, NULL, 0,
-   N_("cancel effect of the previous --transform-symlinks option"), GRID+1 },
 #undef GRID
 #undef GRID
 
 
 #define GRID 120
 #define GRID 120
@@ -1911,14 +1905,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
       set_transform_expr (arg);
       set_transform_expr (arg);
       break;
       break;
 
 
-    case TRANSFORM_SYMLINKS_OPTION:
-      transform_symlinks_option = true;
-      break;
-
-    case NO_TRANSFORM_SYMLINKS_OPTION:
-      transform_symlinks_option = false;
-      break;
-      
     case USE_COMPRESS_PROGRAM_OPTION:
     case USE_COMPRESS_PROGRAM_OPTION:
       set_use_compress_program_option (arg);
       set_use_compress_program_option (arg);
       break;
       break;

+ 78 - 14
src/transform.c

@@ -61,6 +61,7 @@ struct transform
 {
 {
   struct transform *next;
   struct transform *next;
   enum transform_type transform_type;
   enum transform_type transform_type;
+  int flags;
   unsigned match_number;
   unsigned match_number;
   regex_t regex;
   regex_t regex;
   /* Compiled replacement expression */
   /* Compiled replacement expression */
@@ -69,6 +70,8 @@ struct transform
 };
 };
 
 
 
 
+
+int transform_flags = XFORM_ALL;
 static struct transform *transform_head, *transform_tail;
 static struct transform *transform_head, *transform_tail;
 
 
 static struct transform *
 static struct transform *
@@ -131,6 +134,41 @@ add_backref_segment (struct transform *tf, size_t ref)
   segm->v.ref = 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
 static void
 add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl)
 add_case_ctl_segment (struct transform *tf, enum case_ctl_type ctl)
 {
 {
@@ -150,8 +188,26 @@ parse_transform_expr (const char *expr)
   struct transform *tf = new_transform ();
   struct transform *tf = new_transform ();
 
 
   if (expr[0] != 's')
   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];
   delim = expr[1];
 
 
   /* Scan regular expression */
   /* Scan regular expression */
@@ -172,6 +228,7 @@ parse_transform_expr (const char *expr)
 
 
   /* Check flags */
   /* Check flags */
   tf->transform_type = transform_first;
   tf->transform_type = transform_first;
+  tf->flags = transform_flags;
   for (p = expr + j + 1; *p && *p != ';'; p++)
   for (p = expr + j + 1; *p && *p != ';'; p++)
     switch (*p)
     switch (*p)
       {
       {
@@ -186,7 +243,7 @@ parse_transform_expr (const char *expr)
       case 'x':
       case 'x':
 	cflags |= REG_EXTENDED;
 	cflags |= REG_EXTENDED;
 	break;
 	break;
-	
+
       case '0': case '1': case '2': case '3': case '4':
       case '0': case '1': case '2': case '3': case '4':
       case '5': case '6': case '7': case '8': case '9':
       case '5': case '6': case '7': case '8': case '9':
 	tf->match_number = strtoul (p, (char**) &p, 0);
 	tf->match_number = strtoul (p, (char**) &p, 0);
@@ -194,8 +251,9 @@ parse_transform_expr (const char *expr)
 	break;
 	break;
 
 
       default:
       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 == ';')
   if (*p == ';')
@@ -520,10 +578,11 @@ _single_transform_name_to_obstack (struct transform *tf, char *input)
 }
 }
 
 
 bool
 bool
-_transform_name_to_obstack (char *input, char **output)
+_transform_name_to_obstack (int flags, char *input, char **output)
 {
 {
   struct transform *tf;
   struct transform *tf;
-
+  bool alloced = false;
+  
   if (!stk_init)
   if (!stk_init)
     {
     {
       obstack_init (&stk);
       obstack_init (&stk);
@@ -532,18 +591,23 @@ _transform_name_to_obstack (char *input, char **output)
   
   
   for (tf = transform_head; tf; tf = tf->next)
   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;
   *output = input;
-  return transform_head != NULL;
+  return alloced;
 }
 }
   
   
 bool
 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;
     char *str;
-    bool ret = _transform_name_to_obstack (*pinput, &str);
+    bool ret = _transform_name_to_obstack (flags, *pinput, &str);
     if (ret)
     if (ret)
       {
       {
 	assign_string (pinput, fun ? fun (str, dat) : str);
 	assign_string (pinput, fun ? fun (str, dat) : str);
@@ -560,8 +624,8 @@ transform_name_fp (char **pinput, char *(*fun)(char *, void *), void *dat)
 }
 }
 
 
 bool
 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);
 }
 }