Move case statement style discussion to m4 quoting section.

* doc/autoconf.texi (Limitations of Builtins): Move comparison of
quoting styles...
(Balancing Parentheses): ...to this new node.
Suggested by Ralf Wildenhues.

Signed-off-by: Eric Blake <ebb9@byu.net>
This commit is contained in:
Eric Blake 2008-11-21 06:35:35 -07:00
parent abe172f4ba
commit 54dd8a9379
2 changed files with 133 additions and 103 deletions

View File

@ -1,3 +1,11 @@
2008-11-21 Eric Blake <ebb9@byu.net>
Move case statement style discussion to m4 quoting section.
* doc/autoconf.texi (Limitations of Builtins): Move comparison of
quoting styles...
(Balancing Parentheses): ...to this new node.
Suggested by Ralf Wildenhues.
2008-11-20 Eric Blake <ebb9@byu.net>
Factor more common code out of AT_CHECK into shell function.

View File

@ -445,6 +445,7 @@ M4 Quotation
* Quotation and Nested Macros:: Macros calling macros
* Changequote is Evil:: Worse than INTERCAL: M4 + changequote
* Quadrigraphs:: Another way to escape special characters
* Balancing Parentheses:: Dealing with unbalanced parentheses
* Quotation Rule Of Thumb:: One parenthesis, one quote
Using @command{autom4te}
@ -9292,6 +9293,7 @@ former helps one to follow the latter.
* Quotation and Nested Macros:: Macros calling macros
* Changequote is Evil:: Worse than INTERCAL: M4 + changequote
* Quadrigraphs:: Another way to escape special characters
* Balancing Parentheses:: Dealing with unbalanced parentheses
* Quotation Rule Of Thumb:: One parenthesis, one quote
@end menu
@ -9778,6 +9780,126 @@ invention, and I suppose it could have been a common pun around the
Cambridge University computer lab at the time.
@end quotation
@node Balancing Parentheses
@subsection Dealing with unbalanced parentheses
@cindex balancing parentheses
@cindex parentheses, balancing
@cindex unbalanced parentheses, managing
One of the pitfalls of portable shell programming is that @command{case}
statements require unbalanced parentheses (@pxref{Limitations of
Builtins, , Limitations of Shell Builtins}). With syntax highlighting
editors, the presence of unbalanced @samp{)} can interfere with editors
that perform syntax highlighting of macro contents based on finding the
matching @samp{(}. Another concern is how much editing must be done
when transferring code snippets between shell scripts and macro
definitions. But most importantly, the presence of unbalanced
parentheses can introduce expansion bugs.
For an example, here is an underquoted attempt to use the macro
@code{my_case}, which happens to expand to a portable @command{case}
statement:
@example
AC_DEFUN([my_case],
[case $file_name in
*.c) echo "C source code";;
esac])
AS_IF(:, my_case)
@end example
@noindent
In the above example, the @code{AS_IF} call underquotes its arguments.
As a result, the unbalanced @samp{)} generated by the premature
expansion of @code{my_case} results in expanding @code{AS_IF} with a
truncated parameter, and the expansion is syntactically invalid:
@example
if :; then
case $file_name in
*.c
fi echo "C source code";;
esac)
@end example
If nothing else, this should emphasize the importance of the quoting
arguments to macro calls. On the other hand, there are several
variations for defining @code{my_case} to be more robust, even when used
without proper quoting, each with some benefits and some drawbacks.
@itemize @asis
@item Creative literal shell comment
@example
AC_DEFUN([my_case],
[case $file_name in #(
*.c) echo "C source code";;
esac])
@end example
@noindent
This version provides balanced parentheses to several editors, and can
be copied and pasted into a terminal as is. Unfortunately, it is still
unbalanced as an Autoconf argument, since @samp{#(} is an M4 comment
that masks the normal properties of @samp{(}.
@item Quadrigraph shell comment
@example
AC_DEFUN([my_case],
[case $file_name in @@%:@@(
*.c) echo "C source code";;
esac])
@end example
@noindent
This version provides balanced parentheses to even more editors, and can
be used as a balanced Autoconf argument. Unfortunately, it requires
some editing before it can be copied and pasted into a terminal, and the
use of the quadrigraph @samp{@@%:@@} for @samp{#} reduces readability.
@item Quoting just the parenthesis
@example
AC_DEFUN([my_case],
[case $file_name in
*.c[)] echo "C source code";;
esac])
@end example
@noindent
This version quotes the @samp{)}, so that it can be used as a balanced
Autoconf argument. As written, this is not balanced to an editor, but
it can be coupled with @samp{[#(]} to meet that need, too. However, it
still requires some edits before it can be copied and pasted into a
terminal.
@item Double-quoting the entire statement
@example
AC_DEFUN([my_case],
[[case $file_name in #(
*.c) echo "C source code";;
esac]])
@end example
@noindent
Since the entire macro is double-quoted, there is no problem with using
this as an Autoconf argument; and since the double-quoting is over the
entire statement, this code can be easily copied and pasted into a
terminal. However, the double quoting prevents the expansion of any
macros inside the case statement, which may cause its own set of
problems.
@item Using @code{AS_CASE}
@example
AC_DEFUN([my_case],
[AS_CASE([$file_name],
[*.c], [echo "C source code"])])
@end example
@noindent
This version avoids the balancing issue altogether, by relying on
@code{AS_CASE} (@pxref{Common Shell Constructs}); it also allows for the
expansion of @code{AC_REQUIRE} to occur prior to the entire case
statement, rather than within a branch of the case statement that might
not be taken. However, the abstraction comes with a penalty that it is
no longer a quick copy, paste, and edit to get back to shell code.
@end itemize
@node Quotation Rule Of Thumb
@subsection Quotation Rule Of Thumb
@ -14901,113 +15023,13 @@ $ @kbd{case foo in (foo) echo foo;; esac}
@end example
@noindent
@cindex balancing parentheses
@cindex parentheses, balancing
The leading @samp{(} can be omitted safely. Unfortunately, there are
contexts where unbalanced parentheses cause other problems, such as when
using a syntax-highlighting editor that searches for the balancing
counterpart, or more importantly, when using a case statement as an
underquoted argument to an Autoconf macro:
@example
AC_DEFUN([my_case],
[case $file_name in
*.c) echo "C source code";;
esac])
AS_IF(:, my_case)
@end example
@noindent
In the above example, the unbalanced @samp{)} in the premature expansion
of @code{my_case} results in expanding @code{AS_IF} with a truncated
parameter, and the expansion is syntactically invalid:
@example
if :; then
case $file_name in
*.c
fi echo "C source code";;
esac)
@end example
@noindent
If nothing else, this should emphasize the importance of the quoting
rule of thumb (@pxref{Quotation Rule Of Thumb}), that you should single
quote all macro arguments that might be re-expanded, and double-quote
macro arguments that are literal text. On the other hand, there are
several variations for defining @code{my_case} to be more robust, each
with some benefits and some drawbacks.
@table @asis
@item Creative literal shell comment
@example
AC_DEFUN([my_case],
[case $file_name in #(
*.c) echo "C source code";;
esac])
@end example
@noindent
This version provides balanced parentheses to several editors, and can
be copied and pasted into a terminal as is. Unfortunately, it is still
unbalanced as an Autoconf argument, since @samp{#(} is an M4 comment
that masks the normal properties of @samp{(}.
@item Quadrigraph shell comment
@example
AC_DEFUN([my_case],
[case $file_name in @@%:@@(
*.c) echo "C source code";;
esac])
@end example
@noindent
This version provides balanced parentheses to even more editors, and can
be used as a balanced Autoconf argument. Unfortunately, it requires
some editing before it can be copied and pasted into a terminal, and the
use of the quadrigraph @samp{@@%:@@} for @samp{#} reduces readability.
@item Quoting just the parenthesis
@example
AC_DEFUN([my_case],
[case $file_name in
*.c[)] echo "C source code";;
esac])
@end example
@noindent
This version quotes the @samp{)}, so that it can be used as a balanced
Autoconf argument. As written, this is not balanced to an editor, but
it can be coupled with @samp{[#(]} to meet that need, too. However, it
still requires some edits before it can be copied and pasted into a
terminal.
@item Double-quoting the entire statement
@example
AC_DEFUN([my_case],
[[case $file_name in #(
*.c) echo "C source code";;
esac]])
@end example
@noindent
Since the entire macro is double-quoted, there is no problem with using
this as an Autoconf argument; and since the double-quoting is over the
entire statement, this code can be easily copied and pasted into a
terminal. However, the double quoting prevents the expansion of any
macros inside the case statement, which may cause its own set of
problems.
@item Using @code{AS_CASE}
@example
AC_DEFUN([my_case],
[AS_CASE([$file_name],
[*.c], [echo "C source code"])])
@end example
@noindent
This version avoids the balancing issue altogether, by relying on
@code{AS_CASE} (@pxref{Common Shell Constructs}); it also allows for the
expansion of @code{AC_REQUIRE} to occur prior to the entire case
statement, rather than within a branch of the case statement that might
not be taken. However, the abstraction comes with a penalty that it is
no longer a quick copy, paste, and edit to get back to shell code.
@end table
underquoted argument to an Autoconf macro. @xref{Balancing
Parentheses}, for tradeoffs involved in various styles of dealing with
unbalanced @samp{)}.
Zsh handles pattern fragments derived from parameter expansions or
command substitutions as though quoted: