Add a function that finds the longest string from a string_list that
is a prefix of a given string.

Signed-off-by: Michael Haggerty <mhag...@alum.mit.edu>
---
 Documentation/technical/api-string-list.txt |  8 ++++++++
 string-list.c                               | 20 +++++++++++++++++++
 string-list.h                               |  8 ++++++++
 t/t0063-string-list.sh                      | 30 +++++++++++++++++++++++++++++
 test-string-list.c                          | 20 +++++++++++++++++++
 5 files changed, 86 insertions(+)

diff --git a/Documentation/technical/api-string-list.txt 
b/Documentation/technical/api-string-list.txt
index 0f8b7ce..32b35d9 100644
--- a/Documentation/technical/api-string-list.txt
+++ b/Documentation/technical/api-string-list.txt
@@ -75,6 +75,14 @@ Functions
        to be deleted.  Preserve the order of the items that are
        retained.
 
+`string_list_longest_prefix`::
+
+       Return the longest string within a string_list that is a
+       prefix (in the sense of prefixcmp()) of the specified string,
+       or NULL if no such prefix exists.  This function does not
+       require the string_list to be sorted (it does a linear
+       search).
+
 `print_string_list`::
 
        Dump a string_list to stdout, useful mainly for debugging purposes. It
diff --git a/string-list.c b/string-list.c
index decfa74..c54b816 100644
--- a/string-list.c
+++ b/string-list.c
@@ -136,6 +136,26 @@ void filter_string_list(struct string_list *list, int 
free_util,
        list->nr = dst;
 }
 
+char *string_list_longest_prefix(const struct string_list *prefixes,
+                                const char *string)
+{
+       int i, max_len = -1;
+       char *retval = NULL;
+
+       for (i = 0; i < prefixes->nr; i++) {
+               char *prefix = prefixes->items[i].string;
+               if (!prefixcmp(string, prefix)) {
+                       int len = strlen(prefix);
+                       if (len > max_len) {
+                               retval = prefix;
+                               max_len = len;
+                       }
+               }
+       }
+
+       return retval;
+}
+
 void string_list_clear(struct string_list *list, int free_util)
 {
        if (list->items) {
diff --git a/string-list.h b/string-list.h
index 3a6a6dc..5efd07b 100644
--- a/string-list.h
+++ b/string-list.h
@@ -38,6 +38,14 @@ int for_each_string_list(struct string_list *list,
 void filter_string_list(struct string_list *list, int free_util,
                        string_list_each_func_t want, void *cb_data);
 
+/*
+ * Return the longest string in prefixes that is a prefix (in the
+ * sense of prefixcmp()) of string, or NULL if no such prefix exists.
+ * This function does not require the string_list to be sorted (it
+ * does a linear search).
+ */
+char *string_list_longest_prefix(const struct string_list *prefixes, const 
char *string);
+
 
 /* Use these functions only on sorted lists: */
 int string_list_has_string(const struct string_list *list, const char *string);
diff --git a/t/t0063-string-list.sh b/t/t0063-string-list.sh
index dbfc05e..41c8826 100755
--- a/t/t0063-string-list.sh
+++ b/t/t0063-string-list.sh
@@ -17,6 +17,14 @@ test_split () {
        "
 }
 
+test_longest_prefix () {
+       test "$(test-string-list longest_prefix "$1" "$2")" = "$3"
+}
+
+test_no_longest_prefix () {
+       test_must_fail test-string-list longest_prefix "$1" "$2"
+}
+
 test_split "foo:bar:baz" ":" "-1" <<EOF
 3
 [0]: "foo"
@@ -88,4 +96,26 @@ test_expect_success "test remove_duplicates" '
        test a:b:c = "$(test-string-list remove_duplicates a:a:a:b:b:b:c:c:c)"
 '
 
+test_expect_success "test longest_prefix" '
+       test_no_longest_prefix - '' &&
+       test_no_longest_prefix - x &&
+       test_longest_prefix "" x "" &&
+       test_longest_prefix x x x &&
+       test_longest_prefix "" foo "" &&
+       test_longest_prefix : foo "" &&
+       test_longest_prefix f foo f &&
+       test_longest_prefix foo foobar foo &&
+       test_longest_prefix foo foo foo &&
+       test_no_longest_prefix bar foo &&
+       test_no_longest_prefix bar:bar foo &&
+       test_no_longest_prefix foobar foo &&
+       test_longest_prefix foo:bar foo foo &&
+       test_longest_prefix foo:bar bar bar &&
+       test_longest_prefix foo::bar foo foo &&
+       test_longest_prefix foo:foobar foo foo &&
+       test_longest_prefix foobar:foo foo foo &&
+       test_longest_prefix foo: bar "" &&
+       test_longest_prefix :foo bar ""
+'
+
 test_done
diff --git a/test-string-list.c b/test-string-list.c
index 2d6eda7..5e9631f 100644
--- a/test-string-list.c
+++ b/test-string-list.c
@@ -97,6 +97,26 @@ int main(int argc, char **argv)
                return 0;
        }
 
+       if (argc == 4 && !strcmp(argv[1], "longest_prefix")) {
+               /* arguments: <colon-separated-prefixes>|- <string> */
+               struct string_list prefixes = STRING_LIST_INIT_DUP;
+               int retval;
+               const char *prefix_string = argv[2];
+               const char *string = argv[3];
+               const char *match;
+
+               parse_string_list(&prefixes, prefix_string);
+               match = string_list_longest_prefix(&prefixes, string);
+               if (match) {
+                       printf("%s\n", match);
+                       retval = 0;
+               }
+               else
+                       retval = 1;
+               string_list_clear(&prefixes, 0);
+               return retval;
+       }
+
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
-- 
1.7.11.3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to