autoconf: Balancing Parentheses

1 
1 8.1.7 Dealing with unbalanced parentheses
1 -----------------------------------------
1 
1 One of the pitfalls of portable shell programming is that `case'
11 statements require unbalanced parentheses (⇒Limitations of Shell
 Builtins case.).  With syntax highlighting editors, the presence of
1 unbalanced `)' can interfere with editors that perform syntax
1 highlighting of macro contents based on finding the matching `('.
1 Another concern is how much editing must be done when transferring code
1 snippets between shell scripts and macro definitions.  But most
1 importantly, the presence of unbalanced parentheses can introduce
1 expansion bugs.
1 
1    For an example, here is an underquoted attempt to use the macro
1 `my_case', which happens to expand to a portable `case' statement:
1 
1      AC_DEFUN([my_case],
1      [case $file_name in
1        *.c) echo "C source code";;
1      esac])
1      AS_IF(:, my_case)
1 
1 In the above example, the `AS_IF' call underquotes its arguments.  As a
1 result, the unbalanced `)' generated by the premature expansion of
1 `my_case' results in expanding `AS_IF' with a truncated parameter, and
1 the expansion is syntactically invalid:
1 
1      if :; then
1        case $file_name in
1        *.c
1      fi echo "C source code";;
1      esac)
1 
1    If nothing else, this should emphasize the importance of the quoting
1 arguments to macro calls.  On the other hand, there are several
1 variations for defining `my_case' to be more robust, even when used
1 without proper quoting, each with some benefits and some drawbacks.
1 
1      Creative literal shell comment
1           AC_DEFUN([my_case],
1           [case $file_name in #(
1             *.c) echo "C source code";;
1           esac])
1      This version provides balanced parentheses to several editors, and
1      can be copied and pasted into a terminal as is.  Unfortunately, it
1      is still unbalanced as an Autoconf argument, since `#(' is an M4
1      comment that masks the normal properties of `('.
1 
1      Quadrigraph shell comment
1           AC_DEFUN([my_case],
1           [case $file_name in @%:@(
1             *.c) echo "C source code";;
1           esac])
1      This version provides balanced parentheses to even more editors,
1      and can be used as a balanced Autoconf argument.  Unfortunately,
1      it requires some editing before it can be copied and pasted into a
1      terminal, and the use of the quadrigraph `@%:@' for `#' reduces
1      readability.
1 
1      Quoting just the parenthesis
1           AC_DEFUN([my_case],
1           [case $file_name in
1             *.c[)] echo "C source code";;
1           esac])
1      This version quotes the `)', so that it can be used as a balanced
1      Autoconf argument.  As written, this is not balanced to an editor,
1      but it can be coupled with `[#(]' to meet that need, too.
1      However, it still requires some edits before it can be copied and
1      pasted into a terminal.
1 
1      Double-quoting the entire statement
1           AC_DEFUN([my_case],
1           [[case $file_name in #(
1             *.c) echo "C source code";;
1           esac]])
1      Since the entire macro is double-quoted, there is no problem with
1      using this as an Autoconf argument; and since the double-quoting
1      is over the entire statement, this code can be easily copied and
1      pasted into a terminal.  However, the double quoting prevents the
1      expansion of any macros inside the case statement, which may cause
1      its own set of problems.
1 
1      Using `AS_CASE'
1           AC_DEFUN([my_case],
1           [AS_CASE([$file_name],
1             [*.c], [echo "C source code"])])
1      This version avoids the balancing issue altogether, by relying on
1      `AS_CASE' (⇒Common Shell Constructs); it also allows for the
1      expansion of `AC_REQUIRE' to occur prior to the entire case
1      statement, rather than within a branch of the case statement that
1      might not be taken.  However, the abstraction comes with a penalty
1      that it is no longer a quick copy, paste, and edit to get back to
1      shell code.
1