From 71e78da0d8c99d74348eac1be447b92ca863373c Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Thu, 24 Feb 2011 13:36:39 +0200 Subject: [PATCH] getopt: new compat module implementation from OpenBSD --- doc/mainpage.dox | 5 +- m4/usual.m4 | 3 +- test/Makefile | 3 +- test/force_compat.sed | 1 + test/test_common.c | 1 + test/test_common.h | 1 + test/test_getopt.c | 98 +++++++++ usual/getopt.c | 498 ++++++++++++++++++++++++++++++++++++++++++ usual/getopt.h | 112 ++++++++++ 9 files changed, 718 insertions(+), 4 deletions(-) create mode 100644 test/test_getopt.c create mode 100644 usual/getopt.c create mode 100644 usual/getopt.h diff --git a/doc/mainpage.dox b/doc/mainpage.dox index a8664b1..d22d72f 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -28,6 +28,9 @@ * * * + * + * + * * * * @@ -64,9 +67,7 @@ * * * - * * - * * * * diff --git a/m4/usual.m4 b/m4/usual.m4 index ca64e24..458e28a 100644 --- a/m4/usual.m4 +++ b/m4/usual.m4 @@ -121,7 +121,7 @@ AC_CHECK_HEADERS([arpa/inet.h netinet/in.h netinet/tcp.h]) AC_CHECK_HEADERS([sys/param.h sys/uio.h libgen.h pwd.h grp.h]) AC_CHECK_HEADERS([sys/wait.h sys/mman.h syslog.h netdb.h dlfcn.h]) AC_CHECK_HEADERS([err.h pthread.h endian.h sys/endian.h byteswap.h]) -AC_CHECK_HEADERS([malloc.h regex.h]) +AC_CHECK_HEADERS([malloc.h regex.h getopt.h]) dnl ucred.h may have prereqs AC_CHECK_HEADERS([ucred.h sys/ucred.h], [], [], [ #ifdef HAVE_SYS_TYPES_H @@ -142,6 +142,7 @@ AC_CHECK_FUNCS(basename dirname strlcpy strlcat getpeereid sigaction) AC_CHECK_FUNCS(inet_ntop inet_pton poll getline memrchr regcomp) AC_CHECK_FUNCS(err errx warn warnx getprogname setprogname) AC_CHECK_FUNCS(posix_memalign memalign valloc) +AC_CHECK_FUNCS(getopt getopt_long getopt_long_only) AC_CHECK_FUNCS(fls flsl flsll ffs ffsl ffsll) AC_SEARCH_LIBS(getaddrinfo_a, anl) AC_CHECK_FUNCS(getaddrinfo_a) diff --git a/test/Makefile b/test/Makefile index 7cf9508..9fcf493 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,7 +6,8 @@ SRCS = test_string.c test_crypto.c test_aatree.c test_heap.c \ test_cxalloc.c test_bits.c test_base.c test_netdb.c \ test_cfparser.c test_endian.c test_hashtab.c test_mdict.c \ test_shlist.c test_time.c test_hashing.c test_fileutil.c \ - test_socket.c + test_socket.c test_getopt.c + OBJS = $(addprefix obj/, $(SRCS:.c=.o)) HDRS = test_common.h test_config.h tinytest.h tinytest_macros.h LIBS = diff --git a/test/force_compat.sed b/test/force_compat.sed index 3f5fd4e..828cd29 100644 --- a/test/force_compat.sed +++ b/test/force_compat.sed @@ -8,3 +8,4 @@ /GETADDRINFO_A/s,^,//, /INET_NTOP/s,^,//, /INET_PTON/s,^,//, +/GETOPT/s,^,//, diff --git a/test/test_common.c b/test/test_common.c index dad96ca..6aae1f0 100644 --- a/test/test_common.c +++ b/test/test_common.c @@ -23,6 +23,7 @@ struct testgroup_t groups[] = { { "socket/", socket_tests }, { "netdb/", netdb_tests }, { "cfparser/", cfparser_tests }, + { "getopt/", getopt_tests }, { "mdict/", mdict_tests }, { "time/", time_tests }, { "fileutil/", fileutil_tests }, diff --git a/test/test_common.h b/test/test_common.h index df55fc3..460cbc3 100644 --- a/test/test_common.h +++ b/test/test_common.h @@ -31,4 +31,5 @@ extern struct testcase_t time_tests[]; extern struct testcase_t hashing_tests[]; extern struct testcase_t fileutil_tests[]; extern struct testcase_t socket_tests[]; +extern struct testcase_t getopt_tests[]; diff --git a/test/test_getopt.c b/test/test_getopt.c new file mode 100644 index 0000000..d40f30f --- /dev/null +++ b/test/test_getopt.c @@ -0,0 +1,98 @@ + +#include + +#include "test_common.h" + +#include + +#include + +static const char *xgetopt(const char *opts, const struct option *lopts, ...) +{ + static char resbuf[1024]; + + int i, c, argc = 1; + char *argv[100]; + va_list ap; + char *p = resbuf; + + resbuf[0] = 'X'; + resbuf[1] = 0; + argv[0] = "prog"; + + va_start(ap, lopts); + while (1) { + argv[argc] = va_arg(ap, char *); + if (!argv[argc]) + break; + argc++; + } + va_end(ap); + + opterr = 0; + optind = 0; + while (1) { + if (lopts) + c = getopt_long(argc, argv, opts, lopts, NULL); + else + c = getopt(argc, argv, opts); + if (c == -1) + break; + + switch (c) { + case '?': + return "ERR"; + case ':': + return "EARG"; + case 0: + break; + default: + if (p != resbuf) + *p++ = ','; + if (optarg) + p += sprintf(p, "%c=%s", c, optarg); + else + p += sprintf(p, "%c", c); + } + } + for (i = optind; i < argc; i++) + p += sprintf(p, "|%s", argv[i]); + return resbuf; +} + +static void test_getopt(void *_) +{ + str_check(xgetopt("ab:", NULL, "-abFOO", "zzz", NULL), "a,b=FOO|zzz"); + str_check(xgetopt("ab:", NULL, "-a", "zzz", "-bFOO", NULL), "a,b=FOO|zzz"); + str_check(xgetopt("ab:", NULL, "-b", "FOO", "-", "--", "-a", NULL), "b=FOO|-|-a"); + str_check(xgetopt("ab:", NULL, "--foo", NULL), "ERR"); +end:; +} + +static void test_getopt_long(void *_) +{ + static int longc; + static const char sopts[] = "ab:"; + static const struct option lopts[] = { + { "longa", no_argument, NULL, 'a'}, + { "longb", required_argument, NULL, 'b'}, + { "longc", no_argument, &longc, 'C'}, + { NULL }, + }; + + str_check(xgetopt(sopts, lopts, "--longa", "--", "--longa", NULL), "a|--longa"); + str_check(xgetopt(sopts, lopts, "--longb", "FOO", "ARG", "--longa", NULL), "b=FOO,a|ARG"); + str_check(xgetopt(sopts, lopts, "--longb=BAZ", NULL), "b=BAZ"); + str_check(xgetopt(sopts, lopts, "--longb", NULL), "ERR"); + str_check(xgetopt(sopts, lopts, "--xx", NULL), "ERR"); + str_check(xgetopt(sopts, lopts, "-", "--longc", "ARG", NULL), "|-|ARG"); + tt_assert(longc == 'C'); +end:; +} + +struct testcase_t getopt_tests[] = { + { "getopt", test_getopt }, + { "getopt_long", test_getopt_long }, + END_OF_TESTCASES +}; + diff --git a/usual/getopt.c b/usual/getopt.c new file mode 100644 index 0000000..cae49bf --- /dev/null +++ b/usual/getopt.c @@ -0,0 +1,498 @@ +/* $OpenBSD: getopt_long.c,v 1.24 2010/07/22 19:31:53 blambert Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ + +/* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef NEED_USUAL_GETOPT + +#include +#include + +char *optarg; /* argument associated with option */ +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ + +static int optreset; /* reset getopt. do optind=0 externally */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + warnx(ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + warnx(noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + warnx(recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + warnx(illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + warnx(illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + warnx(recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char *nargv[], const char *options) +{ + return getopt_internal(nargc, nargv, options, NULL, NULL, + FLAG_PERMUTE); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char *nargv[], const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char *nargv[], const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} + +#endif /* NEED_USUAL_GETOPT */ diff --git a/usual/getopt.h b/usual/getopt.h new file mode 100644 index 0000000..2b391f6 --- /dev/null +++ b/usual/getopt.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * getopt compat. + * + * This module provides getopt() and getopt_long(). + */ + +#ifndef _USUAL_GETOPT_H_ +#define _USUAL_GETOPT_H_ + +#include + +#ifndef NEED_USUAL_GETOPT +#if !defined(HAVE_GETOPT_H) || !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_LONG) +#define NEED_USUAL_GETOPT +#endif +#endif + +#ifndef NEED_USUAL_GETOPT + +/* Use system getopt */ +#include + +#else /* NEED_USUAL_GETOPT */ + +/* avoid name collision */ +#define optarg usual_optarg +#define opterr usual_opterr +#define optind usual_optind +#define optopt usual_optopt +#define getopt(a,b,c) usual_getopt(a,b,c) +#define getopt_long(a,b,c,d,e) usual_getopt_long(a,b,c,d,e) + + +/** argument to current option, or NULL if it has none */ +extern char *optarg; +/** Current position in arg string. Starts from 1. Setting to 0 resets state. */ +extern int optind; +/** whether getopt() should print error messages on problems. Default: 1. */ +extern int opterr; +/** Option char which caused error */ +extern int optopt; + +/** long option takes no argument */ +#define no_argument 0 +/** long option requires argument */ +#define required_argument 1 +/** long option has optional argument */ +#define optional_argument 2 + +/** Long option description */ +struct option { + /** name of long option */ + const char *name; + + /** + * whether option takes an argument. + * One of no_argument, required_argument, and optional_argument. + */ + int has_arg; + + /** if not NULL, set *flag to val when option found */ + int *flag; + + /** if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +/** Compat: getopt */ +int getopt(int argc, char *argv[], const char *options); + +/** Compat: getopt_long */ +int getopt_long(int argc, char *argv[], const char *options, + const struct option *longopts, int *longindex); + +/** Compat: getopt_long_only */ +int getopt_long_only(int nargc, char *argv[], const char *options, + const struct option *long_options, int *idx); + + +#endif /* NEED_USUAL_GETOPT */ + +#endif /* !_USUAL_GETOPT_H_ */ -- 2.39.5
Compat includes
Base C environment
Command line argument processing
Error handling for command-line tools
Async DNS lookup
Pthreads compat
Signal compat
Socket compat and helper functions
OS support
libevent compat
Process daemonization
Error handling for command-line tools
Various file I/O tools
Async DNS lookup
Logging framework for daemons
Async Postgres connection framework
Safety wrappers around OS I/O