[PATCH] Support newlines in cache variables

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
Report Content as Inappropriate

[PATCH] Support newlines in cache variables

Quinn Grier
The old _AC_CACHE_DUMP code disallowed newlines in cache variables. It
would unset all variables (including non-cache variables) that contain
newlines and output all remaining cache variables. Because unset halts
the (sub)shell when used on a readonly variable, this also disallowed
newlines in all readonly variables (including non-cache variables).

The new code translates newlines to $as_nl expansions and still handles
implementations of set that fail to quote. The important observation is
that bogus variable names in the output of set can be identified using
${name+x} regardless of quoting bugs. The new code works as follows:

      for each line in the output of set
        if the line looks like an assignment
          if the variable name contains _cv_
            if the variable name is not bogus
              if the variable has not been seen yet
                output the variable appropriately
                add the variable to the seen list

The seen list is included to be maximally conservative. Without it,
certain values can cause cache variables to be output multiple times,
which is harmless from a technical perspective but may confuse callers
doing unusual things. For example, ac_cv_x=${as_nl}ac_cv_x= will cause
ac_cv_x to be listed twice. Note that the seen list can be disabled by
removing the ac_seen=$ac_seen$ac_var, assignment.

The $as_nl expansions are double-quoted to handle the Solaris and Ultrix
bugs described in the manual for the ${var=value} syntax. Note that this
syntax is used by AC_CACHE_SAVE, the main caller of _AC_CACHE_DUMP.

* lib/autoconf/general.m4 (_AC_CACHE_DUMP): Support newlines.
This also happens to add support for readonly variables that
contain newlines, which would previously break this code.
 NEWS                    |  3 +++
 doc/autoconf.texi       |  9 ++++-----
 lib/autoconf/general.m4 | 52 +++++++++++++++++++++----------------------------
 3 files changed, 29 insertions(+), 35 deletions(-)

diff --git a/NEWS b/NEWS
index 5f05ad6..d52e8a6 100644
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,9 @@ GNU Autoconf NEWS - User visible changes.
    is now deprecated.  If you really need that behavior use
+** Newlines are now supported in cache variables.  They are translated
+   to expansions of a M4sh-reserved variable that contains a newline.
 ** Macros
 - New macro AC_C__GENERIC.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 1838d6b..f2b89d6 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -10087,11 +10087,10 @@ For example, @samp{broken} or @samp{set}.  This part of the name may
 be omitted if it does not apply.
 @end table
-The values assigned to cache variables may not contain newlines.
-Usually, their values are Boolean (@samp{yes} or @samp{no}) or the
-names of files or functions; so this is not an important restriction.
-@ref{Cache Variable Index} for an index of cache variables with
-documented semantics.
+The values assigned to cache variables may contain newlines, which are
+translated to expansions of a M4sh-reserved variable that contains a
+newline.  For an index of cache variables with documented semantics,
+@pxref{Cache Variable Index}.
 @node Cache Files
diff --git a/lib/autoconf/general.m4 b/lib/autoconf/general.m4
index c15fb13..e203092 100644
--- a/lib/autoconf/general.m4
+++ b/lib/autoconf/general.m4
@@ -1978,42 +1978,34 @@ fi
 # --------------
 # Dump the cache to stdout.  It can be in a pipe (this is a requirement).
-[# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
 # Ultrix sh set writes to stderr and can't be redirected directly,
 # and sets the high bit in the cache file unless we assign to the vars.
+  ac_seen=,
   for ac_var in `(set) 2>&1 | sed -n ['s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p']`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) AC_MSG_WARN([cache variable $ac_var contains a newline]) ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) AS_UNSET([$ac_var]) ;;
+    case $ac_var in #(
+    *_cv_*)
+      eval ac_hit=\$[]{$ac_var+x}
+      case $ac_hit in #(
+      x)
+        case $ac_seen in #(
+        *,$ac_var,*) ;; #(
+        *)
+          eval ac_val=\$$ac_var
+          sed "
+            s/'/'\\\\''/g
+            1s/^/$ac_var='/
+            \$!s/\$/'\"\$as_nl\"'/
+            \$s/\$/'/
+          " <<_ACEOF | tr -d "$as_nl"; echo
+          ac_seen=$ac_seen$ac_var, ;;
+        esac ;;
       esac ;;
-  done
-  (set) 2>&1 |
-    case $as_nl`(ac_space=' '; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      # `set' does not quote correctly, so add quotes: double-quote
-      # substitution turns \\\\ into \\, and sed turns \\ into \.
-      sed -n \
- ["s/'/'\\\\''/g;
-  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"]
-      ;; #(
-    *)
-      # `set' quotes correctly as required by POSIX, so do not add quotes.
-      sed -n ["/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"]
-      ;;
-    esac |
-    sort
+  done | sort