http://invisible-island.net/autoconf/
Copyright © 2020 by Thomas E. Dickey
The Open Group's documentation for the shell utility describes the syntax for Case Conditional Construct like this:
The format for the case construct is as follows: case word in [(]pattern1) compound-list;; [[(]pattern[ | pattern] ... ) compound-list;;] ... [[(]pattern[ | pattern] ... ) compound-list] esac The ";;" is optional for the last compound-list.
The left parentheses “(” is optional in scripts, but a standard shell utility must accept scripts using either syntax.
While autoconf makes no particular use of the shell's
case
statement, the shell fragments
in the autoconf macros do use the feature. For instance, a quick
count gives some numbers:
But grep shows something interesting in the “new” source:
lib/autoconf/general.m4:1852:case $$1_os in *\ *) $1_os=`echo "$$1_os" | sed 's/ /-/g'`;; esac lib/autoconf/general.m4:1953: case $CONFIG_SITE in @%:@(( lib/autoconf/general.m4:1986: case $cache_file in lib/autoconf/general.m4:2010: case $ac_val in #( lib/autoconf/general.m4:2012: case $ac_var in #( lib/autoconf/general.m4:2015: case $ac_var in #( lib/autoconf/general.m4:2024: case $as_nl`(ac_space=' '; set) 2>&1` in #( lib/autoconf/general.m4:2080:dnl at the same time, avoid filename limitation issues in the common case. lib/autoconf/general.m4:2081: case $cache_file in #( lib/autoconf/general.m4:2189:# with an unquoted here-doc, but avoiding a fork in the common case of lib/autoconf/general.m4:2193:# but quadrigraphs are fine in that case. lib/autoconf/general.m4:2439:[[case "(($ac_try" in lib/autoconf/general.m4:2935:case $ac_cv_[]_AC_LANG_ABBREV[]_decl_report in lib/autoconf/general.m4:3059:[case " $LIB@&t@OBJS " in
Contrast that with older autoconf (2.52):
acgeneral.m4:3685: case $[1] in acgeneral.m4:3699: case $[1] in acgeneral.m4:3775: case "$ac_config_target" in acgeneral.m4:3971: case $ac_file in acgeneral.m4:3992: case $srcdir in acgeneral.m4:4008:[ case $INSTALL in acgeneral.m4:4028: case $f in acgeneral.m4:4131: case $ac_file in acgeneral.m4:4213: case $ac_file in acgeneral.m4:4229: case $f in
and ask, why that #(
comment is
used. The answer is that the comment helps a text-editor program
to show its user where a matching parenthesis is in the file. The
case
statement uses parentheses.
The lines of the shell script between
case
and
esac
have patterns
followed by “)” (a right-parenthesis). A left
parenthesis is optional, and omitted from the autoconf
sources.
If you take the time to research the source history, you might notice that the odd comments were added by developers who use vim. However, the feature which is addressed predates vim.
Interestingly enough, vi has had some lisp influence:
This was a documented option of vi, first mentioned in 2BSD, and carried forward into subsequent versions. For example, see The vi User's Handbook (1984), page 43 which says:
If lisp ... makes it easier for you to edit lisp programs. Indents code appropriately for lisp (if you have autoindent set), and modifies the
()
,{}
,[[
and]]
commands to have meaning for lisp. Enables the==
(formatted print) operator for S-expressions. Also see showmatch (page 45).
and on page 45, showmatch
is
documented
If sm ... in Input Mode, whenever you type a ) or }, the cursor will move to the matching ( or { for 1 second if it is on the screen.
As a result, vi users expect to be able to readily find the match for a parenthesis. The fact that the feature was more important for lisp development than, say C, was not really relevant. But generalizing to editing other types of files (such as the mixture of M4 and Bourne shell in autoconf) would need a better tool than vi.
Someone might suppose that Emacs does this. After all, the
early autoconf developers used Emacs, and would have
relied upon its special features. But bear in mind that very few
Emacs users are tool developers. While Emacs has its own
equivalent to showmatch
(blink-matching-paren
),
its
sh-script.el cannot reliably determine if a parenthesis is in
a comment or in a quoted string.
If a better tool is not available, developers use workarounds. I used a special comment in shell scripts to handle this, as early as September 1997 when I began the my-autoconf archive, e.g.,
case $host_os in #(vi freebsd*) AC_CHECK_LIB(mytinfo,tgoto,[LIBS="-lmytinfo $LIBS"]) ;; esac
The idea was not original to me (I recall that it was suggested by Paul Fox). For the cases I noticed, the autoconf developers began doing this in April 2006. Others' experience may vary.
Adding a special comment with the left-parenthesis to simplify
editing was a nuisance because if an instance was overlooked in a
long case-statement, it was not possible to find the matching
parentheses. However the workaround was useful because
autoconf macros use nested
“[
” and
“]
” along with nested
parentheses. If one of those is incorrectly nested, the error may
not be apparent.
In 2015, another developer pointed out that the shell feature
with the left-parenthesis in case
patterns was standard. Because it had been a standard
feature for a long time (about 20 years), it seemed about time to
use it. I made this change to the macro:
2015-04-12 Thomas E. Dickey <dickey@invisible-island.net> * AcSplit/CF_ADD_CFLAGS, AcSplit/CF_CC_ENV_FLAGS, AcSplit/CF_ENABLE_NARROWPROTO, ... eliminate unnecessary "#(vi" markers in autoconf macros by using "(" to begin case-statement cases (suggested by Jens Schweikhardt) * AcSplit/CF_LIB_RULES, AcSplit/CF_LIB_SUFFIX, AcSplit/CF_SRC_MODULES: modified for ncurses --with-extra-suffix option
and used it in xterm patch #318.
A few months later, when doing test-builds before ncurses 6.0,
I noticed that this did not work well with Solaris 10 (whose
/bin/sh
does not conform to the
standard). This system uses a (modified) BSD shell utility by
default, while providing a set of standard utilities in a
separate directory to assert compliance with the XPG4
standard.
Solaris 10 was released in 2005, and was superceded by Solaris
11 in 2010.
Solaris 11.1 (October 2012) changed
/bin/sh
into a symbolic link
pointing to ksh93.
Since Solaris 10 provided a workable shell in
/usr/xpg4/bin
, a short discussion
in ncurses
6's release notes explaining how to build on that platform
was the appropriate choice.
Just documenting it does not make the problem go away (for some people, at least):
Although the mainstream of Solaris development adopted
ksh93, at least one descendent of the Solaris 10
code has been updated since then, with a fix
“DO_POSIX_CASE
” applied a few months
later, and then revised in mid-2017.
A few users (or developers) ask about building on Solaris 10. For instance, in October 2018, on the bug-ncurses mailing list ./configure generated script fails on solaris
Solaris is not the only operating system which might have pre-POSIX tools. In January 2019, when one of the developers for the tin newsreader reported that the change did not work with Ultrix 4.3, I wrote a script to allow him to transform tin's configure script into an XPG3-compliant script.