manpagez: man pages & more
info autoconf
Home | html | info | man

File: autoconf.info,  Node: Balancing Parentheses,  Next: Quotation Rule Of Thumb,  Prev: Quadrigraphs,  Up: M4 Quotation

8.1.7 Dealing with unbalanced parentheses
-----------------------------------------

One of the pitfalls of portable shell programming is that if you intend
your script to run with obsolescent shells, ‘case’ statements require
unbalanced parentheses.  *Note Limitations of Shell Builtins: case.
With syntax highlighting editors, the presence of unbalanced ‘)’ can
interfere with editors that perform syntax highlighting of macro
contents based on finding the matching ‘(’.  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
‘my_case’, which happens to expand to a portable ‘case’ statement:

     AC_DEFUN([my_case],
     [case $file_name in
       *.c) echo "C source code";;
     esac])
     AS_IF(:, my_case)

In the above example, the ‘AS_IF’ call under-quotes its arguments.  As a
result, the unbalanced ‘)’ generated by the premature expansion of
‘my_case’ results in expanding ‘AS_IF’ with a truncated parameter, and
the expansion is syntactically invalid:

     if :
     then :
       case $file_name in
       *.c
     fi echo "C source code";;
     esac)

   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 ‘my_case’ to be more robust, even when used
without proper quoting, each with some benefits and some drawbacks.

     Use left parenthesis before pattern
          AC_DEFUN([my_case],
          [case $file_name in
            (*.c) echo "C source code";;
          esac])
     This is simple and provides balanced parentheses.  Although this is
     not portable to obsolescent shells (notably Solaris 10 ‘/bin/sh’),
     platforms with these shells invariably have a more-modern shell
     available somewhere so this approach typically suffices nowadays.

     Creative literal shell comment
          AC_DEFUN([my_case],
          [case $file_name in #(
            *.c) echo "C source code";;
          esac])
     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 ‘#(’ is an M4
     comment that masks the normal properties of ‘(’.

     Quadrigraph shell comment
          AC_DEFUN([my_case],
          [case $file_name in @%:@(
            *.c) echo "C source code";;
          esac])
     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 ‘@%:@’ for ‘#’ reduces
     readability.

     Quoting just the parenthesis
          AC_DEFUN([my_case],
          [case $file_name in
            *.c[)] echo "C source code";;
          esac])
     This version quotes the ‘)’, 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 ‘[#(]’ to meet that need, too.  However,
     it still requires some edits before it can be copied and pasted
     into a terminal.

     Double-quoting the entire statement
          AC_DEFUN([my_case],
          [[case $file_name in #(
            *.c) echo "C source code";;
          esac]])
     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.

     Using ‘AS_CASE’
          AC_DEFUN([my_case],
          [AS_CASE([$file_name],
            [*.c], [echo "C source code"])])
     This version avoids the balancing issue altogether, by relying on
     ‘AS_CASE’ (*note Common Shell Constructs::); it also allows for the
     expansion of ‘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.

© manpagez.com 2000-2025
Individual documents may contain additional copyright information.