[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: argmatch: accept perfect matches in documented arglists
From: |
Akim Demaille |
Subject: |
Re: argmatch: accept perfect matches in documented arglists |
Date: |
Sun, 19 May 2019 17:02:24 +0200 |
Hey Bruno,
> Le 19 mai 2019 à 14:14, Akim Demaille <address@hidden> a écrit :
>
>> Le 19 mai 2019 à 14:01, Bruno Haible <address@hidden> a écrit :
>
>> So I would prefer a macro with one argument, the type of the first field.
>
> That sounds good.
Well, it is still quite messy. I had hope to keep the implementation in
argmatch.c, but there are too many problems with tracking the offset of the
different members of the structure. Eventually, I went for something much
simpler, much safer, and easier to maintain.
What do you think of something like this?
commit 4cca4c589eaf17756a779ab91776bc68315edf4e
Author: Akim Demaille <address@hidden>
Date: Tue Apr 30 08:01:14 2019 +0200
WIP: argmatch: provide support for documentation
diff --git a/lib/argmatch.h b/lib/argmatch.h
index 50de57f29..5607def49 100644
--- a/lib/argmatch.h
+++ b/lib/argmatch.h
@@ -23,6 +23,7 @@
# define ARGMATCH_H_ 1
# include <stddef.h>
+# include <stdio.h>
# include "verify.h"
@@ -104,6 +105,89 @@ char const *argmatch_to_argument (void const *value,
argmatch_to_argument (Value, Arglist, \
(void const *) (Vallist), sizeof *(Vallist))
+/* A type that groups together all the feature of an argmatch group. */
+# define ARGMATCH_DEFINE_GROUP(Name, Type) \
+ typedef Type argmatch_##Name##_type; \
+ \
+ typedef enum \
+ { \
+ size = sizeof (argmatch_##Name##_type) \
+ } argmatch_##Name##_size; \
+ \
+ typedef struct \
+ { \
+ /* Value that we document. */ \
+ const argmatch_##Name##_type val; \
+ /* The documentation of each documented value. \
+ This dictates the order in which values are documented. \
+ docs[i] documents doc_vals[i]. */ \
+ const char const *doc; \
+ } argmatch_##Name##_doc; \
+ \
+ typedef struct \
+ { \
+ /* Arguments denoting a value. */ \
+ const char const *arg; \
+ /* vals[i] is the value for args[i]. */ \
+ const argmatch_##Name##_type val; \
+ } argmatch_##Name##_arg; \
+ \
+ typedef struct \
+ { \
+ /* Printed before the usage message. */ \
+ const char *doc_pre; \
+ /* Printed after the usage message. */ \
+ const char *doc_post; \
+ \
+ const argmatch_##Name##_doc* docs; \
+ const argmatch_##Name##_arg* args; \
+ } argmatch_##Name##_group_type; \
+ \
+ static inline void \
+ argmatch_usage (const argmatch_##Name##_group_type *g, FILE *out) \
+ { \
+ /* Width of the screen. Help2man does not seem to support \
+ arguments on several lines, so in that case pretend a very \
+ large width. */ \
+ const int screen_width = getenv ("HELP2MAN") ? INT_MAX : 80; \
+ if (g->doc_pre) \
+ fprintf (out, "%s\n", _(g->doc_pre)); \
+ for (int i = 0; g->docs[i].doc; ++i) \
+ { \
+ int col = 0; \
+ bool first = true; \
+ for (int j = 0; g->args[j].arg; ++j) \
+ if (! memcmp (&g->docs[i].val, &g->args[j].val, size)) \
+ { \
+ if (!first \
+ && screen_width < col + 2 + strlen (g->args[j].arg)) \
+ { \
+ fprintf (out, ",\n"); \
+ col = 0; \
+ first = true; \
+ } \
+ if (first) \
+ { \
+ col += fprintf (out, " "); \
+ first = false; \
+ } \
+ else \
+ col += fprintf (out, ","); \
+ col += fprintf (out, " %s", g->args[j].arg); \
+ } \
+ /* The doc. Must be on column 20 separated by at least two \
+ spaces. */ \
+ if (20 < col + 2) \
+ { \
+ fprintf (out, "\n"); \
+ col = 0; \
+ } \
+ fprintf (out, "%*s%s\n", 20 - col, "", _(g->docs[i].doc)); \
+ } \
+ if (g->doc_post) \
+ fprintf (out, "%s\n", _(g->doc_post)); \
+ }
+
#ifdef __cplusplus
}
#endif
diff --git a/tests/test-argmatch.c b/tests/test-argmatch.c
index 9335adf55..de28dd1e2 100644
--- a/tests/test-argmatch.c
+++ b/tests/test-argmatch.c
@@ -21,10 +21,16 @@
#include "argmatch.h"
+#include <gettext.h>
+#include <stdbool.h>
#include <stdlib.h>
+#include <string.h> /* memcmp */
#include "macros.h"
+#define _(Msgid) gettext (Msgid)
+#define N_(Msgid) (Msgid)
+
/* Some packages define ARGMATCH_DIE and ARGMATCH_DIE_DECL in <config.h>, and
thus must link with a definition of that function. Provide it here. */
#ifdef ARGMATCH_DIE_DECL
@@ -59,6 +65,45 @@ static const enum backup_type backup_vals[] =
numbered_backups, numbered_backups, numbered_backups
};
+ARGMATCH_DEFINE_GROUP(backup, enum backup_type);
+
+static const argmatch_backup_doc argmatch_backup_docs[] =
+{
+ { no_backups, N_("never make backups (even if --backup is
given)") },
+ { simple_backups, N_("make numbered backups") },
+ { numbered_existing_backups, N_("numbered if numbered backups exist, simple
otherwise") },
+ { numbered_backups, N_("always make simple backups") },
+ { no_backups, NULL }
+};
+
+static const argmatch_backup_arg argmatch_backup_args[] =
+{
+ { "no", no_backups },
+ { "none", no_backups },
+ { "off", no_backups },
+ { "simple", simple_backups },
+ { "never", simple_backups },
+ { "single", simple_backups },
+ { "existing", numbered_existing_backups },
+ { "nil", numbered_existing_backups },
+ { "numbered-existing", numbered_existing_backups },
+ { "numbered", numbered_backups },
+ { "t", numbered_backups },
+ { "newstyle", numbered_backups },
+ { NULL, no_backups }
+};
+
+argmatch_backup_group_type argmatch_backup_group =
+{
+ N_("\
+The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.\n\
+The version control method may be selected via the --backup option or
through\n\
+the VERSION_CONTROL environment variable. Here are the values:\n"),
+ NULL,
+ argmatch_backup_docs,
+ argmatch_backup_args
+};
+
int
main (int argc, char *argv[])
{
@@ -90,9 +135,11 @@ main (int argc, char *argv[])
/* Ambiguous abbreviated. */
ASSERT (ARGMATCH ("ne", backup_args, backup_vals) == -2);
- /* Ambiguous abbreviated, but same value. */
+ /* Ambiguous abbreviated, but same value ("single" and "simple"). */
ASSERT (ARGMATCH ("si", backup_args, backup_vals) == 3);
ASSERT (ARGMATCH ("s", backup_args, backup_vals) == 3);
+ argmatch_usage (&argmatch_backup_group, stdout);
+
return 0;
}
When run, it gives:
> $ /tmp/gnutest/gltests/test-argmatch
> The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.
> The version control method may be selected via the --backup option or through
> the VERSION_CONTROL environment variable. Here are the values:
>
> no, none, off never make backups (even if --backup is given)
> simple, never, single
> make numbered backups
> existing, nil, numbered-existing
> numbered if numbered backups exist, simple otherwise
> numbered, t, newstyle
> always make simple backups
which is what help2man expects.
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/02
- Re: argmatch: accept perfect matches in documented arglists, Bruno Haible, 2019/05/05
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Bruno Haible, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Bruno Haible, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists,
Akim Demaille <=
- Re: argmatch: accept perfect matches in documented arglists, Bruno Haible, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Paul Eggert, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/19
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/21
- Re: argmatch: accept perfect matches in documented arglists, Paul Eggert, 2019/05/21
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/22
- Re: argmatch: accept perfect matches in documented arglists, Bruno Haible, 2019/05/22
- Re: argmatch: accept perfect matches in documented arglists, Akim Demaille, 2019/05/25