Re: [PATCH] argmatch: add variants that only match full argument

2022-01-30 Thread Pádraig Brady

On 30/01/2022 18:58, Bruno Haible wrote:

Pádraig Brady wrote:

* lib/argmatch.h (argmatch_exact, [X]ARGMATCH_EXACT): New interfaces
that don't support abbreviations.
* lib/argmatch.c (argmatch_exact, __xargmatch_exact_internal): Likewise.
* tests/test-argmatch.c: Add tests.


The code looks correct. But I see some code duplication:
__xargmatch_exact_internal and __xargmatch_internal are very similar.
Given that both of these functions are only invoked through macros, how
about merging them into a single function? Namely, by adding an argument
of type 'bool exactp'.

Bruno


Good call.
I pushed with that adjustment.

Thanks for the review.
Pádraig



Re: [PATCH] argmatch: add variants that only match full argument

2022-01-30 Thread Bruno Haible
Pádraig Brady wrote:
> * lib/argmatch.h (argmatch_exact, [X]ARGMATCH_EXACT): New interfaces
> that don't support abbreviations.
> * lib/argmatch.c (argmatch_exact, __xargmatch_exact_internal): Likewise.
> * tests/test-argmatch.c: Add tests.

The code looks correct. But I see some code duplication:
__xargmatch_exact_internal and __xargmatch_internal are very similar.
Given that both of these functions are only invoked through macros, how
about merging them into a single function? Namely, by adding an argument
of type 'bool exactp'.

Bruno






argmatch: add variants that only match full argument

2022-01-30 Thread Pádraig Brady
I would like a more constrained argument matching
to improve forward compatibility and robustness.

For example I would like `cksum -a sha3` to _not_
be equivalent to `cksum -a sha386`, so that a user
specifying `-a sha3` on an older cksum would not be surprised.
Also argmatch() is used when parsing tags from lines like:
SHA3 (filename) = abcedf
so it's more robust that older cksum instances to fail
earlier in the parsing process, when parsing output from
possible future cksum implementations that might support SHA3.





[PATCH] argmatch: add variants that only match full argument

2022-01-30 Thread Pádraig Brady
* lib/argmatch.h (argmatch_exact, [X]ARGMATCH_EXACT): New interfaces
that don't support abbreviations.
* lib/argmatch.c (argmatch_exact, __xargmatch_exact_internal): Likewise.
* tests/test-argmatch.c: Add tests.
---
 ChangeLog |  8 
 lib/argmatch.c| 37 +
 lib/argmatch.h| 17 +
 tests/test-argmatch.c | 23 +++
 4 files changed, 85 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 4c9a1e7989..e51a00190a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2022-01-30  Pádraig Brady  
+
+   argmatch: add variants that only match full argument
+   * lib/argmatch.h (argmatch_exact, [X]ARGMATCH_EXACT): New interfaces
+   that don't support abbreviations.
+   * lib/argmatch.c (argmatch_exact, __xargmatch_exact_internal): Likewise.
+   * tests/test-argmatch.c: Add tests.
+
 2022-01-30  Bruno Haible  
 
terminfo: Add tests.
diff --git a/lib/argmatch.c b/lib/argmatch.c
index 9e3232f947..71059e8f7e 100644
--- a/lib/argmatch.c
+++ b/lib/argmatch.c
@@ -120,6 +120,24 @@ argmatch (const char *arg, const char *const *arglist,
 return matchind;
 }
 
+ptrdiff_t
+argmatch_exact (const char *arg, const char *const *arglist)
+{
+  size_t i;
+
+  /* Test elements for exact match.  */
+  for (i = 0; arglist[i]; i++)
+{
+  if (!strcmp (arglist[i], arg))
+{
+  /* Exact match found.  */
+  return i;
+}
+}
+
+  return -1;
+}
+
 /* Error reporting for argmatch.
CONTEXT is a description of the type of entity that was being matched.
VALUE is the invalid value that was given.
@@ -189,6 +207,25 @@ __xargmatch_internal (const char *context,
   return -1; /* To please the compilers. */
 }
 
+ptrdiff_t
+__xargmatch_exact_internal (const char *context,
+const char *arg, const char *const *arglist,
+const void *vallist, size_t valsize,
+argmatch_exit_fn exit_fn)
+{
+  ptrdiff_t res = argmatch_exact (arg, arglist);
+  if (res >= 0)
+/* Success. */
+return res;
+
+  /* We failed.  Explain why. */
+  argmatch_invalid (context, arg, res);
+  argmatch_valid (arglist, vallist, valsize);
+  (*exit_fn) ();
+
+  return -1; /* To please the compilers. */
+}
+
 /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
return the first corresponding argument in ARGLIST */
 const char *
diff --git a/lib/argmatch.h b/lib/argmatch.h
index a2364b5a2e..c6d24d981c 100644
--- a/lib/argmatch.h
+++ b/lib/argmatch.h
@@ -52,9 +52,15 @@ extern "C" {
 ptrdiff_t argmatch (char const *arg, char const *const *arglist,
 void const *vallist, size_t valsize) _GL_ATTRIBUTE_PURE;
 
+ptrdiff_t argmatch_exact (char const *arg, char const *const *arglist)
+  _GL_ATTRIBUTE_PURE;
+
 # define ARGMATCH(Arg, Arglist, Vallist) \
   argmatch (Arg, Arglist, (void const *) (Vallist), sizeof *(Vallist))
 
+# define ARGMATCH_EXACT(Arg, Arglist) \
+  argmatch_exact (Arg, Arglist)
+
 /* xargmatch calls this function when it fails.  This function should not
return.  By default, this is a function that calls ARGMATCH_DIE which
in turn defaults to 'exit (exit_failure)'.  */
@@ -91,6 +97,11 @@ ptrdiff_t __xargmatch_internal (char const *context,
 void const *vallist, size_t valsize,
 argmatch_exit_fn exit_fn);
 
+ptrdiff_t __xargmatch_exact_internal (char const *context,
+char const *arg, char const *const *arglist,
+void const *vallist, size_t valsize,
+argmatch_exit_fn exit_fn);
+
 /* Programmer friendly interface to __xargmatch_internal. */
 
 # define XARGMATCH(Context, Arg, Arglist, Vallist)  \
@@ -99,6 +110,12 @@ ptrdiff_t __xargmatch_internal (char const *context,
 sizeof *(Vallist),  \
 argmatch_die)])
 
+# define XARGMATCH_EXACT(Context, Arg, Arglist, Vallist)\
+  ((Vallist) [__xargmatch_exact_internal (Context, Arg, Arglist,\
+(void const *) (Vallist),   \
+sizeof *(Vallist),  \
+argmatch_die)])
+
 /* Convert a value into a corresponding argument. */
 
 char const *argmatch_to_argument (void const *value,
diff --git a/tests/test-argmatch.c b/tests/test-argmatch.c
index 8345150002..46a7f07153 100644
--- a/tests/test-argmatch.c
+++ b/tests/test-argmatch.c
@@ -125,37 +125,60 @@ main (int argc, char *argv[])
   } \
   } while (0)
 
+#define CHECK_EXACT(Input, Output)  \
+  do {  \
+ASSERT (ARGMATCH