Welcome to little lamb

Code » limb » commit c2431d7

Add byte_get_match{,_full}()

author Olivier Brunel
2023-03-24 13:31:21 UTC
committer Olivier Brunel
2023-03-26 14:03:02 UTC
parent 4ec170d24cca368e9e2380ed68a6a6c8e714c7cf

Add byte_get_match{,_full}()

To find the (partial) match of a string in an array. That is, either an
exact match or the given string is the beginning of one of the string in
the array.

Exact match or no other possible match is a success, no matches or more
than one an error.

doc/byte_get_match_full.3.md +72 -0
doc/bytestr.h.0.md +6 -0
include/limb/bytestr.h +4 -0
meta/libs/limb +2 -0
src/byte_get_match.c +10 -0
src/byte_get_match_full.c +32 -0

diff --git a/doc/byte_get_match_full.3.md b/doc/byte_get_match_full.3.md
new file mode 100644
index 0000000..7db9f43
--- /dev/null
+++ b/doc/byte_get_match_full.3.md
@@ -0,0 +1,72 @@
+% limb manual
+% byte_get_match_full(3)
+
+# NAME
+
+byte\_get\_match\_full, byte\_get\_match - find the (partial) match of a given
+string in an array
+
+# SYNOPSIS
+
+    #include <limb/bytestr.h>
+
+```pre hl
+int byte_get_match_full(int *<em>first</em>, const char *<em>str</em>, size_t <em>slen</em>,
+                        const void *<em>list</em>, size_t <em>offset</em>, size_t <em>llen</em>)
+int byte_get_match(int *<em>first</em>, const char *<em>str</em>, size_t <em>slen</em>, const char **<em>list</em>)
+```
+
+# DESCRIPTION
+
+The `byte_get_match_full`() function looks inside the array `list` for a string
+matching `str` of length `slen`.
+
+Each element of the array `list` must by `llen` bytes long, and must contain,
+at byte `offset` (starting from 0), a pointer to a NUL-terminated string to
+check against.
+
+An element is said to match if its `slen` first bytes are the same as those from
+`str`. In case of an /exact match/, that is the element's NUL-terminated string
+is of length `slen`, the search ends and the function returns.
+
+If the element's string is longer however, the search continues through the
+remaining elements in `list`. No other elements shall match for a success.
+Otherwise -1 is returned, and if `first` is not NULL the value it points to is
+set to the index of the first-matching element.
+
+The search goes on until an exact match is found, or an element is found with a
+string pointer that is NULL.
+
+! INFO:
+! - Elements in `list` need not to be ordered.
+! - `first` is not changed if there are no matches. To distinguish between no
+!   matches and more than one, it should be initialized to e.g. -1 prior to
+!   calling `byte_get_match_full`().
+
+The `byte_get_match`() function is similar, but simply takes `list` as a NULL
+terminated array of NUL-terminated string pointers.
+
+# RETURN VALUE
+
+These functions return the index of the matching element in `list`, or -1 if
+either no element matched `str`, or more than one did. In the later case, if
+`first` was not NULL the value it points to is set to the index of the
+first-matching element.
+
+# EXAMPLE
+
+Usually you'll probably want to use `byte_get_match`() with a NULL terminated
+array of strings.
+
+An example of use for `byte_get_match_full`() would be when the strings are
+members of a structure, e.g:
+
+```c
+struct user {
+  int id;
+  const char *name;
+} users[];
+
+int r = byte_get_match_full(&first, name, strlen(name), users,
+                            offsetof(struct user, name), sizeof(*users));
+```
diff --git a/doc/bytestr.h.0.md b/doc/bytestr.h.0.md
index ddb7b2f..ff36a60 100644
--- a/doc/bytestr.h.0.md
+++ b/doc/bytestr.h.0.md
@@ -21,5 +21,11 @@ This header defines functions to work with byte arrays and/or strings.
 
 The following functions are defined :
 
+: [byte_get_match_full](3)
+:: Find the (partial) match of a given string in an array
+
+: [byte_get_match](3)
+:: Find the (partial) match of a given string in an array of strings
+
 : [byte_str](3)
 :: To locate a substring within a string
diff --git a/include/limb/bytestr.h b/include/limb/bytestr.h
index 3ab983b..bc59b28 100644
--- a/include/limb/bytestr.h
+++ b/include/limb/bytestr.h
@@ -8,4 +8,8 @@
 
 extern size_t byte_str(const char *haystack, size_t hlen, const char *needle, size_t nlen);
 
+extern int byte_get_match_full(int *first, const char *str, size_t slen,
+                               const void *list_, size_t offset, size_t llen);
+extern int byte_get_match(int *first, const char *str, size_t slen, const char **list);
+
 #endif /* LIMB_BYTESTR_H */
diff --git a/meta/libs/limb b/meta/libs/limb
index ec05868..6929e1a 100644
--- a/meta/libs/limb
+++ b/meta/libs/limb
@@ -21,6 +21,8 @@ obj/sacoloff.o
 obj/saoff2ptr.o
 obj/sacolptr.o
 # bytestr.h
+obj/byte_get_match_full.o
+obj/byte_get_match.o
 obj/byte_str.o
 # buffer.h
 obj/buffer_putescall.o
diff --git a/src/byte_get_match.c b/src/byte_get_match.c
new file mode 100644
index 0000000..3c3209c
--- /dev/null
+++ b/src/byte_get_match.c
@@ -0,0 +1,10 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/bytestr.h"
+
+int
+byte_get_match(int *first, const char *str, size_t slen, const char **list)
+{
+    return byte_get_match_full(first, str, slen, list, 0, sizeof(*list));
+}
diff --git a/src/byte_get_match_full.c b/src/byte_get_match_full.c
new file mode 100644
index 0000000..049c5eb
--- /dev/null
+++ b/src/byte_get_match_full.c
@@ -0,0 +1,32 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/bytestr.h"
+
+int
+byte_get_match_full(int *first, const char *str, size_t slen,
+                    const void *list_, size_t offset, size_t llen)
+{
+    const char *list = list_;
+    int i, m;
+
+    for (i = 0, m = -1; ; list += llen, ++i) {
+        const char *el = * (const char **) (list + offset);
+        if (!el) break;
+        /* str matches an element */
+        if (!strncmp(el, str, slen)) {
+            /* exact match? */
+            if (strlen(el) == slen) return i;
+
+            if (m < 0) {
+                /* first partial match */
+                if (first) *first = i;
+                m = i;
+            } else {
+                /* more than one match */
+                return -1;
+            }
+        }
+    }
+    return m;
+}