From: Pádraig Brady
Date: Sun, 30 Jan 2022 16:50:27 +0000 (+0000)
Subject: argmatch: add variants that only match full argument
X-Git-Tag: v1.0~2365
X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=6ef3d783333346333f35bb181ba90f5bc46c0b29;p=gnulib.git
argmatch: add variants that only match full argument
* lib/argmatch.h (argmatch_exact, [X]ARGMATCH_EXACT): New interfaces
that don't allow abbreviations.
* lib/argmatch.c (argmatch_exact): Likewise.
(__xargmatch_internal): Add a bool parameter to disable abbreviations.
* tests/test-argmatch.c: Add tests.
---
diff --git a/ChangeLog b/ChangeLog
index fedc7dc777..a202950bd9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+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 allow abbreviations.
+ * lib/argmatch.c (argmatch_exact): Likewise.
+ (__xargmatch_internal): Add a bool parameter to disable abbreviations.
+ * tests/test-argmatch.c: Add tests.
+
2022-01-30 Bruno Haible
tests: Fix interpretation of setupterm's return code.
diff --git a/lib/argmatch.c b/lib/argmatch.c
index 9e3232f947..2a28900a4e 100644
--- a/lib/argmatch.c
+++ b/lib/argmatch.c
@@ -120,6 +120,21 @@ 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))
+ 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.
@@ -174,9 +189,16 @@ ptrdiff_t
__xargmatch_internal (const char *context,
const char *arg, const char *const *arglist,
const void *vallist, size_t valsize,
- argmatch_exit_fn exit_fn)
+ argmatch_exit_fn exit_fn,
+ bool allow_abbreviation)
{
- ptrdiff_t res = argmatch (arg, arglist, vallist, valsize);
+ ptrdiff_t res;
+
+ if (allow_abbreviation)
+ res = argmatch (arg, arglist, vallist, valsize);
+ else
+ res = argmatch_exact (arg, arglist);
+
if (res >= 0)
/* Success. */
return res;
diff --git a/lib/argmatch.h b/lib/argmatch.h
index a2364b5a2e..52f2bb727b 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)'. */
@@ -83,13 +89,14 @@ void argmatch_valid (char const *const *arglist,
-/* Same as argmatch, but upon failure, report an explanation of the
- failure, and exit using the function EXIT_FN. */
+/* Like argmatch/argmatch_exact, but upon failure, report an explanation
+ of the failure, and exit using the function EXIT_FN. */
ptrdiff_t __xargmatch_internal (char const *context,
char const *arg, char const *const *arglist,
void const *vallist, size_t valsize,
- argmatch_exit_fn exit_fn);
+ argmatch_exit_fn exit_fn,
+ bool allow_abbreviation);
/* Programmer friendly interface to __xargmatch_internal. */
@@ -97,7 +104,15 @@ ptrdiff_t __xargmatch_internal (char const *context,
((Vallist) [__xargmatch_internal (Context, Arg, Arglist, \
(void const *) (Vallist), \
sizeof *(Vallist), \
- argmatch_die)])
+ argmatch_die, \
+ true)])
+
+# define XARGMATCH_EXACT(Context, Arg, Arglist, Vallist) \
+ ((Vallist) [__xargmatch_internal (Context, Arg, Arglist, \
+ (void const *) (Vallist), \
+ sizeof *(Vallist), \
+ argmatch_die, \
+ false)])
/* Convert a value into a corresponding argument. */
diff --git a/tests/test-argmatch.c b/tests/test-argmatch.c
index 8345150002..b05e431266 100644
--- a/tests/test-argmatch.c
+++ b/tests/test-argmatch.c
@@ -125,38 +125,63 @@ main (int argc, char *argv[])
} \
} while (0)
+#define CHECK_EXACT(Input, Output) \
+ do { \
+ ASSERT (ARGMATCH_EXACT (Input, backup_args) == Output); \
+ } while (0)
+
/* Not found. */
CHECK ("klingon", -1);
+ CHECK_EXACT ("klingon", -1);
/* Exact match. */
CHECK ("none", 1);
+ CHECK_EXACT ("none", 1);
CHECK ("nil", 7);
+ CHECK_EXACT ("nil", 7);
/* Too long. */
CHECK ("nilpotent", -1);
+ CHECK_EXACT ("nilpotent", -1);
/* Abbreviated. */
CHECK ("simpl", 3);
+ CHECK_EXACT ("simpl", -1);
CHECK ("simp", 3);
+ CHECK_EXACT ("simp", -1);
CHECK ("sim", 3);
+ CHECK_EXACT ("sim", -1);
/* Exact match and abbreviated. */
CHECK ("numbered", 9);
+ CHECK_EXACT ("numbered", 9);
CHECK ("numbere", -2);
+ CHECK_EXACT ("numbere", -1);
CHECK ("number", -2);
+ CHECK_EXACT ("number", -1);
CHECK ("numbe", -2);
+ CHECK_EXACT ("numbe", -1);
CHECK ("numb", -2);
+ CHECK_EXACT ("numb", -1);
CHECK ("num", -2);
+ CHECK_EXACT ("num", -1);
CHECK ("nu", -2);
+ CHECK_EXACT ("nu", -1);
CHECK ("n", -2);
+ CHECK_EXACT ("n", -1);
/* Ambiguous abbreviated. */
CHECK ("ne", -2);
+ CHECK_EXACT ("ne", -1);
/* Ambiguous abbreviated, but same value ("single" and "simple"). */
CHECK ("si", 3);
+ CHECK_EXACT ("si", -1);
CHECK ("s", 3);
+ CHECK_EXACT ("s", -1);
+
#undef CHECK
+#undef CHECK_EXACT
argmatch_backup_usage (stdout);