+#define ARGPAR_REALLOC(_ptr, _type, _nmemb) \
+ ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type)))
+
+#define ARGPAR_CALLOC(_type, _nmemb) \
+ ((_type *) calloc((_nmemb), sizeof(_type)))
+
+#define ARGPAR_ZALLOC(_type) ARGPAR_CALLOC(_type, 1)
+
+#define ARGPAR_ASSERT(_cond) assert(_cond)
+
+#ifdef __MINGW_PRINTF_FORMAT
+# define ARGPAR_PRINTF_FORMAT __MINGW_PRINTF_FORMAT
+#else
+# define ARGPAR_PRINTF_FORMAT printf
+#endif
+
+/*
+ * An argpar iterator.
+ *
+ * Such a structure contains the state of an iterator between
+ * calls to argpar_iter_parse_next().
+ */
+struct argpar_iter {
+ /*
+ * Data provided by the user to argpar_iter_create(); immutable
+ * afterwards.
+ */
+ unsigned int argc;
+ const char * const *argv;
+ const struct argpar_opt_descr *descrs;
+
+ /*
+ * Index of the argument to process in the next
+ * argpar_iter_parse_next() call.
+ */
+ unsigned int i;
+
+ /* Counter of non-option arguments */
+ int non_opt_index;
+
+ /*
+ * Current character of the current short option group: if it's
+ * not `NULL`, the parser is in within a short option group,
+ * therefore it must resume there in the next
+ * argpar_iter_parse_next() call.
+ */
+ const char *short_opt_ch;
+};
+
+/* Base parsing item */
+struct argpar_item {
+ enum argpar_item_type type;
+};
+
+/* Option parsing item */
+struct argpar_item_opt {
+ struct argpar_item base;
+
+ /* Corresponding descriptor */
+ const struct argpar_opt_descr *descr;
+
+ /* Argument, or `NULL` if none; owned by this */
+ char *arg;
+};
+
+/* Non-option parsing item */
+struct argpar_item_non_opt {
+ struct argpar_item base;
+
+ /*
+ * Complete argument, pointing to one of the entries of the
+ * original arguments (`argv`).
+ */
+ const char *arg;
+
+ /*
+ * Index of this argument amongst all original arguments
+ * (`argv`).
+ */
+ unsigned int orig_index;
+
+ /* Index of this argument amongst other non-option arguments */
+ unsigned int non_opt_index;
+};
+
+static __attribute__((format(ARGPAR_PRINTF_FORMAT, 1, 0)))
+char *argpar_vasprintf(const char * const fmt, va_list args)
+{
+ int len1, len2;
+ char *str;
+ va_list args2;
+
+ va_copy(args2, args);
+ len1 = vsnprintf(NULL, 0, fmt, args);
+ if (len1 < 0) {
+ str = NULL;
+ goto end;
+ }
+
+ str = malloc(len1 + 1);
+ if (!str) {
+ goto end;
+ }
+
+ len2 = vsnprintf(str, len1 + 1, fmt, args2);
+ ARGPAR_ASSERT(len1 == len2);
+
+end:
+ va_end(args2);
+ return str;
+}
+
+
+static __attribute__((format(ARGPAR_PRINTF_FORMAT, 1, 2)))
+char *argpar_asprintf(const char * const fmt, ...)
+{
+ va_list args;
+ char *str;
+
+ va_start(args, fmt);
+ str = argpar_vasprintf(fmt, args);
+ va_end(args);
+ return str;
+}
+
+static __attribute__((format(ARGPAR_PRINTF_FORMAT, 2, 3)))
+bool append_string_printf(char ** const str, const char *fmt, ...)
+{
+ char *new_str = NULL;
+ char *addendum;
+ bool success;
+ va_list args;
+
+ ARGPAR_ASSERT(str);
+ va_start(args, fmt);
+ addendum = argpar_vasprintf(fmt, args);
+ va_end(args);
+
+ if (!addendum) {
+ success = false;
+ goto end;
+ }
+
+ new_str = argpar_asprintf("%s%s", *str ? *str : "", addendum);
+ if (!new_str) {
+ success = false;
+ goto end;
+ }
+
+ free(*str);
+ *str = new_str;
+ success = true;
+
+end:
+ free(addendum);
+ return success;
+}
+
+ARGPAR_HIDDEN
+enum argpar_item_type argpar_item_type(const struct argpar_item * const item)
+{
+ ARGPAR_ASSERT(item);
+ return item->type;
+}
+
+ARGPAR_HIDDEN
+const struct argpar_opt_descr *argpar_item_opt_descr(
+ const struct argpar_item * const item)
+{
+ ARGPAR_ASSERT(item);
+ ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT);
+ return ((const struct argpar_item_opt *) item)->descr;
+}
+
+ARGPAR_HIDDEN
+const char *argpar_item_opt_arg(const struct argpar_item * const item)
+{
+ ARGPAR_ASSERT(item);
+ ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT);
+ return ((const struct argpar_item_opt *) item)->arg;
+}
+
+ARGPAR_HIDDEN
+const char *argpar_item_non_opt_arg(const struct argpar_item * const item)
+{
+ ARGPAR_ASSERT(item);
+ ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
+ return ((const struct argpar_item_non_opt *) item)->arg;
+}
+
+ARGPAR_HIDDEN
+unsigned int argpar_item_non_opt_orig_index(
+ const struct argpar_item * const item)
+{
+ ARGPAR_ASSERT(item);
+ ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
+ return ((const struct argpar_item_non_opt *) item)->orig_index;
+}
+
+ARGPAR_HIDDEN
+unsigned int argpar_item_non_opt_non_opt_index(
+ const struct argpar_item * const item)
+{
+ ARGPAR_ASSERT(item);
+ ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
+ return ((const struct argpar_item_non_opt *) item)->non_opt_index;
+}
+
+ARGPAR_HIDDEN
+void argpar_item_destroy(const struct argpar_item * const item)