From: Ralf Wildenhues Date: Sat, 8 Dec 2007 10:46:43 +0000 (+0100) Subject: Proper file name escaping in Autoconf programs and Perl modules. X-Git-Tag: v2.62~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=449317f7ee33553165f46de6d818a44ee2cd7def;p=thirdparty%2Fautoconf.git Proper file name escaping in Autoconf programs and Perl modules. 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. * 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. --- diff --git a/ChangeLog b/ChangeLog index 5d49b2cd..9b86bc4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,28 @@ 2007-12-08 Ralf Wildenhues + Proper file name escaping in Autoconf programs and Perl modules. + 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. + * 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. + Sync from Automake. * lib/Autom4te/Channels.pm, lib/Autom4te/Configure_ac.pm, lib/Autom4te/Struct.pm, lib/Autom4te/XFile.pm: Likewise. diff --git a/bin/autoconf.as b/bin/autoconf.as index b68d4ef6..dbabc308 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 9c19ea3a..2565db21 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 /\@BOTTOM\@/; @@ -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 b273b9a0..8efe537a 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' : '') - . " @M4_DEBUGFILE@=$tcache" . $req->id . "t" + . " @M4_DEBUGFILE@=" . 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) . ' getline) { s/#.*//; diff --git a/bin/autoscan.in b/bin/autoscan.in index 372a8788..59227e26 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 d69211d6..23060f29 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(\@<:\@\$1\@:>\@, \@<:\@\$2\@:>\@)' --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 () @@ -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 d7c36bab..bd65bbf7 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/General.pm b/lib/Autom4te/General.pm index b79467fe..5639e4cb 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 + +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 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 4096d9e5..199c15e4 100644 --- a/tests/tools.at +++ b/tests/tools.at @@ -138,22 +138,73 @@ 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 \ '\'' \'\'' " b * ? name ' +do + file=" file $funny" + outfile="$file out " + dir=" dir $funny" + cachedir=" cache$dir" + TMPDIR=" tmp$dir" + export TMPDIR + + cat >"$file" <<'END' +[m4@&t@_include(foo.m4) +m4@&t@_divert(0)d@&t@nl +FOO] +END + # skip if we cannot create such a file or directory + AT_CHECK([mkdir "$dir" "$cachedir" "$TMPDIR" && test -f "$file" || exit 77]) + cat >"$dir"/foo.m4 <<'END' +[m4@&t@_define([FOO], [bar])] +END -AT_SETUP([autom4te and white space in file names]) + AT_CHECK_AUTOM4TE([-C "$cachedir" -B "$dir" --language=m4sugar -o "$outfile" "$file"]) + AT_CHECK([cat "$outfile"], [], + [[bar +]]) + rm -rf "$outfile" "$cachedir" + AT_CHECK_AUTOM4TE([-C "$cachedir" -I "$dir" --language=m4sugar -o "$outfile" "$file"]) + AT_CHECK([cat "$outfile"], [], + [[bar +]]) -file='file with funny \ '\'' \'\'' $ & #!*? name' -cat >"$file.m4" <<'END' -right + # This exercises a slightly different code path and will catch an open with + # trailing whitespace: + cat >"$file" <<'END' +[m4@&t@_include(foo.m4) +m4@&t@_pattern_forbid([^bar$]) +m4@&t@_divert(0)d@&t@nl +FOO] +END + rm -rf "$outfile" "$cachedir" + AT_CHECK_AUTOM4TE([-C "$cachedir" -I "$dir" --language=m4sugar -o "$outfile" "$file"], + [1], [], [stderr]) + AT_CHECK([grep 'possibly undefined macro' stderr], [], [ignore]) + + cat >"$file" <<'END' +[m4@&t@_include(foo.m4) +m4@&t@_divert(0)d@&t@nl] END -# skip if we cannot create such a file -AT_CHECK([test -f "$file.m4" || exit 77]) -AT_CHECK_AUTOM4TE([-o "$file" "$file.m4"]) + rm -rf "$file.m4f" + AT_CHECK_AUTOM4TE([-C "$cachedir" -I "$dir" --language=m4sugar --freeze -o "$file.m4f" "$file"]) + AT_CHECK([test -s "$file.m4f"]) -AT_CHECK([cat "$file"], [], -[[right -]]) + # Check --reload-state + AT_CHECK_AUTOM4TE([-C "$cachedir" --language=m4sugar -o "$outfile" "$file.m4f" /dev/null]) + + test ! -f b +done AT_CLEANUP @@ -925,3 +976,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 \ '\'' \'\'' " b * ? name ' +do + file=" file $funny" + dir=" dir $funny" + TMPDIR=" tmp$dir" + export TMPDIR + + cat >"$file.in" <<'END' +[AC_INIT(x,0) +m4@&t@_include([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