xref: /freebsd/contrib/kyua/m4/getopt.m4 (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1*b0d29bc4SBrooks Davisdnl Copyright 2010 The Kyua Authors.
2*b0d29bc4SBrooks Davisdnl All rights reserved.
3*b0d29bc4SBrooks Davisdnl
4*b0d29bc4SBrooks Davisdnl Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davisdnl modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davisdnl met:
7*b0d29bc4SBrooks Davisdnl
8*b0d29bc4SBrooks Davisdnl * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davisdnl   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davisdnl * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davisdnl   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davisdnl   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davisdnl * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davisdnl   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davisdnl   without specific prior written permission.
16*b0d29bc4SBrooks Davisdnl
17*b0d29bc4SBrooks Davisdnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davisdnl "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davisdnl LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davisdnl A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davisdnl OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davisdnl SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davisdnl LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davisdnl DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davisdnl THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davisdnl (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davisdnl OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis
30*b0d29bc4SBrooks Davisdnl Checks if getopt(3) supports a + sign to enforce POSIX correctness.
31*b0d29bc4SBrooks Davisdnl
32*b0d29bc4SBrooks Davisdnl In the GNU implementation of getopt(3), we need to pass a + sign at
33*b0d29bc4SBrooks Davisdnl the beginning of the options string to request POSIX behavior.
34*b0d29bc4SBrooks Davisdnl
35*b0d29bc4SBrooks Davisdnl Defines HAVE_GETOPT_GNU if a + sign is supported.
36*b0d29bc4SBrooks DavisAC_DEFUN([_KYUA_GETOPT_GNU], [
37*b0d29bc4SBrooks Davis    AC_CACHE_CHECK(
38*b0d29bc4SBrooks Davis        [whether getopt allows a + sign for POSIX behavior optreset],
39*b0d29bc4SBrooks Davis        [kyua_cv_getopt_gnu], [
40*b0d29bc4SBrooks Davis        AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <stdlib.h>
41*b0d29bc4SBrooks Davis#include <string.h>
42*b0d29bc4SBrooks Davis#include <unistd.h>], [
43*b0d29bc4SBrooks Davis    int argc = 4;
44*b0d29bc4SBrooks Davis    char* argv@<:@5@:>@ = {
45*b0d29bc4SBrooks Davis        strdup("conftest"),
46*b0d29bc4SBrooks Davis        strdup("-+"),
47*b0d29bc4SBrooks Davis        strdup("-a"),
48*b0d29bc4SBrooks Davis        strdup("bar"),
49*b0d29bc4SBrooks Davis        NULL
50*b0d29bc4SBrooks Davis    };
51*b0d29bc4SBrooks Davis    int ch;
52*b0d29bc4SBrooks Davis    int seen_a = 0, seen_plus = 0;
53*b0d29bc4SBrooks Davis
54*b0d29bc4SBrooks Davis    while ((ch = getopt(argc, argv, "+a:")) != -1) {
55*b0d29bc4SBrooks Davis        switch (ch) {
56*b0d29bc4SBrooks Davis        case 'a':
57*b0d29bc4SBrooks Davis            seen_a = 1;
58*b0d29bc4SBrooks Davis            break;
59*b0d29bc4SBrooks Davis
60*b0d29bc4SBrooks Davis        case '+':
61*b0d29bc4SBrooks Davis            seen_plus = 1;
62*b0d29bc4SBrooks Davis            break;
63*b0d29bc4SBrooks Davis
64*b0d29bc4SBrooks Davis        case '?':
65*b0d29bc4SBrooks Davis        default:
66*b0d29bc4SBrooks Davis            ;
67*b0d29bc4SBrooks Davis        }
68*b0d29bc4SBrooks Davis    }
69*b0d29bc4SBrooks Davis
70*b0d29bc4SBrooks Davis    return (seen_a && !seen_plus) ? EXIT_SUCCESS : EXIT_FAILURE;
71*b0d29bc4SBrooks Davis])],
72*b0d29bc4SBrooks Davis        [kyua_cv_getopt_gnu=yes],
73*b0d29bc4SBrooks Davis        [kyua_cv_getopt_gnu=no])
74*b0d29bc4SBrooks Davis    ])
75*b0d29bc4SBrooks Davis    if test "${kyua_cv_getopt_gnu}" = yes; then
76*b0d29bc4SBrooks Davis        AC_DEFINE([HAVE_GETOPT_GNU], [1],
77*b0d29bc4SBrooks Davis                   [Define to 1 if getopt allows a + sign for POSIX behavior])
78*b0d29bc4SBrooks Davis    fi
79*b0d29bc4SBrooks Davis])
80*b0d29bc4SBrooks Davis
81*b0d29bc4SBrooks Davisdnl Checks if optreset exists to reset the processing of getopt(3) options.
82*b0d29bc4SBrooks Davisdnl
83*b0d29bc4SBrooks Davisdnl getopt(3) has an optreset global variable to reset internal state
84*b0d29bc4SBrooks Davisdnl before calling getopt(3) again.  However, optreset is not standard and
85*b0d29bc4SBrooks Davisdnl is only present in the BSD versions of getopt(3).
86*b0d29bc4SBrooks Davisdnl
87*b0d29bc4SBrooks Davisdnl Defines HAVE_GETOPT_WITH_OPTRESET if optreset exists.
88*b0d29bc4SBrooks DavisAC_DEFUN([_KYUA_GETOPT_WITH_OPTRESET], [
89*b0d29bc4SBrooks Davis    AC_CACHE_CHECK(
90*b0d29bc4SBrooks Davis        [whether getopt has optreset],
91*b0d29bc4SBrooks Davis        [kyua_cv_getopt_optreset], [
92*b0d29bc4SBrooks Davis        AC_COMPILE_IFELSE([AC_LANG_SOURCE([
93*b0d29bc4SBrooks Davis#include <stdlib.h>
94*b0d29bc4SBrooks Davis#include <unistd.h>
95*b0d29bc4SBrooks Davis
96*b0d29bc4SBrooks Davisint
97*b0d29bc4SBrooks Davismain(void)
98*b0d29bc4SBrooks Davis{
99*b0d29bc4SBrooks Davis    optreset = 1;
100*b0d29bc4SBrooks Davis    return EXIT_SUCCESS;
101*b0d29bc4SBrooks Davis}
102*b0d29bc4SBrooks Davis])],
103*b0d29bc4SBrooks Davis        [kyua_cv_getopt_optreset=yes],
104*b0d29bc4SBrooks Davis        [kyua_cv_getopt_optreset=no])
105*b0d29bc4SBrooks Davis    ])
106*b0d29bc4SBrooks Davis    if test "${kyua_cv_getopt_optreset}" = yes; then
107*b0d29bc4SBrooks Davis        AC_DEFINE([HAVE_GETOPT_WITH_OPTRESET], [1],
108*b0d29bc4SBrooks Davis                  [Define to 1 if getopt has optreset])
109*b0d29bc4SBrooks Davis    fi
110*b0d29bc4SBrooks Davis])
111*b0d29bc4SBrooks Davis
112*b0d29bc4SBrooks Davis
113*b0d29bc4SBrooks Davisdnl Checks the value to pass to optind to reset getopt(3) processing.
114*b0d29bc4SBrooks Davisdnl
115*b0d29bc4SBrooks Davisdnl The standard value to pass to optind to reset the processing of command
116*b0d29bc4SBrooks Davisdnl lines with getopt(3) is 1.  However, the GNU extensions to getopt_long(3)
117*b0d29bc4SBrooks Davisdnl are not properly reset unless optind is set to 0, causing crashes later
118*b0d29bc4SBrooks Davisdnl on and incorrect option processing behavior.
119*b0d29bc4SBrooks Davisdnl
120*b0d29bc4SBrooks Davisdnl Sets the GETOPT_OPTIND_RESET_VALUE macro to the integer value that has to
121*b0d29bc4SBrooks Davisdnl be passed to optind to reset option processing.
122*b0d29bc4SBrooks DavisAC_DEFUN([_KYUA_GETOPT_OPTIND_RESET_VALUE], [
123*b0d29bc4SBrooks Davis    AC_CACHE_CHECK(
124*b0d29bc4SBrooks Davis        [for the optind value to reset getopt processing],
125*b0d29bc4SBrooks Davis        [kyua_cv_getopt_optind_reset_value], [
126*b0d29bc4SBrooks Davis        AC_RUN_IFELSE([AC_LANG_SOURCE([
127*b0d29bc4SBrooks Davis#include <stdlib.h>
128*b0d29bc4SBrooks Davis#include <string.h>
129*b0d29bc4SBrooks Davis#include <unistd.h>
130*b0d29bc4SBrooks Davis
131*b0d29bc4SBrooks Davisstatic void
132*b0d29bc4SBrooks Davisfirst_pass(void)
133*b0d29bc4SBrooks Davis{
134*b0d29bc4SBrooks Davis    int argc, ch, flag;
135*b0d29bc4SBrooks Davis    char* argv@<:@5@:>@;
136*b0d29bc4SBrooks Davis
137*b0d29bc4SBrooks Davis    argc = 4;
138*b0d29bc4SBrooks Davis    argv@<:@0@:>@ = strdup("progname");
139*b0d29bc4SBrooks Davis    argv@<:@1@:>@ = strdup("-a");
140*b0d29bc4SBrooks Davis    argv@<:@2@:>@ = strdup("foo");
141*b0d29bc4SBrooks Davis    argv@<:@3@:>@ = strdup("bar");
142*b0d29bc4SBrooks Davis    argv@<:@4@:>@ = NULL;
143*b0d29bc4SBrooks Davis
144*b0d29bc4SBrooks Davis    flag = 0;
145*b0d29bc4SBrooks Davis    while ((ch = getopt(argc, argv, "+:a")) != -1) {
146*b0d29bc4SBrooks Davis        switch (ch) {
147*b0d29bc4SBrooks Davis        case 'a':
148*b0d29bc4SBrooks Davis            flag = 1;
149*b0d29bc4SBrooks Davis            break;
150*b0d29bc4SBrooks Davis        default:
151*b0d29bc4SBrooks Davis            break;
152*b0d29bc4SBrooks Davis        }
153*b0d29bc4SBrooks Davis    }
154*b0d29bc4SBrooks Davis    if (!flag) {
155*b0d29bc4SBrooks Davis        exit(EXIT_FAILURE);
156*b0d29bc4SBrooks Davis    }
157*b0d29bc4SBrooks Davis}
158*b0d29bc4SBrooks Davis
159*b0d29bc4SBrooks Davisstatic void
160*b0d29bc4SBrooks Davissecond_pass(void)
161*b0d29bc4SBrooks Davis{
162*b0d29bc4SBrooks Davis    int argc, ch, flag;
163*b0d29bc4SBrooks Davis    char* argv@<:@5@:>@;
164*b0d29bc4SBrooks Davis
165*b0d29bc4SBrooks Davis    argc = 4;
166*b0d29bc4SBrooks Davis    argv@<:@0@:>@ = strdup("progname");
167*b0d29bc4SBrooks Davis    argv@<:@1@:>@ = strdup("-b");
168*b0d29bc4SBrooks Davis    argv@<:@2@:>@ = strdup("foo");
169*b0d29bc4SBrooks Davis    argv@<:@3@:>@ = strdup("bar");
170*b0d29bc4SBrooks Davis    argv@<:@4@:>@ = NULL;
171*b0d29bc4SBrooks Davis
172*b0d29bc4SBrooks Davis    flag = 0;
173*b0d29bc4SBrooks Davis    while ((ch = getopt(argc, argv, "b")) != -1) {
174*b0d29bc4SBrooks Davis        switch (ch) {
175*b0d29bc4SBrooks Davis        case 'b':
176*b0d29bc4SBrooks Davis            flag = 1;
177*b0d29bc4SBrooks Davis            break;
178*b0d29bc4SBrooks Davis        default:
179*b0d29bc4SBrooks Davis            break;
180*b0d29bc4SBrooks Davis        }
181*b0d29bc4SBrooks Davis    }
182*b0d29bc4SBrooks Davis    if (!flag) {
183*b0d29bc4SBrooks Davis        exit(EXIT_FAILURE);
184*b0d29bc4SBrooks Davis    }
185*b0d29bc4SBrooks Davis}
186*b0d29bc4SBrooks Davis
187*b0d29bc4SBrooks Davisint
188*b0d29bc4SBrooks Davismain(void)
189*b0d29bc4SBrooks Davis{
190*b0d29bc4SBrooks Davis    /* We do two passes in two different functions to prevent the reuse of
191*b0d29bc4SBrooks Davis     * variables and, specially, to force the use of two different argument
192*b0d29bc4SBrooks Davis     * vectors. */
193*b0d29bc4SBrooks Davis    first_pass();
194*b0d29bc4SBrooks Davis    optind = 0;
195*b0d29bc4SBrooks Davis    second_pass();
196*b0d29bc4SBrooks Davis    return EXIT_SUCCESS;
197*b0d29bc4SBrooks Davis}
198*b0d29bc4SBrooks Davis])],
199*b0d29bc4SBrooks Davis        [kyua_cv_getopt_optind_reset_value=0],
200*b0d29bc4SBrooks Davis        [kyua_cv_getopt_optind_reset_value=1])
201*b0d29bc4SBrooks Davis    ])
202*b0d29bc4SBrooks Davis    AC_DEFINE_UNQUOTED([GETOPT_OPTIND_RESET_VALUE],
203*b0d29bc4SBrooks Davis        [${kyua_cv_getopt_optind_reset_value}],
204*b0d29bc4SBrooks Davis        [Define to the optind value to reset getopt processing])
205*b0d29bc4SBrooks Davis])
206*b0d29bc4SBrooks Davis
207*b0d29bc4SBrooks Davis
208*b0d29bc4SBrooks Davisdnl Wrapper macro to detect all getopt(3) necessary features.
209*b0d29bc4SBrooks DavisAC_DEFUN([KYUA_GETOPT], [
210*b0d29bc4SBrooks Davis    _KYUA_GETOPT_GNU
211*b0d29bc4SBrooks Davis    _KYUA_GETOPT_OPTIND_RESET_VALUE
212*b0d29bc4SBrooks Davis    _KYUA_GETOPT_WITH_OPTRESET
213*b0d29bc4SBrooks Davis])
214