1# getopt.m4 serial 47
2dnl Copyright (C) 2002-2006, 2008-2021 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7# Request a POSIX compliant getopt function.
8AC_DEFUN([gl_FUNC_GETOPT_POSIX],
9[
10  m4_divert_text([DEFAULTS], [gl_getopt_required=POSIX])
11  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
12  AC_REQUIRE([gl_GETOPT_CHECK_HEADERS])
13  dnl Other modules can request the gnulib implementation of the getopt
14  dnl functions unconditionally, by defining gl_REPLACE_GETOPT_ALWAYS.
15  dnl argp.m4 does this.
16  m4_ifdef([gl_REPLACE_GETOPT_ALWAYS], [
17    REPLACE_GETOPT=1
18  ], [
19    REPLACE_GETOPT=0
20    if test -n "$gl_replace_getopt"; then
21      REPLACE_GETOPT=1
22    fi
23  ])
24  if test $REPLACE_GETOPT = 1; then
25    dnl Arrange for getopt.h to be created.
26    gl_GETOPT_SUBSTITUTE_HEADER
27  fi
28])
29
30# Request a POSIX compliant getopt function with GNU extensions (such as
31# options with optional arguments) and the functions getopt_long,
32# getopt_long_only.
33AC_DEFUN([gl_FUNC_GETOPT_GNU],
34[
35  dnl Set the variable gl_getopt_required, so that all invocations of
36  dnl gl_GETOPT_CHECK_HEADERS in the scope of the current configure file
37  dnl will check for getopt with GNU extensions.
38  dnl This means that if one gnulib-tool invocation requests getopt-posix
39  dnl and another gnulib-tool invocation requests getopt-gnu, it is as if
40  dnl both had requested getopt-gnu.
41  m4_divert_text([INIT_PREPARE], [gl_getopt_required=GNU])
42
43  dnl No need to invoke gl_FUNC_GETOPT_POSIX here; this is automatically
44  dnl done through the module dependency getopt-gnu -> getopt-posix.
45])
46
47# Determine whether to replace the entire getopt facility.
48AC_DEFUN([gl_GETOPT_CHECK_HEADERS],
49[
50  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
51  AC_REQUIRE([AC_PROG_AWK]) dnl for awk that supports ENVIRON
52
53  dnl Persuade Solaris <unistd.h> to declare optarg, optind, opterr, optopt.
54  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
55
56  gl_CHECK_NEXT_HEADERS([getopt.h])
57  if test $ac_cv_header_getopt_h = yes; then
58    HAVE_GETOPT_H=1
59  else
60    HAVE_GETOPT_H=0
61  fi
62  AC_SUBST([HAVE_GETOPT_H])
63
64  gl_replace_getopt=
65
66  dnl Test whether <getopt.h> is available.
67  if test -z "$gl_replace_getopt" && test $gl_getopt_required = GNU; then
68    AC_CHECK_HEADERS([getopt.h], [], [gl_replace_getopt=yes])
69  fi
70
71  dnl Test whether the function getopt_long is available.
72  if test -z "$gl_replace_getopt" && test $gl_getopt_required = GNU; then
73    AC_CHECK_FUNCS([getopt_long_only], [], [gl_replace_getopt=yes])
74  fi
75
76  dnl POSIX 2008 does not specify leading '+' behavior, but see
77  dnl http://austingroupbugs.net/view.php?id=191 for a recommendation on
78  dnl the next version of POSIX.  For now, we only guarantee leading '+'
79  dnl behavior with getopt-gnu.
80  if test -z "$gl_replace_getopt"; then
81    AC_CACHE_CHECK([whether getopt is POSIX compatible],
82      [gl_cv_func_getopt_posix],
83      [
84        dnl Merging these three different test programs into a single one
85        dnl would require a reset mechanism. On BSD systems, it can be done
86        dnl through 'optreset'; on some others (glibc), it can be done by
87        dnl setting 'optind' to 0; on others again (HP-UX, IRIX, OSF/1,
88        dnl Solaris 9, musl libc), there is no such mechanism.
89        if test $cross_compiling = no; then
90          dnl Sanity check. Succeeds everywhere (except on MSVC,
91          dnl which lacks <unistd.h> and getopt() entirely).
92          AC_RUN_IFELSE(
93            [AC_LANG_SOURCE([[
94#include <unistd.h>
95#include <stdlib.h>
96#include <string.h>
97
98int
99main ()
100{
101  static char program[] = "program";
102  static char a[] = "-a";
103  static char foo[] = "foo";
104  static char bar[] = "bar";
105  char *argv[] = { program, a, foo, bar, NULL };
106  int c;
107
108  c = getopt (4, argv, "ab");
109  if (!(c == 'a'))
110    return 1;
111  c = getopt (4, argv, "ab");
112  if (!(c == -1))
113    return 2;
114  if (!(optind == 2))
115    return 3;
116  return 0;
117}
118]])],
119            [gl_cv_func_getopt_posix=maybe],
120            [gl_cv_func_getopt_posix=no])
121          if test $gl_cv_func_getopt_posix = maybe; then
122            dnl Sanity check with '+'. Succeeds everywhere (except on MSVC,
123            dnl which lacks <unistd.h> and getopt() entirely).
124            AC_RUN_IFELSE(
125              [AC_LANG_SOURCE([[
126#include <unistd.h>
127#include <stdlib.h>
128#include <string.h>
129
130int
131main ()
132{
133  static char program[] = "program";
134  static char donald[] = "donald";
135  static char p[] = "-p";
136  static char billy[] = "billy";
137  static char duck[] = "duck";
138  static char a[] = "-a";
139  static char bar[] = "bar";
140  char *argv[] = { program, donald, p, billy, duck, a, bar, NULL };
141  int c;
142
143  c = getopt (7, argv, "+abp:q:");
144  if (!(c == -1))
145    return 4;
146  if (!(strcmp (argv[0], "program") == 0))
147    return 5;
148  if (!(strcmp (argv[1], "donald") == 0))
149    return 6;
150  if (!(strcmp (argv[2], "-p") == 0))
151    return 7;
152  if (!(strcmp (argv[3], "billy") == 0))
153    return 8;
154  if (!(strcmp (argv[4], "duck") == 0))
155    return 9;
156  if (!(strcmp (argv[5], "-a") == 0))
157    return 10;
158  if (!(strcmp (argv[6], "bar") == 0))
159    return 11;
160  if (!(optind == 1))
161    return 12;
162  return 0;
163}
164]])],
165              [gl_cv_func_getopt_posix=maybe],
166              [gl_cv_func_getopt_posix=no])
167          fi
168          if test $gl_cv_func_getopt_posix = maybe; then
169            dnl Detect Mac OS X 10.5, AIX 7.1, mingw bug.
170            AC_RUN_IFELSE(
171              [AC_LANG_SOURCE([[
172#include <unistd.h>
173#include <stdlib.h>
174#include <string.h>
175
176int
177main ()
178{
179  static char program[] = "program";
180  static char ab[] = "-ab";
181  char *argv[3] = { program, ab, NULL };
182  if (getopt (2, argv, "ab:") != 'a')
183    return 13;
184  if (getopt (2, argv, "ab:") != '?')
185    return 14;
186  if (optopt != 'b')
187    return 15;
188  if (optind != 2)
189    return 16;
190  return 0;
191}
192]])],
193              [gl_cv_func_getopt_posix=yes],
194              [gl_cv_func_getopt_posix=no])
195          fi
196        else
197          case "$host_os" in
198            darwin* | aix* | mingw*) gl_cv_func_getopt_posix="guessing no";;
199            *)                       gl_cv_func_getopt_posix="guessing yes";;
200          esac
201        fi
202      ])
203    case "$gl_cv_func_getopt_posix" in
204      *no) gl_replace_getopt=yes ;;
205    esac
206  fi
207
208  if test -z "$gl_replace_getopt" && test $gl_getopt_required = GNU; then
209    AC_CACHE_CHECK([for working GNU getopt function], [gl_cv_func_getopt_gnu],
210      [# Even with POSIXLY_CORRECT, the GNU extension of leading '-' in the
211       # optstring is necessary for programs like m4 that have POSIX-mandated
212       # semantics for supporting options interspersed with files.
213       # Also, since getopt_long is a GNU extension, we require optind=0.
214       # Bash ties 'set -o posix' to a non-exported POSIXLY_CORRECT;
215       # so take care to revert to the correct (non-)export state.
216dnl GNU Coding Standards currently allow awk but not env; besides, env
217dnl is ambiguous with environment values that contain newlines.
218       gl_awk_probe='BEGIN { if ("POSIXLY_CORRECT" in ENVIRON) print "x" }'
219       case ${POSIXLY_CORRECT+x}`$AWK "$gl_awk_probe" </dev/null` in
220         xx) gl_had_POSIXLY_CORRECT=exported ;;
221         x)  gl_had_POSIXLY_CORRECT=yes      ;;
222         *)  gl_had_POSIXLY_CORRECT=         ;;
223       esac
224       POSIXLY_CORRECT=1
225       export POSIXLY_CORRECT
226       AC_RUN_IFELSE(
227        [AC_LANG_PROGRAM([[#include <getopt.h>
228                           #include <stddef.h>
229                           #include <string.h>
230           ]GL_NOCRASH[
231           ]], [[
232             int result = 0;
233
234             nocrash_init();
235
236             /* This code succeeds on glibc 2.8, OpenBSD 4.0, Cygwin, mingw,
237                and fails on Mac OS X 10.5, AIX 5.2, HP-UX 11, IRIX 6.5,
238                OSF/1 5.1, Solaris 10.  */
239             {
240               static char conftest[] = "conftest";
241               static char plus[] = "-+";
242               char *argv[3] = { conftest, plus, NULL };
243               opterr = 0;
244               if (getopt (2, argv, "+a") != '?')
245                 result |= 1;
246             }
247             /* This code succeeds on glibc 2.8, mingw,
248                and fails on Mac OS X 10.5, OpenBSD 4.0, AIX 5.2, HP-UX 11,
249                IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.5.x.  */
250             {
251               static char program[] = "program";
252               static char p[] = "-p";
253               static char foo[] = "foo";
254               static char bar[] = "bar";
255               char *argv[] = { program, p, foo, bar, NULL };
256
257               optind = 1;
258               if (getopt (4, argv, "p::") != 'p')
259                 result |= 2;
260               else if (optarg != NULL)
261                 result |= 4;
262               else if (getopt (4, argv, "p::") != -1)
263                 result |= 6;
264               else if (optind != 2)
265                 result |= 8;
266             }
267             /* This code succeeds on glibc 2.8 and fails on Cygwin 1.7.0.  */
268             {
269               static char program[] = "program";
270               static char foo[] = "foo";
271               static char p[] = "-p";
272               char *argv[] = { program, foo, p, NULL };
273               optind = 0;
274               if (getopt (3, argv, "-p") != 1)
275                 result |= 16;
276               else if (getopt (3, argv, "-p") != 'p')
277                 result |= 16;
278             }
279             /* This code fails on glibc 2.11.  */
280             {
281               static char program[] = "program";
282               static char b[] = "-b";
283               static char a[] = "-a";
284               char *argv[] = { program, b, a, NULL };
285               optind = opterr = 0;
286               if (getopt (3, argv, "+:a:b") != 'b')
287                 result |= 32;
288               else if (getopt (3, argv, "+:a:b") != ':')
289                 result |= 32;
290             }
291             /* This code dumps core on glibc 2.14.  */
292             {
293               static char program[] = "program";
294               static char w[] = "-W";
295               static char dummy[] = "dummy";
296               char *argv[] = { program, w, dummy, NULL };
297               optind = opterr = 1;
298               if (getopt (3, argv, "W;") != 'W')
299                 result |= 64;
300             }
301             return result;
302           ]])],
303        [gl_cv_func_getopt_gnu=yes],
304        [gl_cv_func_getopt_gnu=no],
305        [dnl Cross compiling.
306         dnl Assume the worst, even on glibc platforms.
307         dnl But obey --enable-cross-guesses.
308         gl_cv_func_getopt_gnu="$gl_cross_guess_normal"
309        ])
310       case $gl_had_POSIXLY_CORRECT in
311         exported) ;;
312         yes) AS_UNSET([POSIXLY_CORRECT]); POSIXLY_CORRECT=1 ;;
313         *) AS_UNSET([POSIXLY_CORRECT]) ;;
314       esac
315      ])
316    if test "$gl_cv_func_getopt_gnu" != yes; then
317      gl_replace_getopt=yes
318    else
319      AC_CACHE_CHECK([for working GNU getopt_long function],
320        [gl_cv_func_getopt_long_gnu],
321        [AC_RUN_IFELSE(
322           [AC_LANG_PROGRAM(
323              [[#include <getopt.h>
324                #include <stddef.h>
325                #include <string.h>
326              ]],
327              [[static const struct option long_options[] =
328                  {
329                    { "xtremely-",no_argument,       NULL, 1003 },
330                    { "xtra",     no_argument,       NULL, 1001 },
331                    { "xtreme",   no_argument,       NULL, 1002 },
332                    { "xtremely", no_argument,       NULL, 1003 },
333                    { NULL,       0,                 NULL, 0 }
334                  };
335                /* This code fails on OpenBSD 5.0.  */
336                {
337                  static char program[] = "program";
338                  static char xtremel[] = "--xtremel";
339                  char *argv[] = { program, xtremel, NULL };
340                  int option_index;
341                  optind = 1; opterr = 0;
342                  if (getopt_long (2, argv, "", long_options, &option_index) != 1003)
343                    return 1;
344                }
345                return 0;
346              ]])],
347           [gl_cv_func_getopt_long_gnu=yes],
348           [gl_cv_func_getopt_long_gnu=no],
349           [dnl Cross compiling. Guess no on OpenBSD, yes otherwise.
350            case "$host_os" in
351              openbsd*) gl_cv_func_getopt_long_gnu="guessing no";;
352              *)        gl_cv_func_getopt_long_gnu="guessing yes";;
353            esac
354           ])
355        ])
356      case "$gl_cv_func_getopt_long_gnu" in
357        *yes) ;;
358        *) gl_replace_getopt=yes ;;
359      esac
360    fi
361  fi
362])
363
364AC_DEFUN([gl_GETOPT_SUBSTITUTE_HEADER],
365[
366  AC_CHECK_HEADERS_ONCE([sys/cdefs.h])
367  if test $ac_cv_header_sys_cdefs_h = yes; then
368    HAVE_SYS_CDEFS_H=1
369  else
370    HAVE_SYS_CDEFS_H=0
371  fi
372  AC_SUBST([HAVE_SYS_CDEFS_H])
373
374  AC_DEFINE([__GETOPT_PREFIX], [[rpl_]],
375    [Define to rpl_ if the getopt replacement functions and variables
376     should be used.])
377  GETOPT_H=getopt.h
378  GETOPT_CDEFS_H=getopt-cdefs.h
379  AC_SUBST([GETOPT_H])
380  AC_SUBST([GETOPT_CDEFS_H])
381])
382