Hi Bruno, > Le 27 avr. 2019 à 19:56, Bruno Haible <br...@clisp.org> a écrit : > > Hi Akim, > >> Because that's not what argmatch provides. You seem to be referring to >> a fully blown feature, and support for internationalization I guess. > > And support for help2man should not be forgotten either.
Sure. >> I'm just exploiting the unique prefix feature to shoehorn the >> documentation in there. > > I would find it better to go with a more featureful facility, then > (among getopt, argmatch, argp, AutoOpts [1], etc.) - or invent a new one. Is this what you have in mind? It's in the test because it's simpler to prototype there. I should probably make the argmatch_group private and provide pseudo constructors to be more robust to adding new members if needed in the future. Of course the construction would be runtime, but I suppose it will not be costly enough to be a problem. Most existing functions should probably be rewritten on top of argmatch_group, with backward compatibility of course. I'd be happy to check the output of argmatch_usage, but I don't think we have the equivalent of string streams in gnulib, do we? I did not try to depend on $COLUMNS, because it is not used so far in gnulib. commit 7fc2a29e4d82c7bf7882421e65af6224bfc30188 Author: Akim Demaille <akim.demai...@gmail.com> Date: Tue Apr 30 08:01:14 2019 +0200 WIP: argmatch: provide support for documentation diff --git a/tests/test-argmatch.c b/tests/test-argmatch.c index 9335adf55..99666a12c 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,105 @@ static const enum backup_type backup_vals[] = numbered_backups, numbered_backups, numbered_backups }; +static const char *const backup_docs[] = +{ + N_("never make backups (even if --backup is given)"), + N_("make numbered backups"), + N_("numbered if numbered backups exist, simple otherwise"), + N_("always make simple backups"), + NULL +}; + +static const enum backup_type backup_doc_vals[] = +{ + no_backups, + simple_backups, + numbered_existing_backups, + numbered_backups +}; + +typedef struct argmatch_group +{ + /* Printed before the usage message. */ + const char *doc_pre; + /* Printed after the usage message. */ + const char *doc_post; + /* Size of the values (in bytes). */ + size_t val_size; + + /* The documentation of each documented value. + This dictates the order in which values are documented. + docs[i] documents doc_vals[i]. */ + const char *const *docs; + /* Values that we document. */ + const void *doc_vals; + + /* Arguments denoting a value. */ + const char *const *args; + /* vals[i] is the value for args[i]. */ + const void *vals; +} argmatch_group; + +argmatch_group 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, + sizeof *backup_vals, + backup_docs, + backup_doc_vals, + backup_args, + backup_vals +}; + +void +argmatch_usage (FILE *out, const argmatch_group *g) +{ + /* 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]; ++i) + { + int col = 0; + bool first = true; + for (int j = 0; g->args[j]; ++j) + if (! memcmp ((const char *)g->doc_vals + i * g->val_size, + (const char *)g->vals + j * g->val_size, + g->val_size)) + { + if (!first + && screen_width < col + 2 + strlen (g->args[j])) + { + 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]); + } + /* 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])); + } + if (g->doc_post) + fprintf (out, "%s\n", _(g->doc_post)); +} + int main (int argc, char *argv[]) { @@ -90,9 +195,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 (stdout, &backup_group); + return 0; }