aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--libsimple-arg.c507
-rw-r--r--libsimple-arg.h89
-rw-r--r--man0/libsimple-arg.h.054
-rw-r--r--man3/libsimple_memalign.313
-rw-r--r--man3/libsimple_pvalloc.313
-rw-r--r--man3/libsimple_valloc.313
-rw-r--r--test.h4
8 files changed, 608 insertions, 87 deletions
diff --git a/Makefile b/Makefile
index dbd993c..ec24fef 100644
--- a/Makefile
+++ b/Makefile
@@ -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.
diff --git a/test.h b/test.h
index 29e6f13..fe229ef 100644
--- a/test.h
+++ b/test.h
@@ -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)); \