diff options
author | Mattias Andrée <maandree@kth.se> | 2018-11-14 23:07:52 +0100 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2018-11-14 23:07:52 +0100 |
commit | 548a358df5654e653329f2c9033ef94aeaa143ad (patch) | |
tree | 5ae1a435ee78a55ea68c25315044a1e052b62328 | |
parent | Document libsimple-arg.h and add support optional arguments on long options and add KEEP_DASHDASH to ARGBEGIN3 (now named ARGBEGIN4) (diff) | |
download | libsimple-548a358df5654e653329f2c9033ef94aeaa143ad.tar.gz libsimple-548a358df5654e653329f2c9033ef94aeaa143ad.tar.bz2 libsimple-548a358df5654e653329f2c9033ef94aeaa143ad.tar.xz |
Some fixes to libsimple-arg.h, test everything except long arguments, and fix some man pages
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | libsimple-arg.c | 507 | ||||
-rw-r--r-- | libsimple-arg.h | 89 | ||||
-rw-r--r-- | man0/libsimple-arg.h.0 | 54 | ||||
-rw-r--r-- | man3/libsimple_memalign.3 | 13 | ||||
-rw-r--r-- | man3/libsimple_pvalloc.3 | 13 | ||||
-rw-r--r-- | man3/libsimple_valloc.3 | 13 | ||||
-rw-r--r-- | test.h | 4 |
8 files changed, 608 insertions, 87 deletions
@@ -128,7 +128,7 @@ OBJ =\ vweprintf.o\ libsimple.o -TESTS = $(OBJ:.o=.test) +TESTS = $(OBJ:.o=.test) libsimple-arg.test all: libsimple.a $(TESTS) $(OBJ): $(@:.o=.c) $(HDR) diff --git a/libsimple-arg.c b/libsimple-arg.c new file mode 100644 index 0000000..fcebb42 --- /dev/null +++ b/libsimple-arg.c @@ -0,0 +1,507 @@ +/* See LICENSE file for copyright and license details. */ +#include <setjmp.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "test.h" +#include "libsimple-arg.h" + + +#define PARSER_BEGIN\ + int old_argc = argc;\ + char **old_argv = argv;\ + { + + +#define PARSER_END\ + ;}\ + assert(argv0 == old_argv[0]);\ + assert(argv == &old_argv[old_argc - argc]);\ + return argc + + +#define PARSER_END_NO_ARGV0\ + }\ + assert(argv0 == NULL);\ + assert(argv == &old_argv[old_argc - argc]);\ + return argc + + +#define SHORT_WITHOUT_ARG(SHORT_FLAG)\ + do {\ + assert(nparsed < sizeof(parsed) / sizeof(*parsed));\ + assert(FLAG() == (SHORT_FLAG)[1]);\ + parsed[nparsed].short_used = 1;\ + parsed[nparsed].long_used = 0;\ + parsed[nparsed].have_arg = 0;\ + parsed[nparsed].short_flag[0] = (SHORT_FLAG)[0];\ + parsed[nparsed].short_flag[1] = (SHORT_FLAG)[1];\ + parsed[nparsed].short_flag[2] = '\0';\ + parsed[nparsed].long_flag[0] = '\0';\ + parsed[nparsed].argument[0] = '\0';\ + nparsed += 1;\ + } while (0) + + +#define SHORT_WITH_ARG(SHORT_FLAG)\ + do {\ + char *arg__;\ + assert(nparsed < sizeof(parsed) / sizeof(*parsed));\ + assert(FLAG() == (SHORT_FLAG)[1]);\ + parsed[nparsed].short_used = 1;\ + parsed[nparsed].long_used = 0;\ + parsed[nparsed].have_arg = 1;\ + parsed[nparsed].short_flag[0] = (SHORT_FLAG)[0];\ + parsed[nparsed].short_flag[1] = (SHORT_FLAG)[1];\ + parsed[nparsed].short_flag[2] = '\0';\ + parsed[nparsed].long_flag[0] = '\0';\ + assert(strlen(ARG()) < sizeof(parsed[nparsed].argument));\ + assert((arg__ = ARG()));\ + assert(arg__ == ARGNULL());\ + stpcpy(parsed[nparsed].argument, ARG());\ + nparsed += 1;\ + } while (0) + + +#define SHORT_WITH_MISSING_ARG(SHORT_FLAG)\ + do {\ + assert(!ARGNULL());\ + ARG();\ + } while (0) + + +#define SHORT_WITH_ARGHERE(SHORT_FLAG)\ + do {\ + assert(nparsed < sizeof(parsed) / sizeof(*parsed));\ + assert(FLAG() == ARGHERE()[0]);\ + parsed[nparsed].short_used = 1;\ + parsed[nparsed].long_used = 0;\ + parsed[nparsed].have_arg = 1;\ + parsed[nparsed].short_flag[0] = (SHORT_FLAG)[0];\ + parsed[nparsed].short_flag[1] = (SHORT_FLAG)[1];\ + parsed[nparsed].short_flag[2] = '\0';\ + parsed[nparsed].long_flag[0] = '\0';\ + assert(strlen(ARGHERE()) < sizeof(parsed[nparsed].argument));\ + stpcpy(parsed[nparsed].argument, ARGHERE());\ + nparsed += 1;\ + } while (0) + + +#define ASSERT_ENTRY(SHORT_FLAG, LONG_FLAG, ARGUMENT)\ + do {\ + const char *volatile short_flag__ = (SHORT_FLAG);\ + const char *volatile long_flag__ = (LONG_FLAG);\ + const char *volatile argument__ = (ARGUMENT);\ + assert(parsedi < nparsed);\ + assert(parsed[parsedi].short_used == !!short_flag__);\ + if (short_flag__) assert(!strcmp(parsed[parsedi].short_flag, short_flag__));\ + assert(parsed[parsedi].long_used == !!long_flag__);\ + if (long_flag__) assert(!strcmp(parsed[parsedi].long_flag, long_flag__));\ + assert(parsed[parsedi].have_arg == !!argument__);\ + if (argument__) assert(!strcmp(parsed[parsedi].argument, argument__));\ + parsedi += 1;\ + } while (0) + + +#define ASSERT_END()\ + do {\ + assert(parsedi == nparsed);\ + parsedi = 0;\ + } while (0) + + +struct entry { + char short_used; + char long_used; + char have_arg; + char short_flag[3]; + char long_flag[256]; + char argument[256]; +}; + + +static struct entry parsed[100]; +static size_t nparsed = 0; +static size_t parsedi = 0; +static jmp_buf usage_jmp; +extern char *argv0_1; +extern char *argv0_2; +extern char *argv0_3; +extern char *argv0_0; + + +#define usage usage1 +#define argv0 argv0_1 +USAGE("-1"); +#undef usage +#undef argv0 + +#define usage usage2 +#define argv0 argv0_2 +NUSAGE(2, "-2"); +#undef usage +#undef argv0 + +#define usage usage3 +#define argv0 argv0_3 +NUSAGE(3, ""); +#undef usage +#undef argv0 + +#define usage usage0 +#define argv0 argv0_0 +NUSAGE(0, NULL); +#undef usage +#undef argv0 + + +#define apply(...) apply_(__VA_ARGS__, NULL) +static int +apply_(int (*func)(int argc, char *argv[]), ...) +{ + va_list ap; + char **argv, **old_argv; + const char *arg; + size_t argc = 0, i; + int ret; + + va_start(ap, func); + while (va_arg(ap, const char *)) + argc += 1; + va_end(ap); + assert((argv = calloc(argc + 1, sizeof(*argv)))); + assert((old_argv = calloc(argc + 1, sizeof(*argv)))); + va_start(ap, func); + for (i = 0; i < argc; i++) { + assert((arg = va_arg(ap, const char *))); + assert((argv[i] = strdup(arg))); + } + va_end(ap); + memcpy(old_argv, argv, (argc + 1) * sizeof(*argv)); + + if (setjmp(usage_jmp)) { + ret = -1; + goto out; + } + + nparsed = 0; + argv0 = NULL; + ret = func((int)argc, argv); +out: + va_start(ap, func); + for (i = 0; i < argc - (size_t)ret; i++) { + va_arg(ap, const char *); + free(old_argv[i]); + } + for (; i < argc; i++) { + assert(argv[i] == old_argv[i]); + assert(!strcmp(argv[i], va_arg(ap, const char *))); + free(old_argv[i]); + } + va_end(ap); + free(argv); + free(old_argv); + return ret; +} + + +static void +usage(void) +{ + longjmp(usage_jmp, 1); +} + + +static int +parser1(int argc, char *argv[]) +{ + PARSER_BEGIN; + ARGBEGIN { + case 'a': SHORT_WITHOUT_ARG("-a"); break; + case 'b': SHORT_WITHOUT_ARG("-b"); break; + case 'c': SHORT_WITHOUT_ARG("-c"); break; + case 'd': SHORT_WITHOUT_ARG("-d"); break; + case 'e': SHORT_WITHOUT_ARG("-e"); break; + case 'A': SHORT_WITHOUT_ARG("-A"); break; + case 'B': SHORT_WITHOUT_ARG("-B"); break; + case 'C': SHORT_WITHOUT_ARG("-C"); break; + case 'D': SHORT_WITHOUT_ARG("-D"); break; + case 'E': SHORT_WITHOUT_ARG("-E"); break; + case 'x': SHORT_WITH_ARG("-x"); break; + case 'y': SHORT_WITH_ARG("-y"); break; + case 'z': SHORT_WITH_ARG("-z"); break; + case 'X': SHORT_WITH_ARG("-X"); break; + case 'Y': SHORT_WITH_ARG("-Y"); break; + case 'Z': SHORT_WITH_ARG("-Z"); break; + case '-': SHORT_WITHOUT_ARG("--"); break; + case ARGNUM: SHORT_WITH_ARGHERE("-#"); break; + case '@': SHORT_WITH_MISSING_ARG("-@"); break; + default: + usage(); + } ARGEND; + PARSER_END; +} + + +static int +parser2(int argc, char *argv[]) +{ + PARSER_BEGIN; + SUBARGBEGIN { + case 'a': SHORT_WITHOUT_ARG("-a"); break; + case 'b': SHORT_WITHOUT_ARG("-b"); break; + case 'c': SHORT_WITHOUT_ARG("-c"); break; + case 'd': SHORT_WITHOUT_ARG("-d"); break; + case 'e': SHORT_WITHOUT_ARG("-e"); break; + case 'A': SHORT_WITHOUT_ARG("-A"); break; + case 'B': SHORT_WITHOUT_ARG("-B"); break; + case 'C': SHORT_WITHOUT_ARG("-C"); break; + case 'D': SHORT_WITHOUT_ARG("-D"); break; + case 'E': SHORT_WITHOUT_ARG("-E"); break; + case 'x': SHORT_WITH_ARG("-x"); break; + case 'y': SHORT_WITH_ARG("-y"); break; + case 'z': SHORT_WITH_ARG("-z"); break; + case 'X': SHORT_WITH_ARG("-X"); break; + case 'Y': SHORT_WITH_ARG("-Y"); break; + case 'Z': SHORT_WITH_ARG("-Z"); break; + case '-': SHORT_WITHOUT_ARG("--"); break; + case ARGNUM: SHORT_WITH_ARGHERE("-#"); break; + case '@': SHORT_WITH_MISSING_ARG("-@"); break; + default: + usage(); + } ARGEND; + PARSER_END_NO_ARGV0; +} + + +static int +parser3(int argc, char *argv[]) +{ + PARSER_BEGIN; + NOFLAGS(0); + PARSER_END; +} + + +static int +parser4(int argc, char *argv[]) +{ + PARSER_BEGIN; + NOFLAGS(argc); + PARSER_END; +} + + +static int +parser5(int argc, char *argv[]) +{ + PARSER_BEGIN; + ARGBEGIN { + case 'a': SHORT_WITHOUT_ARG("-a"); break; + case 'x': SHORT_WITHOUT_ARG("-x"); break; + case '-': SHORT_WITHOUT_ARG("--"); break; + default: + usage(); + } ARGALT('+') { + case 'a': SHORT_WITHOUT_ARG("+a"); break; + case 'y': SHORT_WITHOUT_ARG("+y"); break; + case '+': SHORT_WITHOUT_ARG("++"); break; + default: + usage(); + } ARGALT('/') { + case 'a': SHORT_WITHOUT_ARG("/a"); break; + case 'z': SHORT_WITHOUT_ARG("/z"); break; + case '/': SHORT_WITHOUT_ARG("//"); break; + default: + usage(); + } ARGALT('x') { + case 'a': SHORT_WITHOUT_ARG("xa"); break; + case 'b': SHORT_WITHOUT_ARG("xb"); break; + case 'x': SHORT_WITHOUT_ARG("xx"); break; + default: + usage(); + } ARGEND; + PARSER_END; +} + + +static int +parser6(int argc, char *argv[]) +{ + PARSER_BEGIN; + ARGBEGIN2(1, 1) { + default: + argv[0] = LFLAG(); + goto stop; + } ARGALT('+') { + case 'a': SHORT_WITHOUT_ARG("+a"); break; + case 'b': SHORT_WITHOUT_ARG("+b"); break; + case 'c': SHORT_WITHOUT_ARG("+c"); break; + case 'd': SHORT_WITHOUT_ARG("+d"); break; + case 'e': SHORT_WITHOUT_ARG("+e"); break; + case 'A': SHORT_WITHOUT_ARG("+A"); break; + case 'B': SHORT_WITHOUT_ARG("+B"); break; + case 'C': SHORT_WITHOUT_ARG("+C"); break; + case 'D': SHORT_WITHOUT_ARG("+D"); break; + case 'E': SHORT_WITHOUT_ARG("+E"); break; + case 'x': SHORT_WITH_ARG("+x"); break; + case 'y': SHORT_WITH_ARG("+y"); break; + case 'z': SHORT_WITH_ARG("+z"); break; + case 'X': SHORT_WITH_ARG("+X"); break; + case 'Y': SHORT_WITH_ARG("+Y"); break; + case 'Z': SHORT_WITH_ARG("+Z"); break; + case '+': SHORT_WITHOUT_ARG("++"); break; + case ARGNUM: SHORT_WITH_ARGHERE("+#"); break; + case '@': SHORT_WITH_MISSING_ARG("+@"); break; + default: + usage(); + } ARGEND; +stop: + PARSER_END; +} + + +int +main(void) +{ + const char *a1; + size_t i; + + assert(apply(parser1) == 0); + ASSERT_END(); + + assert(apply(parser1, "-a") == 0); + ASSERT_END(); + + assert(apply(parser1, "-a", "-a", "-o") == -1); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_END(); + + assert(apply(parser1, "-a", "-a", "-Y") == -1); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_END(); + + for (i = 0; i < 5; i++) { + a1 = ((const char *[]){"--", "z", "-", "", "+a"})[i]; + assert(apply(parser1, "argv[0]", "-abdexhello world", "-x", "hi", "-y", "-Y", a1, "-Z", "z") == 2 + !!i); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_ENTRY("-b", NULL, NULL); + ASSERT_ENTRY("-d", NULL, NULL); + ASSERT_ENTRY("-e", NULL, NULL); + ASSERT_ENTRY("-x", NULL, "hello world"); + ASSERT_ENTRY("-x", NULL, "hi"); + ASSERT_ENTRY("-y", NULL, "-Y"); + ASSERT_END(); + } + + assert(apply(parser1, "", "-a1000", "-200") == 0); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_ENTRY("-#", NULL, "1000"); + ASSERT_ENTRY("-#", NULL, "200"); + ASSERT_END(); + + assert(apply(parser1, "", "-a", "-@") == -1); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_END(); + + assert(apply(parser1, "", "-a-") == -1); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_END(); + + for (i = 0; i < 5; i++) { + a1 = ((const char *[]){"--", "z", "-", "", "+a"})[i]; + assert(apply(parser2, "-abdexhello world", "-x", "hi", "-y", "-Y", a1, "-Z", "z") == 2 + !!i); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_ENTRY("-b", NULL, NULL); + ASSERT_ENTRY("-d", NULL, NULL); + ASSERT_ENTRY("-e", NULL, NULL); + ASSERT_ENTRY("-x", NULL, "hello world"); + ASSERT_ENTRY("-x", NULL, "hi"); + ASSERT_ENTRY("-y", NULL, "-Y"); + ASSERT_END(); + } + + assert(apply(parser3, "x") == 0); ASSERT_END(); + assert(apply(parser3, "y", "z") == 1); ASSERT_END(); + assert(apply(parser3, "x", "z", "-a") == 2); ASSERT_END(); + assert(apply(parser3, "y", "-z", "a") == -1); ASSERT_END(); + assert(apply(parser3, "x", "--", "-a") == 1); ASSERT_END(); + assert(apply(parser3, "", "--") == 0); ASSERT_END(); + assert(apply(parser3, "-", "--x") == -1); ASSERT_END(); + assert(apply(parser3, "", "+") == 1); ASSERT_END(); + assert(apply(parser3, "-", "") == 1); ASSERT_END(); + assert(apply(parser3, "", "-") == 1); ASSERT_END(); + + assert(apply(parser4, "x") == 0); ASSERT_END(); + assert(apply(parser4, "y", "z") == -1); ASSERT_END(); + assert(apply(parser4, "", "z", "-a") == -1); ASSERT_END(); + assert(apply(parser4, "-", "-z", "a") == -1); ASSERT_END(); + assert(apply(parser4, "", "--", "-a") == -1); ASSERT_END(); + assert(apply(parser4, "-", "--") == 0); ASSERT_END(); + assert(apply(parser4, "", "--x") == -1); ASSERT_END(); + assert(apply(parser4, "-", "+") == -1); ASSERT_END(); + assert(apply(parser4, "", "") == -1); ASSERT_END(); + assert(apply(parser4, "-", "-") == -1); ASSERT_END(); + + for (i = 0; i < 4; i++) { + a1 = ((const char *[]){"--", "++", "//", "xx"})[i]; + assert(apply(parser5, "<>", "-a", "+a", "/a", "xa", "-x", "+y", "/z", "xb", a1, "yy") == 1 + !!i); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_ENTRY("+a", NULL, NULL); + ASSERT_ENTRY("/a", NULL, NULL); + ASSERT_ENTRY("xa", NULL, NULL); + ASSERT_ENTRY("-x", NULL, NULL); + ASSERT_ENTRY("+y", NULL, NULL); + ASSERT_ENTRY("/z", NULL, NULL); + ASSERT_ENTRY("xb", NULL, NULL); + ASSERT_END(); + } + + assert(apply(parser5, "<>", "-y") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "-z") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "-b") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "+x") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "+z") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "+b") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "/x") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "/y") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "/b") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "xy") == -1); ASSERT_END(); + assert(apply(parser5, "<>", "xz") == -1); ASSERT_END(); + + for (i = 0; i < 6; i++) { + a1 = ((const char *[]){"++", "z", "+", "", "-a", "--"})[i]; + assert(apply(parser6, "0", "+abdexhello world", "+x", "hi", "+y", "+Y", a1, "+Z", "z") == 3); + ASSERT_ENTRY("+a", NULL, NULL); + ASSERT_ENTRY("+b", NULL, NULL); + ASSERT_ENTRY("+d", NULL, NULL); + ASSERT_ENTRY("+e", NULL, NULL); + ASSERT_ENTRY("+x", NULL, "hello world"); + ASSERT_ENTRY("+x", NULL, "hi"); + ASSERT_ENTRY("+y", NULL, "+Y"); + ASSERT_END(); + } + + argv0_1 = "[1]"; + assert_exit(usage1()); + assert(exit_status == 1); + assert_stderr("usage: [1] -1\n"); + + argv0_2 = "[2]"; + assert_exit(usage2()); + assert_stderr("usage: [2] -2\n"); + assert(exit_status == 2); + + argv0_3 = "[3]"; + assert_exit(usage3()); + assert_stderr("usage: [3]\n"); + assert(exit_status == 3); + + argv0_0 = "[0]"; + assert_exit(usage0()); + assert_stderr("usage: [0]\n"); + assert(exit_status == 0); + + return 0; +} diff --git a/libsimple-arg.h b/libsimple-arg.h index cb32001..0ba316a 100644 --- a/libsimple-arg.h +++ b/libsimple-arg.h @@ -6,8 +6,6 @@ #include <stdlib.h> #include <string.h> -/* TODO add tests */ - /** * The zeroth command line argument, the name of the process, @@ -86,7 +84,7 @@ struct longopt { * usage(); * } ARGEND; */ -#define ARGBEGIN ARGBEGIN4(1, 1, argc, argv) +#define ARGBEGIN ARGBEGIN2(1, 0) /** * `SUBARGBEGIN {} ARGEND;` is similar to @@ -94,26 +92,18 @@ struct longopt { * is not set to `argv[0]`, instead `argv[0]` * is handled like any other element in `argv` */ -#define SUBARGBEGIN ARGBEGIN4(0, 1, argc, argv) +#define SUBARGBEGIN ARGBEGIN2(0, 0) /** * Flexible alternative to `ARGBEGIN` * - * @param WITH_ARGV0 If 0, behave like `SUBARGBEGIN`, - * otherwise, behave like `ARGBEGIN` - * @param KEEP_DASHDASH If and only if 0, "--" is not removed - * `argv` before parsing is stopped when it - * is encountered - * @param argc:int variable The number of elements in `argv`, will be - * update to the number of arguments remaining - * after parsing stopped - * @param argv:char ** variable The command line arguments to parse, - * `argv[argc]` must be `NULL`; will be updated, - * via offseting, to the arguments remaining - * after parsing stopped, `argv[argc]` will - * still be `NULL` + * @param WITH_ARGV0 If 0, behave like `SUBARGBEGIN`, + * otherwise, behave like `ARGBEGIN` + * @param KEEP_DASHDASH If and only if 0, "--" is not removed + * `argv` before parsing is stopped when it + * is encountered */ -#define ARGBEGIN4(WITH_ARGV0, argc, argv)\ +#define ARGBEGIN2(WITH_ARGV0, KEEP_DASHDASH)\ do {\ char flag_, *lflag_, *arg_;\ int brk_ = 0, again_;\ @@ -157,7 +147,7 @@ struct longopt { * @param LONGOPTS:struct longopt * The options, list shall end * with `NULL` as `.long_flag` */ -#define ARGMAPLONG(LONGOPTS)\ +#define ARGMAPLONG(LONGOPTS)/* TODO test */\ for (i_ = 0; (LONGOPTS)[i_].long_flag; i_++) {\ if (TESTLONG((LONGOPTS)[i_].long_flag, (LONGOPTS)[i_].with_arg)) {\ flag_ = (LONGOPTS)[i_].short_flag;\ @@ -214,7 +204,7 @@ struct longopt { switch (flag_) { /** - * Refer to `ARGBEGIN`, `SUBARGBEGIN`, and `ARGBEGIN3` + * Refer to `ARGBEGIN`, `SUBARGBEGIN`, and `ARGBEGIN4` */ #define ARGEND\ }\ @@ -323,33 +313,6 @@ struct longopt { /** - * `NOFLAG(x);` is an optimised shorthand for - * - * ARGBEGIN { - * default: - * usage(); - * } ARGEND; - * - * if (x) - * usage(); - * - * @param ... If non-zero, the `usage` function - * will be called - */ -#define NOFLAGS(...)\ - do {\ - if (*argv)\ - argv0 = *argv++, argc--;\ - if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && !argv[0][2])\ - argv++, argc--;\ - else if (argv[0] && argv[0][0] == '-')\ - usage();\ - if (__VA_ARGS__)\ - usage();\ - } while (0) - - -/** * Test if the argument is a specific long option * * Example: @@ -375,9 +338,9 @@ struct longopt { * @param WARG:int Whether the option takes an argument, * should not have side-effects */ -#define TESTLONG(FLG, WARG)\ +#define TESTLONG(FLG, WARG)/* TODO test */\ ((WARG)\ - ? ((!strncmp(lflag_, (FLG), (n_ = strlen(FLG), n_ -= ((FLG)[n_ - !!n_] == '='))) && lflag_[n_] == '=') \ + ? ((!strncmp(lflag_, (FLG), (n_ = strlen(FLG), n_ -= ((FLG)[n_ - !!n_] == '='))) && lflag_[n_] == '=')\ ? (lflag_[n_] = '\0',\ (arg_ = &lflag_[n_ + 1]),\ (brk_ = 1))\ @@ -393,6 +356,33 @@ struct longopt { /** + * `NOFLAG(x);` is an optimised shorthand for + * + * ARGBEGIN { + * default: + * usage(); + * } ARGEND; + * + * if (x) + * usage(); + * + * @param ... If non-zero, the `usage` function + * will be called + */ +#define NOFLAGS(...)\ + do {\ + if (*argv)\ + argv0 = *argv++, argc--;\ + if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && !argv[0][2])\ + argv++, argc--;\ + else if (argv[0] && argv[0][0] == '-' && argv[0][1])\ + usage();\ + if (__VA_ARGS__)\ + usage();\ + } while (0) + + +/** * Define the function `static void usage(void)` * that prints the error message * "usage: %s %s\n", argv0, SYNOPSIS @@ -408,7 +398,6 @@ struct longopt { #define USAGE(SYNOPSIS)\ NUSAGE(1, SYNOPSIS) - /** * Define the function `static void usage(void)` * that prints the error message diff --git a/man0/libsimple-arg.h.0 b/man0/libsimple-arg.h.0 index 842f816..550eddd 100644 --- a/man0/libsimple-arg.h.0 +++ b/man0/libsimple-arg.h.0 @@ -13,21 +13,21 @@ struct longopt { int with_arg; }; -#define ARGBEGIN ARGBEGIN4(1, 1, argc, argv) -#define SUBARGBEGIN ARGBEGIN4(0, 1, argc, argv) -#define ARGBEGIN4(\fIWITH_ARGV0\fP, \fIKEEP_DASHDASH\fP, \fIargc\fP, \fIargv\fP) /* implementation omitted */ -#define ARGMAPLONG(\fILONGOPTS\fP) /* implementation omitted */ -#define ARGALT(\fISYMBOL\fP) /* implementation omitted */ -#define ARGEND /* implementation omitted */ -#define ARGNUM /* implementation omitted */ -#define FLAG() /* implementation omitted */ -#define LFLAG() /* implementation omitted */ -#define ARG() /* implementation omitted */ -#define ARGHERE() /* implementation omitted */ -#define NOFLAGS(...) /* implementation omitted */ -#define TESTLONG(\fIFLG\fP, \fIWARG\fP) /* implementation omitted */ -#define USAGE(\fISYNOPSIS\fP) /* implementation omitted */ -#define NUSAGE(\fISTATUS\fP, \fISYNOPSIS\fP) /* implementation omitted */ +#define ARGBEGIN ARGBEGIN2(1, 0) +#define SUBARGBEGIN ARGBEGIN2(0, 0) +#define ARGBEGIN2(\fIWITH_ARGV0\fP, \fIKEEP_DASHDASH\fP) /* implementation omitted */ +#define ARGMAPLONG(\fILONGOPTS\fP) /* implementation omitted */ +#define ARGALT(\fISYMBOL\fP) /* implementation omitted */ +#define ARGEND /* implementation omitted */ +#define ARGNUM /* implementation omitted */ +#define FLAG() /* implementation omitted */ +#define LFLAG() /* implementation omitted */ +#define ARG() /* implementation omitted */ +#define ARGHERE() /* implementation omitted */ +#define NOFLAGS(...) /* implementation omitted */ +#define TESTLONG(\fIFLG\fP, \fIWARG\fP) /* implementation omitted */ +#define USAGE(\fISYNOPSIS\fP) /* implementation omitted */ +#define NUSAGE(\fISTATUS\fP, \fISYNOPSIS\fP) /* implementation omitted */ .fi .SH DESCRIPTION The @@ -179,7 +179,7 @@ and are set to only contain the remaining, unparsed, arguments. .PP The -.BR ARGBEGIN4 () +.BR ARGBEGIN2 () macro can be used instead of the .B ARGBEGIN and @@ -214,12 +214,6 @@ is encounted, and it becomes visible to the application code, implement GNU behaviour by running the parsing in a loop and stop when the application code sees .BR -- . -The -.BR ARGBEGIN4 () -also lets the user choose which variables to use as -.I argc -and -.IR argv . .PP If the application should support flags starting with another symbol than a dash @@ -394,18 +388,18 @@ macro shall be used directly in a (or .BR default ) for -.IR ARGBEGIN , -.IR SUBARGBEGIN , +.BR ARGBEGIN , +.BR SUBARGBEGIN , or -.IR ARGBEGIN4 , +.BR ARGBEGIN2 , and not inside a loop or inner .BR switch ), and in the next iteration of the argument parsing loop, the flag will be the short flag consisting of the two characters -.B long_flag[0] +.I long_flag[0] and -.B short_flag +.I short_flag (in that order). Example: .nf @@ -435,13 +429,13 @@ have to map entries, one where ends with .RB ' = ' and -.B with_arg +.I with_arg is non-zero, and one where -.B long_flag +.I long_flag does not end with .RB ' = ' and -.B with_arg +.I with_arg is zero. These .I cannot have the same diff --git a/man3/libsimple_memalign.3 b/man3/libsimple_memalign.3 index 8df0d50..8bf04a1 100644 --- a/man3/libsimple_memalign.3 +++ b/man3/libsimple_memalign.3 @@ -36,7 +36,9 @@ pointer with an alignment of bytes to the allocated memory. The function .BR free (3) shall be called with the returned pointer as -input when the allocated memory is no longer needed. +input when the allocated memory is no longer needed, +but see +.BR NOTES . .PP The .BR libsimple_enmemalign () @@ -144,7 +146,14 @@ None. .SH FUTURE DIRECTIONS None. .SH NOTES -None. +Portable applications shall assume that pointer +returned by the +.BR memalign () +function can be deallocated with the +.BR free (3) +functon, unless the namespaced alias +.BR libsimple_memalign () +is used explicitly. .SH BUGS None. .SH SEE ALSO diff --git a/man3/libsimple_pvalloc.3 b/man3/libsimple_pvalloc.3 index 63473b3..b6cf4c6 100644 --- a/man3/libsimple_pvalloc.3 +++ b/man3/libsimple_pvalloc.3 @@ -36,7 +36,9 @@ alignment of the page size to the allocated memory. The function .BR free (3) shall be called with the returned pointer as -input when the allocated memory is no longer needed. +input when the allocated memory is no longer needed, +but see +.BR NOTES . .PP The .BR libsimple_enpvalloc () @@ -132,6 +134,15 @@ None. .SH FUTURE DIRECTIONS None. .SH NOTES +Portable applications shall assume that pointer +returned by the +.BR pvalloc () +function can be deallocated with the +.BR free (3) +functon, unless the namespaced alias +.BR libsimple_pvalloc () +is used explicitly. +.PP The GNU implementation of .BR pvalloc (3) is \(dqMT-Unsafe init\(dq. diff --git a/man3/libsimple_valloc.3 b/man3/libsimple_valloc.3 index 033e5e9..84cce32 100644 --- a/man3/libsimple_valloc.3 +++ b/man3/libsimple_valloc.3 @@ -35,7 +35,9 @@ pointer with an alignment of the page size to the allocated memory. The function .BR free (3) shall be called with the returned pointer as -input when the allocated memory is no longer needed. +input when the allocated memory is no longer needed, +but see +.BR NOTES . .PP The .BR libsimple_envalloc () @@ -131,6 +133,15 @@ None. .SH FUTURE DIRECTIONS None. .SH NOTES +Portable applications shall assume that pointer +returned by the +.BR valloc () +function can be deallocated with the +.BR free (3) +functon, unless the namespaced alias +.BR libsimple_valloc () +is used explicitly. +.PP The GNU implementation of .BR valloc (3) is \(dqMT-Unsafe init\(dq. @@ -44,11 +44,11 @@ assert_exit((void)(ptr__ = (EXPR)));\ } while (0) -#define assert_stderr(FMT, ...)\ +#define assert_stderr(...)\ do {\ char buf__[1024];\ int len__;\ - len__ = sprintf(buf__, FMT, __VA_ARGS__);\ + len__ = sprintf(buf__, __VA_ARGS__);\ assert(len__ >= 0);\ assert((size_t)len__ == stderr_n);\ assert(!memcmp(buf__, (char **)(void *)(&stderr_buf), stderr_n)); \ |