Skip to content

Commit

Permalink
getopt: new compat module
Browse files Browse the repository at this point in the history
implementation from OpenBSD
  • Loading branch information
markokr committed Feb 24, 2011
1 parent a0a451e commit 71e78da
Show file tree
Hide file tree
Showing 9 changed files with 718 additions and 4 deletions.
5 changes: 3 additions & 2 deletions doc/mainpage.dox
Expand Up @@ -28,6 +28,9 @@
* <table>
* <tr><th colspan=2> Compat includes </th></tr>
* <tr><td> <usual/base.h> </td><td> Base C environment </td></tr>
* <tr><td> <usual/getopt.h> </td><td> Command line argument processing </td></tr>
* <tr><td> <usual/err.h> </td><td> Error handling for command-line tools </td></tr>
* <tr><td> <usual/netdb.h> </td><td> Async DNS lookup </td></tr>
* <tr><td> <usual/pthread.h> </td><td> Pthreads compat </td></tr>
* <tr><td> <usual/signal.h> </td><td> Signal compat </td></tr>
* <tr><td> <usual/socket.h> </td><td> Socket compat and helper functions </td></tr>
Expand Down Expand Up @@ -64,9 +67,7 @@
* <tr><th colspan=2> OS support </th></tr>
* <tr><td> <usual/event.h> </td><td> libevent compat </td></tr>
* <tr><td> <usual/daemon.h> </td><td> Process daemonization </td></tr>
* <tr><td> <usual/err.h> </td><td> Error handling for command-line tools </td></tr>
* <tr><td> <usual/fileutil.h> </td><td> Various file I/O tools </td></tr>
* <tr><td> <usual/netdb.h> </td><td> Async DNS lookup </td></tr>
* <tr><td> <usual/logging.h> </td><td> Logging framework for daemons </td></tr>
* <tr><td> <usual/pgsocket.h> </td><td> Async Postgres connection framework </td></tr>
* <tr><td> <usual/safeio.h> </td><td> Safety wrappers around OS I/O </td></tr>
Expand Down
3 changes: 2 additions & 1 deletion m4/usual.m4
Expand Up @@ -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
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion test/Makefile
Expand Up @@ -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 =
Expand Down
1 change: 1 addition & 0 deletions test/force_compat.sed
Expand Up @@ -8,3 +8,4 @@
/GETADDRINFO_A/s,^,//,
/INET_NTOP/s,^,//,
/INET_PTON/s,^,//,
/GETOPT/s,^,//,
1 change: 1 addition & 0 deletions test/test_common.c
Expand Up @@ -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 },
Expand Down
1 change: 1 addition & 0 deletions test/test_common.h
Expand Up @@ -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[];

98 changes: 98 additions & 0 deletions test/test_getopt.c
@@ -0,0 +1,98 @@

#include <usual/getopt.h>

#include "test_common.h"

#include <usual/string.h>

#include <stdarg.h>

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
};

0 comments on commit 71e78da

Please sign in to comment.