autoconf-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/10] Proper file name escaping in Autoconf programs and Perl


From: Ralf Wildenhues
Subject: Re: [PATCH 1/10] Proper file name escaping in Autoconf programs and Perl modules.
Date: Thu, 6 Dec 2007 22:53:13 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

This includes escaping of characters special to the shell
as well as special to Perl, e.g., leading `<' or `>'.
For example, when $file starts with `>', `open ">$file"'
wrongly tries to append to a different file.

* bin/autoconf.as: Fix quoting for autom4te options.
* lib/Autom4te/General.pm (shell_quote): New function, taken
from coreutils, written by Jim Meyering.
(mktmpdir): Use it.
* lib/Autom4te/FileUtils.pm (open_quote): New function.
(update_file, contents): Use it.
* bin/autom4te.in (files_to_options, handle_m4): Use shell_quote
and open_quote
* bin/autoreconf.in (parse_args): Likewise.
* bin/autoscan.in (main): Likewise.
* bin/autoupdate.in (main): Likewise.
* bin/autoheader.in: Likewise, fixing old insufficient escaping.
* bin/ifnames.in: Likewise, XFile usage fixes.
* tests/tools.at (autom4te and whitespace in file names): Extend
test.  Test twice, with special characters allowed on w32, and the
rest.  Test leading and trailing whitespace, for `open_quote'.
(autotools and whitespace in file names): New, analogous test.
Reported by Paul Eggert and Benoit Sigoure, additional suggestions
by Russ Allbery and Eric Blake.
---

Updated patch which should incorporate all suggestions.

I assume a modified XFile could help avoid many of the additional
function calls; if someone wants to pursue that rather than this
backward-compatible (for Automake) patch, feel free to post a patch.

Cheers,
Ralf

 bin/autoconf.as           |   17 +++++--
 bin/autoheader.in         |   21 ++++----
 bin/autom4te.in           |   38 ++++++--------
 bin/autoreconf.in         |   10 ++--
 bin/autoscan.in           |   18 +++---
 bin/autoupdate.in         |   34 ++++++------
 bin/ifnames.in            |    3 +-
 lib/Autom4te/FileUtils.pm |   29 +++++++++--
 lib/Autom4te/General.pm   |   33 +++++++++++-
 tests/tools.at            |  120 ++++++++++++++++++++++++++++++++++++++++-----
 10 files changed, 236 insertions(+), 87 deletions(-)

diff --git a/bin/autoconf.as b/bin/autoconf.as
index b68d4ef..dbabc30 100644
--- a/bin/autoconf.as
+++ b/bin/autoconf.as
@@ -107,14 +107,21 @@ while test $# -gt 0 ; do
     --include=*  | -I?* | \
     --prepend-include=* | -B?* | \
     --warnings=* | -W?* )
-       autom4te_options="$autom4te_options '$1'"; shift ;;
-
+       case $1 in
+         *\'*) arg=`AS_ECHO(["$1"]) | sed "s/'/'\\\\\\\\''/g"` ;;
+        *) arg=$1 ;;
+       esac
+       autom4te_options="$autom4te_options '$arg'"; shift ;;
     # Options with separated arg passed as is to autom4te.
     --include  | -I | \
     --prepend-include  | -B | \
     --warnings | -W )
        test $# = 1 && eval "$exit_missing_arg"
-       autom4te_options="$autom4te_options $option '$2'"
+       case $2 in
+         *\'*) arg=`AS_ECHO(["$2"]) | sed "s/'/'\\\\\\\\''/g"` ;;
+        *) arg=$2 ;;
+       esac
+       autom4te_options="$autom4te_options $option '$arg'"
        shift; shift ;;
 
     --trace=* | -t?* )
@@ -178,8 +185,8 @@ esac
 test -z "$outfile" && outfile=-
 
 # Run autom4te with expansion.
-eval set x $autom4te_options \
-  --language=autoconf --output=\$outfile "$traces" \$infile
+eval set x "$autom4te_options" \
+  --language=autoconf --output=\"\$outfile\" "$traces" \"\$infile\"
 shift
 $verbose && AS_ECHO(["$as_me: running $AUTOM4TE $*"]) >&2
 exec "$AUTOM4TE" "$@"
diff --git a/bin/autoheader.in b/bin/autoheader.in
index 9c19ea3..2565db2 100644
--- a/bin/autoheader.in
+++ b/bin/autoheader.in
@@ -157,8 +157,8 @@ END
 
 # Set up autoconf.
 my $autoconf = "'$autom4te' --language=autoconf ";
-$autoconf .= join (' ', map { "--include='$_'" } @include);
-$autoconf .= join (' ', map { "--prepend-include='$_'" } @prepend_include);
+$autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
+$autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } 
@prepend_include);
 $autoconf .= ' --debug' if $debug;
 $autoconf .= ' --force' if $force;
 $autoconf .= ' --verbose' if $verbose;
@@ -169,16 +169,17 @@ $autoconf .= ' --verbose' if $verbose;
 
 # Source what the traces are trying to tell us.
 verb "$me: running $autoconf to trace from $ARGV[0]";
+my $quoted_tmp = shell_quote ($tmp);
 xsystem ("$autoconf"
         # If you change this list, update the
         # `Autoheader-preselections' section of autom4te.in.
         . ' --trace AC_CONFIG_HEADERS:\'$$config_h ||= \'"\'"\'$1\'"\'"\';\''
         . ' --trace AH_OUTPUT:\'$$verbatim{\'"\'"\'$1\'"\'"\'} = 
\'"\'"\'$2\'"\'"\';\''
         . ' --trace AC_DEFINE_TRACE_LITERAL:\'$$symbol{\'"\'"\'$1\'"\'"\'} = 
1;\''
-        . " $ARGV[0] >$tmp/traces.pl");
+        . " " . shell_quote ($ARGV[0]) . " >$quoted_tmp/traces.pl");
 
 local (%verbatim, %symbol);
-debug "$me: \`do'ing $tmp/traces.pl:\n" . `sed 's/^/| /' $tmp/traces.pl`;
+debug "$me: \`do'ing $tmp/traces.pl:\n" . `sed 's/^/| /' 
$quoted_tmp/traces.pl`;
 do "$tmp/traces.pl";
 warn "couldn't parse $tmp/traces.pl: $@" if $@;
 unless ($config_h)
@@ -197,7 +198,7 @@ $config_h_in ||= "$config_h.in";
 # only the name of the macro.
 %symbol = map { s/\(.*//; $_ => 1 } keys %symbol;
 
-my $out = new Autom4te::XFile (">$tmp/config.hin");
+my $out = new Autom4te::XFile ("> " . open_quote ("$tmp/config.hin"));
 
 # Don't write "do not edit" -- it will get copied into the
 # config.h, which it's ok to edit.
@@ -206,7 +207,7 @@ print $out "/* $config_h_in.  Generated from $ARGV[0] by 
autoheader.  */\n";
 # Dump the top.
 if ($config_h_top)
   {
-    my $in = new Autom4te::XFile ($config_h_top);
+    my $in = new Autom4te::XFile ("< " . open_quote ($config_h_top));
     while ($_ = $in->getline)
       {
        print $out $_;
@@ -216,7 +217,7 @@ if ($config_h_top)
 # Dump `acconfig.h', except for its bottom portion.
 if ($acconfig_h)
   {
-    my $in = new Autom4te::XFile ($acconfig_h);
+    my $in = new Autom4te::XFile ("< " . open_quote ($acconfig_h));
     while ($_ = $in->getline)
       {
        last if /address@hidden@/;
@@ -234,7 +235,7 @@ foreach (sort keys %verbatim)
 # Dump bottom portion of `acconfig.h'.
 if ($acconfig_h)
   {
-    my $in = new Autom4te::XFile ($acconfig_h);
+    my $in = new Autom4te::XFile ("< " . open_quote ($acconfig_h));
     my $dump = 0;
     while ($_ = $in->getline)
       {
@@ -246,7 +247,7 @@ if ($acconfig_h)
 # Dump the bottom.
 if ($config_h_bot)
   {
-    my $in = new Autom4te::XFile ($config_h_bot);
+    my $in = new Autom4te::XFile ("< " . open_quote ($config_h_bot));
     while ($_ = $in->getline)
       {
        print $out $_;
@@ -257,7 +258,7 @@ $out->close;
 
 # Check that all the symbols have a template.
 {
-  my $in = new Autom4te::XFile ("$tmp/config.hin");
+  my $in = new Autom4te::XFile ("< " . open_quote ("$tmp/config.hin"));
   my $suggest_ac_define = 1;
   while ($_ = $in->getline)
     {
diff --git a/bin/autom4te.in b/bin/autom4te.in
index b273b9a..8efe537 100644
--- a/bin/autom4te.in
+++ b/bin/autom4te.in
@@ -235,14 +235,10 @@ sub files_to_options (@)
   my @res;
   foreach my $file (@file)
     {
-      (my $arg = $file) =~ s/'/'\\''/g;
+      my $arg = shell_quote ($file);
       if ($file =~ /\.m4f$/)
        {
-         $arg = "--reload-state=$file";
-       }
-      if ($file =~ /[\t "'\\\$()]/)
-       {
-         $arg = "'$arg'";
+         $arg = "--reload-state=$arg";
        }
       push @res, $arg;
     }
@@ -258,7 +254,7 @@ sub load_configuration ($)
   my ($file) = @_;
   use Text::ParseWords;
 
-  my $cfg = new Autom4te::XFile ($file);
+  my $cfg = new Autom4te::XFile ("< " . open_quote ($file));
   my $lang;
   while ($_ = $cfg->getline)
     {
@@ -462,13 +458,13 @@ sub handle_m4 ($@)
   # We don't output directly to the cache files, to avoid problems
   # when we are interrupted (that leaves corrupted files).
   xsystem ("$m4"
-          . join (' --include=', '', @include)
+          . join (' --include=', '', map { shell_quote ($_) } @include)
           . ' --debug=aflq'
           . (!exists $ENV{'AUTOM4TE_NO_FATAL'} ? ' --fatal-warning' : '')
-          . " @address@hidden" . $req->id . "t"
+          . " @address@hidden" . shell_quote ("$tcache" . $req->id . "t")
           . join (' --trace=',   '', sort @macro)
           . " " . files_to_options (@ARGV)
-          . " >$ocache" . $req->id . "t");
+          . " > " . shell_quote ("$ocache" . $req->id . "t"));
 
   # Everything went ok: preserve the outputs.
   foreach my $file (map { $_ . $req->id } ($tcache, $ocache))
@@ -526,7 +522,7 @@ sub handle_output ($$)
   handle_traces ($req, "$tmp/patterns",
                 ('m4_pattern_forbid' => 'forbid:$1:$2',
                  'm4_pattern_allow'  => 'allow:$1'));
-  my @patterns = new Autom4te::XFile ("$tmp/patterns")->getlines;
+  my @patterns = new Autom4te::XFile ("< " . open_quote 
("$tmp/patterns"))->getlines;
   chomp @patterns;
   my %forbidden =
     map { /^forbid:([^:]+):.+$/ => /^forbid:[^:]+:(.+)$/ } @patterns;
@@ -553,7 +549,7 @@ sub handle_output ($$)
     }
   fatal "cannot create $output: $!"
     unless $out;
-  my $in = new Autom4te::XFile ($ocache . $req->id);
+  my $in = new Autom4te::XFile ("< " . open_quote ($ocache . $req->id));
 
   my %prohibited;
   my $res;
@@ -594,7 +590,7 @@ sub handle_output ($$)
   if ($ARGV[$#ARGV] ne '-')
     {
       my $prohibited = '\b(' . join ('|', keys %prohibited) . ')\b';
-      my $file = new Autom4te::XFile ($ARGV[$#ARGV]);
+      my $file = new Autom4te::XFile ("< " . open_quote ($ARGV[$#ARGV]));
 
       while ($_ = $file->getline)
        {
@@ -712,7 +708,7 @@ sub handle_traces ($$%)
   verb "formatting traces for `$output': " . join (', ', sort keys %trace);
 
   # Processing the traces.
-  my $trace_m4 = new Autom4te::XFile (">$tmp/traces.m4");
+  my $trace_m4 = new Autom4te::XFile ("> " . open_quote ("$tmp/traces.m4"));
 
   $_ = <<'EOF';
   divert(-1)
@@ -816,7 +812,7 @@ EOF
   #
   # Pay attention that the file name might include colons, if under DOS
   # for instance, so we don't use `[^:]+'.
-  my $traces = new Autom4te::XFile ($tcache . $req->id);
+  my $traces = new Autom4te::XFile ("< " . open_quote ($tcache . $req->id));
   while ($_ = $traces->getline)
     {
       # Trace with arguments, as the example above.  We don't try
@@ -831,8 +827,8 @@ EOF
     }
   $trace_m4->close;
 
-  my $in = new Autom4te::XFile ("$m4 $tmp/traces.m4 |");
-  my $out = new Autom4te::XFile (">$output");
+  my $in = new Autom4te::XFile ("$m4 " . shell_quote ("$tmp/traces.m4") . " 
|");
+  my $out = new Autom4te::XFile ("> " . open_quote ($output));
 
   # This is dubious: should we really transform the quadrigraphs in
   # traces?  It might break balanced [ ] etc. in the output.  The
@@ -892,7 +888,7 @@ sub up_to_date ($)
   handle_traces ($req, "$tmp/dependencies",
                 ('include'    => '$1',
                  'm4_include' => '$1'));
-  my $deps = new Autom4te::XFile ("$tmp/dependencies");
+  my $deps = new Autom4te::XFile ("< " . open_quote ("$tmp/dependencies"));
   while ($_ = $deps->getline)
     {
       chomp;
@@ -925,7 +921,7 @@ sub freeze ($)
   # output but comments and empty lines.
   my $result = xqx ("$m4"
                    . ' --fatal-warning'
-                   . join (' --include=', '', @include)
+                   . join (' --include=', '', map { shell_quote ($_) } 
@include)
                    . ' --define=divert'
                    . " " . files_to_options (@ARGV)
                    . ' </dev/null');
@@ -939,8 +935,8 @@ sub freeze ($)
   # or an improper paren etc.
   xsystem ("$m4"
           . ' --fatal-warning'
-          . join (' --include=', '', @include)
-          . " --freeze-state=$output"
+          . join (' --include=', '', map { shell_quote ($_) } @include)
+          . " --freeze-state=" . shell_quote ($output)
           . " " . files_to_options (@ARGV)
           . ' </dev/null');
 }
diff --git a/bin/autoreconf.in b/bin/autoreconf.in
index c964b03..e707446 100644
--- a/bin/autoreconf.in
+++ b/bin/autoreconf.in
@@ -182,10 +182,10 @@ sub parse_args ()
 
   # Dispatch autoreconf's option to the tools.
   # --include;
-  $autoconf   .= join (' --include=', '', @include);
-  $autoconf   .= join (' --prepend-include=', '', @prepend_include);
-  $autoheader .= join (' --include=', '', @include);
-  $autoheader .= join (' --prepend-include=', '', @prepend_include);
+  $autoconf   .= join (' --include=', '', map { shell_quote ($_) } @include);
+  $autoconf   .= join (' --prepend-include=', '', map { shell_quote ($_) } 
@prepend_include);
+  $autoheader .= join (' --include=', '', map { shell_quote ($_) } @include);
+  $autoheader .= join (' --prepend-include=', '', map { shell_quote ($_) } 
@prepend_include);
 
   # --install and --symlink;
   if ($install)
@@ -316,7 +316,7 @@ sub autoreconf_current_directory ()
   my $uses_gettext;
   if (-f $configure_ac)
     {
-      my $configure_ac_file = new Autom4te::XFile $configure_ac;
+      my $configure_ac_file = new Autom4te::XFile "< $configure_ac";
       while ($_ = $configure_ac_file->getline)
        {
          s/#.*//;
diff --git a/bin/autoscan.in b/bin/autoscan.in
index 372a878..59227e2 100644
--- a/bin/autoscan.in
+++ b/bin/autoscan.in
@@ -166,7 +166,7 @@ sub init_tables ()
   # instead of duplicating the code in lots of configure.ac files.
   my $file = find_file ("autoscan/autoscan.list",
                        reverse (@prepend_include), @include);
-  my $table = new Autom4te::XFile $file;
+  my $table = new Autom4te::XFile "< " . open_quote ($file);
   my $tables_are_consistent = 1;
 
   while ($_ = $table->getline)
@@ -241,7 +241,7 @@ sub scan_c_file ($)
   # Nonzero if in a multiline comment.
   my $in_comment = 0;
 
-  my $file = new Autom4te::XFile "<$file_name";
+  my $file = new Autom4te::XFile "< " . open_quote ($file_name);
 
   while ($_ = $file->getline)
     {
@@ -307,7 +307,7 @@ sub scan_makefile ($)
   my ($file_name) = @_;
   push @makefiles, $File::Find::name;
 
-  my $file = new Autom4te::XFile "<$file_name";
+  my $file = new Autom4te::XFile "< " . open_quote ($file_name);
 
   while ($_ = $file->getline)
     {
@@ -349,7 +349,7 @@ sub scan_sh_file ($)
   my ($file_name) = @_;
   push @shfiles, $File::Find::name;
 
-  my $file = new Autom4te::XFile "<$file_name";
+  my $file = new Autom4te::XFile "< " . open_quote ($file_name);
 
   while ($_ = $file->getline)
     {
@@ -518,7 +518,7 @@ sub output ($)
   my $configure_scan = shift;
   my %unique_makefiles;
 
-  my $file = new Autom4te::XFile ">$configure_scan";
+  my $file = new Autom4te::XFile "> " . open_quote ($configure_scan);
 
   print $file
     ("#                                               -*- Autoconf -*-\n" .
@@ -587,7 +587,7 @@ sub check_configure_ac ($)
 
   verb "running: $autoconf $trace_option $configure_ac";
   my $traces =
-    new Autom4te::XFile "$autoconf $trace_option $configure_ac|";
+    new Autom4te::XFile "$autoconf $trace_option $configure_ac |";
 
   while ($_ = $traces->getline)
     {
@@ -636,12 +636,12 @@ sub check_configure_ac ($)
 ## -------------- ##
 
 parse_args;
-$log = new Autom4te::XFile ">$me.log";
+$log = new Autom4te::XFile "> " . open_quote ("$me.log");
 
 $autoconf .= " --debug" if $debug;
 $autoconf .= " --verbose" if $verbose;
-$autoconf .= join (' --include=', '', @include);
-$autoconf .= join (' --prepend-include=', '', @prepend_include);
+$autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
+$autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } 
@prepend_include);
 
 my $configure_ac = find_configure_ac;
 init_tables;
diff --git a/bin/autoupdate.in b/bin/autoupdate.in
index d69211d..23060f2 100644
--- a/bin/autoupdate.in
+++ b/bin/autoupdate.in
@@ -127,8 +127,8 @@ my (%ac_macros, %au_macros, %m4_builtins);
 sub handle_autoconf_macros ()
 {
   # Get the builtins.
-  xsystem ("echo dumpdef | $m4 2>$tmp/m4.defs >/dev/null");
-  my $m4_defs = new Autom4te::XFile "$tmp/m4.defs";
+  xsystem ("echo dumpdef | $m4 2>" . shell_quote ("$tmp/m4.defs") . " 
>/dev/null");
+  my $m4_defs = new Autom4te::XFile "< " . open_quote ("$tmp/m4.defs");
   while ($_ = $m4_defs->getline)
     {
       $m4_builtins{$1} = 1
@@ -184,9 +184,9 @@ sub handle_autoconf_macros ()
 
   # ac.m4 -- autoquoting definitions of the AC macros (M4sugar excluded).
   # unac.m4 -- undefine the AC macros.
-  my $ac_m4 = new Autom4te::XFile ">$tmp/ac.m4";
+  my $ac_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/ac.m4");
   print $ac_m4 "# ac.m4 -- autoquoting definitions of the AC macros.\n";
-  my $unac_m4 = new Autom4te::XFile ">$tmp/unac.m4";
+  my $unac_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/unac.m4");
   print $unac_m4 "# unac.m4 -- undefine the AC macros.\n";
   foreach (sort keys %ac_macros)
     {
@@ -197,11 +197,11 @@ sub handle_autoconf_macros ()
   # m4save.m4 -- save the m4 builtins.
   # unm4.m4 -- disable the m4 builtins.
   # m4.m4 -- enable the m4 builtins.
-  my $m4save_m4 = new Autom4te::XFile ">$tmp/m4save.m4";
+  my $m4save_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/m4save.m4");
   print $m4save_m4 "# m4save.m4 -- save the m4 builtins.\n";
-  my $unm4_m4 = new Autom4te::XFile ">$tmp/unm4.m4";
+  my $unm4_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/unm4.m4");
   print $unm4_m4 "# unm4.m4 -- disable the m4 builtins.\n";
-  my $m4_m4 = new Autom4te::XFile ">$tmp/m4.m4";
+  my $m4_m4 = new Autom4te::XFile "> " . open_quote ("$tmp/m4.m4");
   print $m4_m4 "# m4.m4 -- enable the m4 builtins.\n";
   foreach (sort keys %m4_builtins)
     {
@@ -220,8 +220,8 @@ parse_args;
 $autoconf .= " --debug" if $debug;
 $autoconf .= " --force" if $force;
 $autoconf .= " --verbose" if $verbose;
-$autoconf .= join (' --include=', '', @include);
-$autoconf .= join (' --prepend-include=', '', @prepend_include);
+$autoconf .= join (' --include=', '', map { shell_quote ($_) } @include);
+$autoconf .= join (' --prepend-include=', '', map { shell_quote ($_) } 
@prepend_include);
 
 mktmpdir ('au');
 handle_autoconf_macros;
@@ -233,7 +233,7 @@ my $au_changequote =
 # au.m4 -- definitions the AU macros.
 xsystem ("$autoconf --trace AU_DEFINE:'_au_defun(\@<:address@hidden@:>\@,
 \@<:address@hidden@:>\@)' --melt /dev/null "
-       . ">$tmp/au.m4");
+       . ">" . shell_quote ("$tmp/au.m4"));
 
 
 
@@ -247,7 +247,7 @@ foreach my $file (@ARGV)
     if ($file eq '-')
       {
        $file = "$tmp/stdin";
-       system "cat >$file";
+       system "cat >" . shell_quote ($file);
       }
     elsif (! -r "$file")
       {
@@ -376,9 +376,9 @@ EOF
     $input_m4 =~ s/\$file/$file/g;
 
     # prepared input -- input, but reenables the quote before each AU macro.
-    open INPUT_M4, ">$tmp/input.m4"
+    open INPUT_M4, "> " . open_quote ("$tmp/input.m4")
        or error "cannot open: $!";
-    open FILE, "<$file"
+    open FILE, "< " . open_quote ($file)
        or error "cannot open: $!";
     print INPUT_M4 "$input_m4";
     while (<FILE>)
@@ -392,10 +392,10 @@ EOF
        or error "cannot close $tmp/input.m4: $!";
 
     # Now ask m4 to perform the update.
-    xsystem ("$m4 --include=$tmp"
-            . join (' --include=', '', reverse (@prepend_include))
-            . join (' --include=', '', @include)
-            . " $tmp/input.m4 >$tmp/updated");
+    xsystem ("$m4 --include=" . shell_quote ($tmp)
+            . join (' --include=', '', map { shell_quote ($_) } reverse 
(@prepend_include))
+            . join (' --include=', '', map { shell_quote ($_) } @include)
+            . " " . shell_quote ("$tmp/input.m4") . " > " . shell_quote 
("$tmp/updated"));
     update_file ("$tmp/updated",
                 "$file" eq "$tmp/stdin" ? '-' : "$file");
   }
diff --git a/bin/ifnames.in b/bin/ifnames.in
index d7c36ba..bd65bbf 100644
--- a/bin/ifnames.in
+++ b/bin/ifnames.in
@@ -43,6 +43,7 @@ BEGIN
 
 use Autom4te::General;
 use Autom4te::XFile;
+use Autom4te::FileUtils;
 
 # $HELP
 # -----
@@ -92,7 +93,7 @@ my %occurrence;
 sub scan_file ($)
 {
   my ($file_name) = @_;
-  my $file = new Autom4te::XFile ($file_name);
+  my $file = new Autom4te::XFile ("< " . open_quote ($file_name));
   while ($_ = $file->getline)
     {
       # Continuation lines.
diff --git a/lib/Autom4te/FileUtils.pm b/lib/Autom4te/FileUtils.pm
index 3c9c1ba..e49ae31 100644
--- a/lib/Autom4te/FileUtils.pm
+++ b/lib/Autom4te/FileUtils.pm
@@ -1,4 +1,4 @@
-# Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+# Copyright (C) 2003, 2004, 2005, 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
@@ -44,12 +44,33 @@ use Autom4te::ChannelDefs;
 use vars qw (@ISA @EXPORT);
 
 @ISA = qw (Exporter);
address@hidden = qw (&contents
address@hidden = qw (&open_quote &contents
              &find_file &mtime
              &update_file &up_to_date_p
              &xsystem &xqx &dir_has_case_matching_file &reset_dir_cache);
 
 
+=item C<open_quote ($file_name)>
+
+Quote C<$file_name> for open.
+
+=cut
+
+# $FILE_NAME
+# open_quote ($FILE_NAME)
+# -----------------------
+# If the string $S is a well-behaved file name, simply return it.
+# If it starts with white space, prepend `./'.  Return the new string.
+sub open_quote($)
+{
+  my ($s) = @_;
+  if ($s =~ m!^\s!)
+    {
+      $s = "./$s";
+    }
+  return $s;
+}
+
 =item C<find_file ($file_name, @include)>
 
 Return the first path for a C<$file_name> in the C<include>s.
@@ -139,7 +160,7 @@ sub update_file ($$;$)
 
   if ($to eq '-')
     {
-      my $in = new IO::File ("$from");
+      my $in = new IO::File ("< " . open_quote ($from));
       my $out = new IO::File (">-");
       while ($_ = $in->getline)
        {
@@ -303,7 +324,7 @@ sub contents ($)
   my ($file) = @_;
   verb "reading $file";
   local $/;                    # Turn on slurp-mode.
-  my $f = new Autom4te::XFile "< $file";
+  my $f = new Autom4te::XFile "< " . open_quote ($file);
   my $contents = $f->getline;
   $f->close;
   return $contents;
diff --git a/lib/Autom4te/General.pm b/lib/Autom4te/General.pm
index b79467f..5639e4c 100644
--- a/lib/Autom4te/General.pm
+++ b/lib/Autom4te/General.pm
@@ -1,5 +1,6 @@
 # autoconf -- create `configure' using m4 macros
-# Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2002, 2003, 2004, 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
@@ -53,7 +54,7 @@ my @export_vars =
 # Functions we define and export.
 my @export_subs =
   qw (&debug
-      &getopt &mktmpdir
+      &getopt &shell_quote &mktmpdir
       &uniq);
 
 # Functions we forward (coming from modules we use).
@@ -281,6 +282,31 @@ sub getopt (%)
 }
 
 
+=item C<shell_quote ($file_name)>
+
+Quote C<$file_name> for the shell.
+
+=cut
+
+# $FILE_NAME
+# shell_quote ($FILE_NAME)
+# ------------------------
+# If the string $S is a well-behaved file name, simply return it.
+# If it contains white space, quotes, etc., quote it, and return
+# the new string.
+sub shell_quote($)
+{
+  my ($s) = @_;
+  if ($s =~ m![^\w+/.,-]!)
+    {
+      # Convert each single quote to '\''
+      $s =~ s/\'/\'\\\'\'/g;
+      # Then single quote the string.
+      $s = "'$s'";
+    }
+  return $s;
+}
+
 =item C<mktmpdir ($signature)>
 
 Create a temporary directory which name is based on C<$signature>.
@@ -295,10 +321,11 @@ sub mktmpdir ($)
 {
   my ($signature) = @_;
   my $TMPDIR = $ENV{'TMPDIR'} || '/tmp';
+  my $quoted_tmpdir = shell_quote ($TMPDIR);
 
   # If mktemp supports dirs, use it.
   $tmp = `(umask 077 &&
-          mktemp -d "$TMPDIR/${signature}XXXXXX") 2>/dev/null`;
+          mktemp -d $quoted_tmpdir/"${signature}XXXXXX") 2>/dev/null`;
   chomp $tmp;
 
   if (!$tmp || ! -d $tmp)
diff --git a/tests/tools.at b/tests/tools.at
index 4096d9e..7c75b33 100644
--- a/tests/tools.at
+++ b/tests/tools.at
@@ -138,22 +138,57 @@ AT_CHECK([cat file], 0,
 AT_CLEANUP
 
 
-# autom4te and file names containing white space
-# ----------------------------------------------
+# autom4te and file names containing whitespace
+# ---------------------------------------------
+
+AT_SETUP([autom4te and whitespace in file names])
+
+x=
+export x
+rm -f a b
+# the first one omits special characters that are not w32 safe.
+for funny in \
+  'with  funny '\'' $x & #! name ' \
+  'with  funny \ '\'' \'\'' " <a >b * ? name '
+do
+  file=" file $funny"
+  dir=" dir $funny"
+  cachedir=" cache$dir"
+  TMPDIR=" tmp$dir"
+  export TMPDIR
+
+  cat >"$file.m4" <<'END'
+[m4@&address@hidden(foo.m4)
+m4@&address@hidden(0)d@&address@hidden
+FOO]
+END
+  # skip if we cannot create such a file or directory
+  AT_CHECK([mkdir "$dir" "$cachedir" "$TMPDIR" && test -f "$file.m4" || exit 
77])
+  cat >"$dir"/foo.m4 <<'END'
+[m4@&address@hidden([FOO], [bar])]
+END
 
-AT_SETUP([autom4te and white space in file names])
+  AT_CHECK_AUTOM4TE([-C "$cachedir" -B "$dir" --language=m4sugar -o "$file" 
"$file.m4"])
+  AT_CHECK([cat "$file"], [],
+  [[bar
+]])
+  AT_CHECK_AUTOM4TE([-C "$cachedir" -I "$dir" --language=m4sugar -o "$file" 
"$file.m4"])
+  AT_CHECK([cat "$file"], [],
+  [[bar
+]])
 
-file='file with  funny \ '\'' \'\'' $ & #!*? name'
-cat >"$file.m4" <<'END'
-right
+  cat >"$file.m4" <<'END'
+[m4@&address@hidden(foo.m4)
+m4@&address@hidden(0)d@&address@hidden
 END
-# skip if we cannot create such a file
-AT_CHECK([test -f "$file.m4" || exit 77])
-AT_CHECK_AUTOM4TE([-o "$file" "$file.m4"])
+  AT_CHECK_AUTOM4TE([-C "$cachedir" -I "$dir" --language=m4sugar --freeze -o 
"$file.m4f" "$file.m4"])
+  AT_CHECK([test -s "$file.m4f"])
 
-AT_CHECK([cat "$file"], [],
-[[right
-]])
+  # Check --reload-state
+  AT_CHECK_AUTOM4TE([-C "$cachedir" --language=m4sugar -o "$file" "$file.m4f" 
/dev/null])
+
+  test ! -f b
+done
 
 AT_CLEANUP
 
@@ -925,3 +960,64 @@ AT_CHECK([test "`find configure -newer newer`" = "" ||
          { diff old-requests autom4te.cache/requests; exit 1; }])
 
 AT_CLEANUP
+
+
+# autotools and file names containing whitespace
+# ---------------------------------------------
+
+AT_SETUP([autotools and whitespace in file names])
+
+x=
+export x
+rm -f a b
+# the first one omits special characters that are not w32 safe.
+for funny in \
+  'with  funny '\'' $x & #! name ' \
+  'with  funny \ '\'' \'\'' " <a >b * ? name '
+do
+  file=" file $funny"
+  dir=" dir $funny"
+  TMPDIR=" tmp$dir"
+  export TMPDIR
+
+  cat >"$file.in" <<'END'
+[AC_INIT(x,0)
+m4@&address@hidden([foo.m4])
+AC_CONFIG_HEADERS([config.h:config.hin])
+AC_MACRO
+AC_OUTPUT]
+END
+  # skip if we cannot create such a file or directory
+  AT_CHECK([mkdir "$dir" "$TMPDIR" && test -f "$file.in" || exit 77])
+  cat >"$dir"/foo.m4 <<'END'
+[AC_DEFUN([AC_MACRO], [echo hi])]
+END
+
+  AT_CHECK_AUTOHEADER([-B "$dir" "$file.in"])
+  AT_CHECK_AUTOHEADER([-I "$dir" "$file.in"])
+  AT_CHECK_AUTOUPDATE([-B "$dir" "$file.in"])
+  AT_CHECK_AUTOUPDATE([-I "$dir" "$file.in"])
+  AT_CHECK_AUTOUPDATE([-B "$dir" - < "$file.in"], [], [ignore])
+  AT_CHECK_AUTOCONF([-B "$dir" -o "$file" "$file.in"])
+  AT_CHECK_AUTOCONF([-I "$dir" -o "$file" "$file.in"])
+  # In autoconf, these exercise a slightly different code path:
+  AT_CHECK_AUTOCONF([--prepend-include="$dir" -o "$file" "$file.in"])
+  AT_CHECK_AUTOCONF([--include="$dir" -o "$file" "$file.in"])
+  AT_CHECK([autoscan -B "$dir"], [], [], [ignore])
+  AT_CHECK([autoscan -I "$dir"], [], [], [ignore])
+  # autoreconf requires a sane input file name.  Also, disable aclocal.
+  mv -f "$file.in" configure.in
+  AT_DATA([aclocal.m4])
+  AT_CHECK([autoreconf -B "$dir"])
+  AT_CHECK([autoreconf -I "$dir"])
+
+  cat >"$file.c" <<'END'
+#if FOO
+#endif
+END
+  AT_CHECK([ifnames "$file.c"], [], [ignore])
+
+  test ! -f b
+done
+
+AT_CLEANUP
-- 
1.5.3.7.1005.gdada0c





reply via email to

[Prev in Thread] Current Thread [Next in Thread]