Re: multiline output variables.

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

 



Hi, again.  This took a while because I was working on other things.  I
hope that this is the final patch for supporting multiline output
variables.  (Though I bet that I've made some dumb typo.)

The attached patch is 'cvs diff'ed from anoncvs as of this afternoon.

On Fri, 28 Jan 2005, Stepan Kasal wrote:

> 2) ad
> > AC_SUBST(ac_delim) can cause an endless loop
>
	Although this no longer causes a problem, I've made it always fake
ac_delim as being the empty string, just to reduce the mess.

> My proposal indeed fixed this, yet I think a safety belt cannot hurt.
> We could change the simple infinite loop to something like:
>
	I instead just ask `test ${#ac_delim} -gt 1000', which gives six
iterations with the current set up.

>
>
> 3) ad: the implementation of non-recursive substitution:
>
> All the hacks with |#@!@#| are too complicated and not general enough.
> There is a better solution.
>
	I agree that your solution works and makes non-recursion invisible
to the user, but I think it's actually benefitial to have the wacky string
that gets deleted (for instance, to disabiguate `@foo@bar@' by
`@foo@|#_!!_#|bar@'), so I have not taken your suggestion here.  I just
surround all `@'s with the deleted string, and also put it at the
beginning of each output value.  Note that I changed the deleted string to
be a palendrome, since that allows it to be inserted at its own center.  I
think this just looks "better".

> sed  ':s
> /'"$ac_delim"'$/b ok
> N
> b s
> :ok
> s/?/?q/g
> s/@/?a/g
> s/[\\&,]/\\&/g
> s/\n/\\&/g
> s/^/s,@/
> s/!/@,/
> s/'"$ac_delim"'$/,g/'
	I figure that it's better to not accumulate lines, since with
newlines, output values can get quite large.  I instead handle the first
line of the value specially (to turn _AC_Var! into ,@_AC_Var@,|#_!!_#|)
and then loop through remaining lines without starting a new sed cycle.

> 4) When reading parts of your patch, I cannot understand why it is
> necessary to use diversions.
	Sheer lunacy on my part.  I've programmed to much lisp and forgot
that you could assign to variables.

> I think it might be easier to count `sed commands' instead of
> `substitutions'
	Indeed.  Note that I've taken the suggestion to use s///g rather
than looping back to the beginning, so the two numbers are usually closer.
In fact, I think that the majority of configure.ac's now will only need a
single sed fragment, which is nice.


Some additional stuff besides _AC_OUTPUT_FILES:  I've added to the
documentation of AC_HEADER_STDBOOL as an example of the benefits of this
patch. It is worth noting that this patch only allows newlines in output
variables, not in defines nor in cache values.  As mentioned before, I've
also restricted file substitutions to whole lines.

I've run `make check' with this patch, but killed it after the "Testing
config.status." section.  If there is a real chance that the patch effects
other tests, tell me.

My thanks go to Stepan for all the help he's given with this.

Now, could somebody tell me what paperwork I need to actually make this
public?  I have the okay from my work.

-Dan
? multi.diff
Index: doc/autoconf.texi
===================================================================
RCS file: /cvsroot/autoconf/autoconf/doc/autoconf.texi,v
retrieving revision 1.875
diff -u -r1.875 autoconf.texi
--- doc/autoconf.texi	5 Feb 2005 07:58:43 -0000	1.875
+++ doc/autoconf.texi	7 Feb 2005 20:47:36 -0000
@@ -4873,6 +4873,39 @@
 # define __bool_true_false_are_defined 1
 #endif
 @end verbatim
+
+However, since output variables can now contain newlines, it is possible
+to construct an output variable that includes only those headers and
+definitions needed, such as:
+
+@verbatim
+AC_HEADER_STDBOOL
+AC_SUBST(stdbool)
+if test "x$ac_cv_header_stdbool_h" = xyes; then
+  stdbool='
+#include <stdbool.h>
+'
+else
+  if test "x$ac_cv_type__Bool" != xyes; then
+    stdbool='
+#ifdef __cplusplus
+typedef bool _Bool;
+#else
+typedef unsigned char _Bool;
+#endif
+'
+  else
+    stdbool='
+'
+  fi
+  stdbool=$stdbool'dnl
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+'
+fi
+@end verbatim
 @end defmac
 
 
@@ -7297,9 +7330,13 @@
 or more @file{Makefile}s).  This means that @code{AC_OUTPUT} will
 replace instances of @samp{@@@var{variable}@@} in input files with the
 value that the shell variable @var{variable} has when @code{AC_OUTPUT}
-is called.  This value of @var{variable} should not contain literal
-newlines.  (There is currently no portable way to escape literal
-newlines.)
+is called.  It is now permissible for the value to contain newlines.
+The substituted value is not rescanned for more output variables;
+occurences of @samp{@@@var{variable}@@} in the value are inserted
+literally into the output file.  (Actually, the surrounding @code{@@}s
+are surrounded by @code{|#_!!_#|}, and all occurences of @code{|#_!!_#|}
+are ultimately removed.  If by some misfortune, you need a literal
+@code{|#_!!_#|} in your output file, use @code{|#_!|#_!!_#|!_#|}.)
 
 If @var{value} is given, in addition assign it to @var{variable}.
 
@@ -7316,7 +7353,10 @@
 @samp{@@@var{variable}@@} in output files (such as @file{Makefile.in})
 with the contents of the file that the shell variable @var{variable}
 names when @code{AC_OUTPUT} is called.  Set the variable to
-@file{/dev/null} for cases that do not have a file to insert.
+@file{/dev/null} for cases that do not have a file to insert.  This
+substitution only occurs when the @samp{@@@var{variable}@@} is on a line
+by itself, optionally surrounded by spaces and tabs.  The whole line,
+including the spaces, tabs, and the terminating newline, is replaced.
 
 This macro is useful for inserting @file{Makefile} fragments containing
 special dependencies or other @code{make} directives for particular host
Index: lib/autoconf/status.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/autoconf/status.m4,v
retrieving revision 1.49
diff -u -r1.49 status.m4
--- lib/autoconf/status.m4	2 Feb 2005 23:31:17 -0000	1.49
+++ lib/autoconf/status.m4	7 Feb 2005 20:47:36 -0000
@@ -850,7 +850,15 @@
 m4_define([AC_LIST_FILES])
 m4_define([AC_LIST_FILES_COMMANDS])
 
-
+# _AC_SED_CMD_LIMIT
+# -----------------
+# Evaluate to an m4 number equal to the maximum number of commands to put
+# in any single sed program.
+#
+# Some seds have small command number limits, like on Digital OSF/1 and HP-UX.
+m4_define([_AC_SED_CMD_LIMIT],
+dnl One cannot portably go further than 100 commands because of HP-UX.
+[100])
 
 # _AC_OUTPUT_FILES
 # ----------------
@@ -860,80 +868,142 @@
 # It has to send itself into $CONFIG_STATUS (eg, via here documents).
 # Upon exit, no here document shall be opened.
 m4_define([_AC_OUTPUT_FILES],
-[cat >>$CONFIG_STATUS <<_ACEOF
-
+[cat >>$CONFIG_STATUS <<\_ACEOF
 #
 # CONFIG_FILES section.
 #
 
 # No need to generate the scripts if there are no CONFIG_FILES.
 # This happens for instance when ./config.status config.h
-if test -n "\$CONFIG_FILES"; then
-  # Protect against being on the right side of a sed subst in config.status.
-dnl Please, pay attention that this sed code depends a lot on the shape
-dnl of the sed commands issued by AC_SUBST.  So if you change one, change
-dnl the other too.
-[  sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
-   s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >"\$tmp/subs.sed" <<\\CEOF]
-dnl These here document variables are unquoted when configure runs
-dnl but quoted when config.status runs, so variables are expanded once.
-dnl Insert the sed substitutions of variables.
-m4_ifdef([_AC_SUBST_VARS],
-	 [AC_FOREACH([AC_Var], m4_defn([_AC_SUBST_VARS]),
-[s,@AC_Var@,$AC_Var,;t t
-])])dnl
-m4_ifdef([_AC_SUBST_FILES],
-	 [AC_FOREACH([AC_Var], m4_defn([_AC_SUBST_FILES]),
-[/@AC_Var@/r $AC_Var
-s,@AC_Var@,,;t t
-])])dnl
-CEOF
+if test -n "$CONFIG_FILES"; then
 
 _ACEOF
 
-  cat >>$CONFIG_STATUS <<\_ACEOF
-  # Split the substitutions into bite-sized pieces for seds with
-  # small command number limits, like on Digital OSF/1 and HP-UX.
-dnl One cannot portably go further than 100 commands because of HP-UX.
-dnl Here, there are 2 cmd per line, and two cmd are added later.
-  ac_max_sed_lines=48
-  ac_sed_frag=1 # Number of current file.
-  ac_beg=1 # First line for current file.
-  ac_end=$ac_max_sed_lines # Line after last line for current file.
-  ac_more_lines=:
-  ac_sed_cmds=
-  while $ac_more_lines; do
-    if test $ac_beg -gt 1; then
-      sed "1,${ac_beg}d; ${ac_end}q" "$tmp/subs.sed" >"$tmp/subs.frag"
-    else
-      sed "${ac_end}q" "$tmp/subs.sed" >"$tmp/subs.frag"
-    fi
-    if test ! -s "$tmp/subs.frag"; then
-      ac_more_lines=false
-    else
-      # The purpose of the label and of the branching condition is to
-      # speed up the sed processing (if there are no `@' at all, there
-      # is no need to browse any of the substitutions).
-      # These are the two extra sed commands mentioned above.
-      (echo [':t
-  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b'] && cat "$tmp/subs.frag") >"$tmp/subs-$ac_sed_frag.sed"
-      if test -z "$ac_sed_cmds"; then
-	ac_sed_cmds="sed -f '$tmp/subs-$ac_sed_frag.sed'"
-      else
-	ac_sed_cmds="$ac_sed_cmds | sed -f '$tmp/subs-$ac_sed_frag.sed'"
-      fi
-      ac_sed_frag=`expr $ac_sed_frag + 1`
-      ac_beg=$ac_end
-      ac_end=`expr $ac_end + $ac_max_sed_lines`
-    fi
-  done
-  if test -z "$ac_sed_cmds"; then
-    ac_sed_cmds=cat
+m4_pushdef([_AC_SED_CMDS], [])dnl Part of pipeline that does substitutions.
+dnl
+m4_pushdef([_AC_SED_FRAG_NUM], 0)dnl Fragment number.
+m4_pushdef([_AC_SED_CMD_NUM], 1)dnl Num of commands in current frag so far.
+m4_pushdef([_AC_SED_DELIM_NUM], 0)dnl Expected number of delimiters in file.
+m4_pushdef([_AC_SED_FRAG], [])dnl The constant part of the current fragment.
+dnl
+m4_ifdef([_AC_SUBST_FILES],
+[# Create sed commands to just substitute file output variables.
+
+AC_FOREACH([_AC_Var], m4_defn([_AC_SUBST_FILES]),
+[dnl End fragments at beginning of loop so that last fragment is not ended.
+m4_if(1,m4_eval(_AC_SED_CMD_NUM+4>_AC_SED_CMD_LIMIT),
+[dnl Fragment is full and not the last one, so no need for the final un-escape.
+dnl Increment fragment number.
+m4_define([_AC_SED_FRAG_NUM],m4_eval(_AC_SED_FRAG_NUM+1))dnl
+dnl Record that this fragment will need to be used.
+m4_define([_AC_SED_CMDS],
+m4_defn([_AC_SED_CMDS])[| sed -f "$tmp/subs-]_AC_SED_FRAG_NUM[.sed" ])dnl
+[cat >>$CONFIG_STATUS <<_ACEOF
+cat >"$tmp/subs-]_AC_SED_FRAG_NUM[.sed" <\CEOF
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+]m4_defn(_AC_SED_FRAG)dnl
+[CEOF
+
+_ACEOF
+]m4_define([_AC_SED_CMD_NUM], 1)m4_define([_AC_SED_FRAG])dnl
+])dnl Last fragment ended.
+m4_define([_AC_SED_CMD_NUM], m4_eval(_AC_SED_CMD_NUM+4))dnl
+m4_define([_AC_SED_FRAG],
+m4_defn([_AC_SED_FRAG])dnl
+[/^[ 	]*@]_AC_Var[@[ 	]*$/{ r $]_AC_Var[
+d; }
+])dnl
+])dnl
+# Remaining file output variables are in a fragment that also has non-file
+# output varibles.
+
+])
+dnl
+m4_define([_AC_SED_FRAG],[
+]m4_defn([_AC_SED_FRAG]))dnl
+AC_FOREACH([_AC_Var],
+m4_ifdef([_AC_SUBST_VARS],[m4_defn([_AC_SUBST_VARS]) ])[@END@],
+[m4_if(_AC_SED_DELIM_NUM,0,
+[m4_if(_AC_Var,[@END@],
+[dnl The whole of the last fragment would be the final deletion of `|#_!!_#|'.
+m4_define([_AC_SED_CMDS],m4_defn([_AC_SED_CMDS])[| sed 's/|#_!!_#|//g' ])],
+[
+ac_delim='%!_!# '
+while :; do
+  cat >conf$$subs.sed <<_ACEOF
+])])dnl
+m4_if(_AC_Var,[ac_delim],
+[dnl Just to be on the safe side, claim that $ac_delim is the empty string.
+m4_define([_AC_SED_FRAG],
+m4_defn([_AC_SED_FRAG])dnl
+[s,ac_delim,|#_!!_#|,g
+])dnl
+m4_define([_AC_SED_CMD_NUM], m4_eval(_AC_SED_CMD_NUM+1))],
+      _AC_Var,[@END@],
+      [m4_if(1,m4_eval(_AC_SED_CMD_NUM+2<=_AC_SED_CMD_LIMIT),
+             [m4_define([_AC_SED_FRAG], [ n]m4_defn([_AC_SED_FRAG]))])],
+[m4_define([_AC_SED_CMD_NUM], m4_eval(_AC_SED_CMD_NUM+1))dnl
+m4_define([_AC_SED_DELIM_NUM], m4_eval(_AC_SED_DELIM_NUM+1))dnl
+_AC_Var!$_AC_Var$ac_delim
+])dnl
+m4_if(_AC_SED_CMD_LIMIT,
+      m4_if(_AC_Var,[@END@],_AC_SED_CMD_LIMIT,_AC_SED_CMD_NUM),
+[_ACEOF
+
+  if test `grep -c "$ac_delim\$" conf$$subs.sed` = _AC_SED_DELIM_NUM; then
+    break
+  elif test ${#ac_delim} -gt 1000; then
+    AC_MSG_ERROR([could not make $CONFIG_STATUS])
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
   fi
-fi # test -n "$CONFIG_FILES"
+done
 
+ac_eof=
+while grep -q "^CEOF$ac_eof\$" conf$$subs.sed; do
+  ac_eof=`expr $ac_eof + 1`
+done
+
+dnl Increment fragment number.
+m4_define([_AC_SED_FRAG_NUM],m4_eval(_AC_SED_FRAG_NUM+1))dnl
+dnl Record that this fragment will need to be used.
+m4_define([_AC_SED_CMDS],
+m4_defn([_AC_SED_CMDS])[| sed -f "$tmp/subs-]_AC_SED_FRAG_NUM[.sed" ])dnl
+[cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-]_AC_SED_FRAG_NUM[.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b]m4_defn([_AC_SED_FRAG])dnl
+[_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/|#_!!_#|@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^[^\n]*\n//; s/[,\\&]/\\&/g; s/@/|#_!!_#|@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+]m4_if(_AC_Var,[@END@],
+[m4_if(1,m4_eval(_AC_SED_CMD_NUM+2>_AC_SED_CMD_LIMIT),
+[m4_define([_AC_SED_CMDS],m4_defn([_AC_SED_CMDS])[| sed 's/|#_!!_#|//g' ])],
+[[:n
+s/|#_!!_#|//g
+]])])dnl
+CEOF$ac_eof
 _ACEOF
+m4_define([_AC_SED_FRAG], [
+])m4_define([_AC_SED_DELIM_NUM], 0)m4_define([_AC_SED_CMD_NUM], 1)dnl
+
+])])dnl
+dnl
+m4_popdef([_AC_SED_FRAG_NUM])dnl
+m4_popdef([_AC_SED_CMD_NUM])dnl
+m4_popdef([_AC_SED_DELIM_NUM])dnl
+m4_popdef([_AC_SED_FRAG])dnl
+dnl
 cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
 for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
   # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
   case $ac_file in
@@ -1018,8 +1088,8 @@
 s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
 AC_PROVIDE_IFELSE([AC_PROG_INSTALL], [s,@INSTALL@,$ac_INSTALL,;t t
 ])dnl
-dnl The parens around the eval prevent an "illegal io" in Ultrix sh.
-" $ac_file_inputs | (eval "$ac_sed_cmds") >"$tmp/out"
+" $ac_file_inputs m4_defn([_AC_SED_CMDS])>$tmp/out
+m4_popdef([_AC_SED_CMDS])dnl
   rm -f "$tmp/stdin"
 dnl This would break Makefile dependencies.
 dnl  if diff $ac_file "$tmp/out" >/dev/null 2>&1; then
Index: tests/torture.at
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/torture.at,v
retrieving revision 1.50
diff -u -r1.50 torture.at
--- tests/torture.at	5 Feb 2005 07:34:54 -0000	1.50
+++ tests/torture.at	7 Feb 2005 20:47:36 -0000
@@ -556,7 +556,6 @@
 ## ---------------------- ##
 
 AT_SETUP([Substitute a newline])
-AT_XFAIL_IF(:)
 
 AT_DATA([Foo.in],
 [@foo@
_______________________________________________
Autoconf mailing list
Autoconf@xxxxxxx
http://lists.gnu.org/mailman/listinfo/autoconf

[Index of Archives]     [GCC Help]     [Kernel Discussion]     [RPM Discussion]     [Red Hat Development]     [Yosemite News]     [Linux USB]     [Samba]

  Powered by Linux