/************************************************************************ * * 0.cmdopts.cpp - test exercising the rw_runopts() and rw_setopts() * utility functions * * $Id: 0.cmdopts.cpp 590052 2007-10-30 12:44:14Z faridz $ * ************************************************************************ * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Copyright 2005-2006 Rogue Wave Software. * **************************************************************************/ #include #include #include // global buffer containing the names of all callbacks (along with // their arguments) called in response to each invocation to rw_runopts() static char argstr [4096]; // the maximum number of callbacks to be invoked by a single call // to rw_runopts() #define MAXCALLBACKS 32 // the values to be returned by each callback static int retvals [MAXCALLBACKS]; // the cumulative number of callback invocations static size_t ncalls; // the exit status of the whole test static int exit_status; // the current line number static int current_line; /**************************************************************************/ // prints its arguments in a human-readable form to buf static int pargs (char *buf, const char *funcname, int argc, char *argv []) { _RWSTD_ASSERT (0 != buf); char* next = buf + strlen (buf); if ('\0' != *buf) { next [0] = ';'; next [1] = '\0'; ++next; } if (funcname) next += sprintf (next, "%s(%d,{", funcname, argc); else next += sprintf (next, "%d,{", argc); for (int i = 0; i < argc; ++i) { if (argv [i]) next += sprintf (next, "\"%s\"", argv [i]); else { strcpy (next, "(null)"); next += strlen (next); } if (i + 1 < argc) { next [0] = ','; next [1] = '\0'; ++next; } } next [0] = '}'; next [1] = ')'; next [2] = '\0'; // verify that the number of calls hasn't exceeded the size // of the array of return values _RWSTD_ASSERT (ncalls < MAXCALLBACKS); return retvals [ncalls]; } /**************************************************************************/ static int callback_imp (const char *cbname, int argc, char *argv[]) { const int status = pargs (argstr, cbname, argc, argv); ++ncalls; return status; } static int foo (int argc, char *argv[]) { return callback_imp ("foo", argc, argv); } static int bar (int argc, char *argv[]) { return callback_imp ("bar", argc, argv); } static int err (int argc, char *argv[]) { return callback_imp ("ERR", argc, argv); } /**************************************************************************/ typedef int (cbfun_t)(int, char*[]); static int opt_counts [4]; // hackery to allow passing int* and cbfun_t* in the same argument static const union { int *pint; cbfun_t *pfun; int ival; } cntptrs [] = { { opt_counts + 0 }, { opt_counts + 1 }, { opt_counts + 2 }, { opt_counts + 3 } }; /**************************************************************************/ static void test_opts (const char *expect, int get_exp, char *argv [], int set_exp, const char *argspec, cbfun_t *f0, cbfun_t *f1 = 0, cbfun_t *f2 = 0, cbfun_t *f3 = 0) { argstr [0] = '\0'; // reset all previously set options rw_setopts (0, 0); // set new options const int set_res = rw_setopts (argspec, f0, f1, f2, f3); if (set_res != set_exp) { // convert function pointers to void pointers // to avoid compiler error and warnings union { cbfun_t *pfun; void *pvoid; } uptr[] = { { f0 }, { f1 }, { f2 }, { f3 } }; fprintf (stderr, "line %d: rw_setopts (\"%s\", %p, %p, %p, %p) == %d, got %d\n", current_line, argspec, uptr [0].pvoid, uptr [1].pvoid, uptr [2].pvoid, uptr [3].pvoid, set_exp, set_res); exit_status = 1; } argstr [0] = '\0'; // compute the value of argc from argv int argc = 0; for (; argv [argc]; ++argc); // reset the number of callback invocations ncalls = 0; // reset the option counters memset (opt_counts, 0, sizeof opt_counts); const int get_res = rw_runopts (argc, argv); if (get_res != get_exp) { static char tmp [4096]; tmp [0] = '\0'; pargs (tmp, 0, argc, argv); fprintf (stderr, "line %d: rw_runopts (%s) == %d, got %d\n", current_line, tmp, get_exp, get_res); exit_status = 1; } if (strchr (expect, '#')) { // when the expected result string contains the pound sign, // treat the arguments as pointers to integers as opposed // to pointers to callback functions and format the actual // result as a sequence of integers at the given addresses if (f0 == cntptrs [0].pfun) { sprintf (argstr + strlen (argstr), "%s%d", *argstr ? "; #" : "#", opt_counts [0]); if (f1 == cntptrs [1].pfun) { sprintf (argstr + strlen (argstr), ",%d", opt_counts [1]); if (f2 == cntptrs [2].pfun) { sprintf (argstr + strlen (argstr), ",%d", opt_counts [2]); if (f3 == cntptrs [3].pfun) { sprintf (argstr + strlen (argstr), ",%d", opt_counts [3]); } } } } } if (strcmp (argstr, expect)) { fprintf (stderr, "line %d: \"%s\" != \"%s\"\n", current_line, argstr, expect); exit_status = 1; } } /**************************************************************************/ static char** mkargv (const char *s0, const char *s1 = 0, const char *s2 = 0, const char *s3 = 0, const char *s4 = 0, const char *s5 = 0, const char *s6 = 0, const char *s7 = 0, const char *s8 = 0, const char *s9 = 0) { static char argbuf [10][1024]; static char* argv [10]; argv [0] = s0 ? strcpy (argbuf [0], s0) : 0; argv [1] = s1 ? strcpy (argbuf [1], s1) : 0; argv [2] = s2 ? strcpy (argbuf [2], s2) : 0; argv [3] = s3 ? strcpy (argbuf [3], s3) : 0; argv [4] = s4 ? strcpy (argbuf [4], s4) : 0; argv [5] = s5 ? strcpy (argbuf [5], s5) : 0; argv [6] = s6 ? strcpy (argbuf [6], s6) : 0; argv [7] = s7 ? strcpy (argbuf [7], s7) : 0; argv [8] = s8 ? strcpy (argbuf [8], s8) : 0; argv [9] = s9 ? strcpy (argbuf [9], s9) : 0; return argv; } /**************************************************************************/ // convenience macros for brevity #define A mkargv #define B bar #define F foo #define E err #define C0 cntptrs [0].pfun #define C1 cntptrs [1].pfun #define C2 cntptrs [2].pfun #define C3 cntptrs [3].pfun #define N(n) make_arg (n) #define T (current_line = __LINE__), test_opts /**************************************************************************/ static void test_unknown_options () { // +--------- expected result string (formatted by callbacks) // | +----- expected value returned from rw_runopts() // | | +-- second argument to rw_runopts() (argv) // | | | // | | | +---------- expected rw_setopts() result // | | | | +------- rw_setopts() first argument // | | | | | +-- rw_setopts() callbacks... // | | | | | | // V V V V V V T ("", 0, A (""), 0, "", 0); // exercise setting up the "unknown option" handler T ("", 0, A (""), 1, "-", 0); T ("", 0, A (""), 1, "-", E); // exercise invoking the "unknown option" handler T ("ERR(1,{\"-x\"})", 0, A ("-x"), 2, "- f", E, F); T ("ERR(2,{\"-x\",\"-y\"});" "foo(1,{\"-y\"})", 0, A ("-x","-y"), 2, "- y", E, F); retvals [0] = 1; T ("ERR(2,{\"-x\",\"-y\"})", 1, A ("-x","-y"), 2, "- y", E, F); retvals [0] = 0; retvals [1] = 2; T ("foo(2,{\"-x\",\"-y\"});" "ERR(1,{\"-y\"})", 2, A ("-x","-y"), 2, "- x", E, F); T ("foo(3,{\"-x\",\"-y\",\"-x\"});" "ERR(2,{\"-y\",\"-x\"})", 2, A ("-x","-y", "-x"), 2, "- x", E, F); retvals [1] = 0; } /**************************************************************************/ static void test_counted_options () { // exercise options with a counter instead of a callback T ("#1", 0, A ("-b"), 1, "b#", C0); T ("#1", 0, A ("--cc"), 1, "|-cc#", C0); T ("#2", 0, A ("-d", "-d"), 1, "d#", C0); T ("#2", 0, A ("-e", "--ee"), 1, "e|-ee#", C0); T ("#3", 0, A ("-e", "-e", "-e"), 1, "e#", C0); T ("#1,2", 0, A ("-f", "-g", "-g"), 2, "f# g#", C0, C1); // exercise counted options with a numerical argument T ("#0", 0, A ("--n=0"), 1, "|-n#", C0); T ("#1", 0, A ("--n=1"), 1, "|-n#", C0); T ("#1", 0, A ("--n=+1"), 1, "|-n#", C0); T ("#-1", 0, A ("--n=-1"), 1, "|-n#", C0); T ("#2", 0, A ("--n=+2"), 1, "|-n#", C0); T ("#-2", 0, A ("--n=-2"), 1, "|-n#", C0); T ("#12345", 0, A ("--n=+12345"), 1, "|-n#", C0); T ("#-12346", 0, A ("--n=-12346"), 1, "|-n#", C0); // exercise counted options with a restricted numerical argument T ("#0", 0, A ("--n=0"), 1, "|-n#0", C0); T ("#1", 0, A ("--n=1"), 1, "|-n#0", C0); T ("#1", 0, A ("--n=1"), 1, "|-n#1", C0); T ("#2", 0, A ("--n=2"), 1, "|-n#1", C0); T ("#1", 0, A ("--n=+1"), 1, "|-n#+1", C0); T ("#-1", 0, A ("--n=-1"), 1, "|-n#-1", C0); T ("#0", 0, A ("--n=0"), 1, "|-n#-1", C0); T ("#1", 0, A ("--n=1"), 1, "|-n#-1", C0); T ("#123", 0, A ("--n=+123"), 1, "|-n#+123", C0); T ("#124", 0, A ("--n=+124"), 1, "|-n#+123", C0); T ("#-125", 0, A ("--n=-125"), 1, "|-n#-125", C0); T ("#-126", 0, A ("--n=-126"), 1, "|-n#-127", C0); T ("#0", 0, A ("--n=0"), 1, "|-n#0-1", C0); T ("#1", 0, A ("--n=1"), 1, "|-n#0-1", C0); T ("#0", 0, A ("--n=0"), 1, "|-n#-1-0", C0); // same as above but with an out of range argument T ("", 1, A ("--n=1"), 1, "|-n#-1-0", C0); T ("", 1, A ("--n=-1"), 1, "|-n#0", C0); T ("", 1, A ("--n=0"), 1, "|-n#1", C0); T ("", 1, A ("--n=1"), 1, "|-n#2", C0); T ("", 1, A ("--n=+2"), 1, "|-n#+3", C0); T ("", 1, A ("--n=-1"), 1, "|-n#0-1", C0); T ("", 1, A ("--n=+2"), 1, "|-n#0-1", C0); T ("", 1, A ("--n=-11"), 1, "|-n#-10--5", C0); T ("", 1, A ("--n=-4"), 1, "|-n#-10--5", C0); T ("", 1, A ("--n=-11"), 1, "|-n#-1-1", C0); T ("", 1, A ("--n=-1"), 1, "|-n#0-32", C0); T ("", 1, A ("--n=33"), 1, "|-n#0-32", C0); } /**************************************************************************/ static void test_tristate () { // +-- expected result string // | +-- expected return value from rw_getopts() // | | +-- command line arguments // | | | +-- number of directives // | | | | +-- cmdopt specification // | | | | | +-- counter // | | | | | | // V V V V V V T ("#1", 0, A ("--enable-foo"), 1, "|-foo~", C0); T ("#1", 0, A ("--use-foo"), 1, "|-foo~", C0); T ("#1", 0, A ("--with-foo"), 1, "|-foo~", C0); T ("#-1", 0, A ("--disable-foo"), 1, "|-foo~", C0); T ("#-1", 0, A ("--no-foo"), 1, "|-foo~", C0); T ("#-1", 0, A ("--without-foo"), 1, "|-foo~", C0); // the same tristate can be repeated any number of times T ("#1", 0, A ("--enable-foo", "--use-foo"), 1, "|-foo~", C0); T ("#-1", 0, A ("--no-foo", "--without-foo"), 1, "|-foo~", C0); // the last tristate wins T ("#-1", 0, A ("--use-foo", "--no-foo"), 1, "|-foo~", C0); T ("#1", 0, A ("--no-foo", "--use-foo"), 1, "|-foo~", C0); ////////////////////////////////////////////////////////////////// // set bits using a bitmap T ("#1", 0, A ("--enable-foo"), 1, "|-foo~:0", C0); T ("#1", 0, A ("--enable-foo"), 1, "|-foo~:1", C0); T ("#2", 0, A ("--enable-foo"), 1, "|-foo~:2", C0); T ("#3", 0, A ("--enable-foo"), 1, "|-foo~:3", C0); T ("#4", 0, A ("--enable-foo"), 1, "|-foo~:4", C0); // unset bits using a bitmap T ("#-2", 0, A ("--disable-foo"), 1, "|-foo~:1", C0); T ("#-3", 0, A ("--disable-foo"), 1, "|-foo~:2", C0); T ("#-4", 0, A ("--disable-foo"), 1, "|-foo~:3", C0); T ("#-5", 0, A ("--disable-foo"), 1, "|-foo~:4", C0); // set bits in word 2 T ("#0,1", 0, A ("--enable-bar"), 1, "|-bar~32:0", C0, C1); T ("#0,1", 0, A ("--enable-bar"), 1, "|-bar~32:1", C0, C1); T ("#0,2", 0, A ("--enable-bar"), 1, "|-bar~32:2", C0, C1); T ("#0,3", 0, A ("--enable-bar"), 1, "|-bar~32:3", C0, C1); T ("#0,4", 0, A ("--enable-bar"), 1, "|-bar~32:4", C0, C1); // enable bits 0 through 4 in C0 one at a time T ("#1", 0, A ("--with-0"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); T ("#2", 0, A ("--with-1"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); T ("#4", 0, A ("--with-2"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); T ("#8", 0, A ("--with-3"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); // enable multiple bits 0 through 4 in C0 simultaneously T ("#3", 0, A ("--with-0", "--with-1"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); T ("#7", 0, A ("--with-0", "--with-1", "--with-2"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); T ("#15", 0, A ("--with-0", "--with-1", "--with-2", "--with-3"), 4, "|-0~0 |-1~1 |-2~2 |-3~3", C0, C0, C0, C0); // specify bit value T ("#1", 0, A ("--with-0"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#2", 0, A ("--with-1"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#4", 0, A ("--with-2"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#8", 0, A ("--with-3"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#3", 0, A ("--with-0", "--with-1"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#7", 0, A ("--with-0", "--with-1", "--with-2"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#15", 0, A ("--with-0", "--with-1", "--with-2", "--with-3"), 4, "|-0~0:1 |-1~1:1 |-2~2:1 |-3~3:1", C0, C0, C0, C0); T ("#-1073741824", 0, A ("--enable-f30"), 3, "|-f30~30:3 |-f28~28:2 |-f26~26:2", C0, C0, C0); T ("#-2147483648", 0, A ("--enable-f30"), 3, "|-f30~30:2 |-f28~28:2 |-f26~26:2", C0, C0, C0); T ("#-1610612736", 0, A ("--enable-f30","--enable-f28"), 3, "|-f30~30:2 |-f28~28:2 |-f26~26:2", C0, C0, C0); T ("#-1476395008", 0, A ("--enable-f30","--enable-f28","--enable-f26"), 3, "|-f30~30:2 |-f28~28:2 |-f26~26:2", C0, C0, C0); } /**************************************************************************/ static void test_optional_argument () { // exercise an option with an optional argument T ("foo(1,{\"-a\"})", 0, A ("-a"), 1, "a:", F); T ("foo(1,{\"-a\"})", 0, A ("-a"), 1, "a:", F); T ("foo(2,{\"-a\",\"x\"})", 0, A ("-a", "x"), 1, "a:", F); T ("foo(1,{\"-ay\"})", 0, A ("-ay"), 1, "a:", F); T ("foo(1,{\"-axyz\"})", 0, A ("-axyz"), 1, "a:", F); T ("foo(1,{\"--a\"})", 0, A ("--a"), 1, "|-a:", F); T ("ERR(1,{\"--ab\"})", 0, A ("--ab"), 2, "- |-a:", E, F); // exercise the processing of two optional command line options T ("foo(2,{\"-a\",\"-b\"});" "bar(1,{\"-b\"})", 0, A ("-a", "-b"), 2, "a: b", F, B); T ("foo(3,{\"-a\",\"x\",\"-b\"});" "bar(1,{\"-b\"})", 0, A ("-a", "x", "-b"), 2, "a: b", F, B); // exercise optional restricted numeric argument T ("foo(2,{\"-n\",\"0\"})", 0, A ("-n", "0"), 1, "n:0", F); T ("foo(2,{\"-n\",\"+1\"})", 0, A ("-n", "+1"), 1, "n:1", F); T ("foo(2,{\"-n\",\"+2\"})", 0, A ("-n", "+2"), 1, "n:+2", F); T ("foo(2,{\"-n\",\"\\-2\"})", 0, A ("-n", "\\-2"), 1, "n:-3", F); T ("foo(2,{\"-n\",\"\\-0\"})", 0, A ("-n", "\\-0"), 1, "n:-3-0", F); } /**************************************************************************/ static void test_required_argument () { // exercise the processing of an option with a required argument // the equals sign missing T ("ERR(1,{\"--a\"})", 0, A ("--a"), 2, "- |-a=", E, F); // required argument empty T ("foo(1,{\"--a=\"})", 0, A ("--a="), 1, "|-a=", F); // required argument contains funky characters T ("foo(1,{\"--a=1\"})", 0, A ("--a=1"), 1, "|-a=", F); T ("foo(1,{\"--b=1-\"})", 0, A ("--b=1-"), 1, "|-b=", F); T ("foo(1,{\"--c=-2\"})", 0, A ("--c=-2"), 1, "|-c=", F); T ("foo(1,{\"--d=1-2\"})", 0, A ("--d=1-2"), 1, "|-d=", F); T ("foo(1,{\"--e=-1=2\"})", 0, A ("--e=-1=2"), 1, "|-e=", F); T ("foo(1,{\"--f=-1=-2\"})", 0, A ("--f=-1=-2"), 1, "|-f=", F); T ("foo(1,{\"--g=2,3\"})", 0, A ("--g=2,3"), 1, "|-g=", F); T ("foo(1,{\"--h=3:4\"})", 0, A ("--h=3:4"), 1, "|-h=", F); T ("foo(1,{\"--i=\"j\"\"})", 0, A ("--i=\"j\""), 1, "|-i=", F); // exercise restricted numeric argument T ("foo(1,{\"--a=1\"})", 0, A ("--a=1"), 1, "|-a=0", F); T ("foo(1,{\"--a=1\"})", 0, A ("--a=1"), 1, "|-a=1", F); T ("foo(1,{\"--a=2\"})", 0, A ("--a=2"), 1, "|-a=2", F); T ("foo(1,{\"--a=3\"})", 0, A ("--a=3"), 1, "|-a=3-4", F); T ("foo(1,{\"--a=5\"})", 0, A ("--a=5"), 1, "|-a=4-5", F); T ("", 1, A ("--a=1"), 1, "|-a=2", F); T ("", 1, A ("--a=2"), 1, "|-a=0-1", F); T ("", 1, A ("--a=-1"), 1, "|-a=1-2", F); T ("", 1, A ("--a=+123"), 1, "|-a=+2-3", F); } /**************************************************************************/ static void test_repeated_options () { // exercise repeated options // only the first occurrence of each command line option // causes an invocation of the callback, all subsequent // ones will be ignored by default T ("foo(2,{\"-a\",\"-a\"})", 0, A ("-a", "-a"), 1, "a", F); // unlimited number of invocations T ("foo(2,{\"-a\",\"-a\"});" "foo(1,{\"-a\"})", 0, A ("-a", "-a"), 1, "a@*", F); // no invocation (option is disabled) T ("", 0, A ("-a"), 1, "a@0", F); T ("", 0, A ("-a", "-a"), 1, "a@0", F); T ("bar(1,{\"-b\"})", 0, A ("-a", "-a", "-b"), 2, "a@0 b", F, B); T ("bar(2,{\"-b\",\"-a\"})", 0, A ("-a", "-b", "-a"), 2, "a@0 b", F, B); T ("bar(3,{\"-b\",\"-a\",\"-b\"})", 0, A ("-b", "-a", "-b"), 2, "b a@0", B, F); T ("bar(4,{\"-b\",\"-a\",\"-b\",\"-a\"})", 0, A ("-b", "-a", "-b", "-a"), 2, "b a@0", B, F); // at most one invocation (default) T ("foo(2,{\"-a\",\"-a\"})", 0, A ("-a", "-a"), 1, "a@1", F); T ("foo(2,{\"-a\",\"-a\"})", 0, A ("-a", "-a"), 1, "a@1", F); // at most two invocations T ("foo(2,{\"-a\",\"-a\"});" "foo(1,{\"-a\"})", 0, A ("-a", "-a"), 1, "a@2", F); T ("foo(3,{\"-a\",\"-a\",\"-a\"});" "foo(2,{\"-a\",\"-a\"})", 0, A ("-a", "-a", "-a"), 1, "a@2", F); // inverted option (callback invoked iff option is not specified) T ("", 0, A ("-i"), 1, "i!", F); T ("foo(0,{})", 0, A (""), 1, "i!", F); T ("", 0, A ("--j"), 1, "i|-j!", F); T ("foo(1,{\"-k\"});" "foo(0,{})", 0, A ("-k"), 2, "k l!", F, F); } /**************************************************************************/ int main () { // +--------- expected result string (formatted by callbacks) // | +----- expected value returned from rw_runopts() // | | +-- second argument to rw_runopts() (argv) // | | | // | | | +---------- expected rw_setopts() result // | | | | +------- rw_setopts() first argument // | | | | | +-- rw_setopts() callbacks... // | | | | | | // V V V V V V T ("", 0, A (""), 0, "", 0); T ("", 0, A ("a"), 0, "", 0); T ("", 0, A ("a", "b"), 0, "", 0); T ("", 0, A ("a", "b"), 0, "", 0); T ("", 0, A (""), 1, "f", F); T ("", 0, A ("a"), 1, "f", F); T ("", 0, A ("a", "b"), 1, "f", F); T ("", 0, A ("a", "b"), 1, "f", F); T ("", 0, A ("a", "f"), 1, "f", F); T ("", 0, A ("f", "f"), 1, "f", F); // exercise short and/or long options T ("foo(1,{\"-a\"})", 0, A ("-a"), 1, "a", F); T ("foo(1,{\"--a\"})", 0, A ("--a"), 1, "|-a", F); T ("foo(1,{\"-a\"})", 0, A ("-a"), 1, "a|-a", F); T ("foo(1,{\"--a\"})", 0, A ("--a"), 1, "a|-a", F); // exercise the handling of unknown options test_unknown_options (); // exercise the handling of options with a counter // instead of a callback handler test_counted_options (); // exercise the handling of options with an optional argument test_optional_argument (); // exercise the handling of tristate options test_tristate (); // exercise the handling of options with a required argument test_required_argument (); // exercise the handling of repeated occurrences of the same option test_repeated_options (); // exercise callback errors retvals [0] = 1; T ("foo(2,{\"-a\",\"-b\"})", retvals [0], A ("-a", "-b"), 2, "a b", F, B); retvals [0] = 0; retvals [1] = 2; T ("foo(3,{\"-a\",\"-b\",\"-c\"});" "bar(2,{\"-b\",\"-c\"})", retvals [1], A ("-a", "-b", "-c"), 3, "a b c", F, B, E); retvals [1] = 0; return exit_status; }