]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: actions: add a function to suggest an action ressembling a given word
authorWilly Tarreau <w@1wt.eu>
Fri, 12 Mar 2021 10:59:24 +0000 (11:59 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 12 Mar 2021 13:13:21 +0000 (14:13 +0100)
action_suggest() will return a pointer to an action whose keyword more or
less ressembles the passed argument. It also accepts to be more tolerant
against prefixes (since actions taking arguments are handled as prefixes).
This will be used to suggest approaching words.

include/haproxy/action.h
src/action.c

index 7338a75e1ad533ab61d5ad95d7b9311c0e8fb191..a4bec01eb6e69804170df72bda5eac7f71b9a45f 100644 (file)
@@ -29,6 +29,7 @@
 
 int act_resolution_cb(struct resolv_requester *requester, struct dns_counters *counters);
 int act_resolution_error_cb(struct resolv_requester *requester, int error_code);
+const char *action_suggest(const char *word, const struct list *keywords, const char **extra);
 
 static inline struct action_kw *action_lookup(struct list *keywords, const char *kw)
 {
index 8292fe90cc8094bbf2150137c69941da0a939365..c81737642187bca2ba5b5544b647ae5cc405742d 100644 (file)
@@ -206,3 +206,56 @@ int cfg_parse_rule_set_timeout(const char **args, int idx, int *out_timeout,
 
        return 0;
 }
+
+/* tries to find in list <keywords> a similar looking action as the one in
+ * <word>, and returns it otherwise NULL. <word> may be NULL or empty. An
+ * optional array of extra words to compare may be passed in <extra>, but it
+ * must then be terminated by a NULL entry. If unused it may be NULL.
+ */
+const char *action_suggest(const char *word, const struct list *keywords, const char **extra)
+{
+       uint8_t word_sig[1024];
+       uint8_t list_sig[1024];
+       const struct action_kw_list *kwl;
+       const struct action_kw *best_kw = NULL;
+       const char *best_ptr = NULL;
+       int dist, best_dist = INT_MAX;
+       int index;
+
+       if (!word || !*word)
+               return NULL;
+
+       make_word_fingerprint(word_sig, word);
+       list_for_each_entry(kwl, keywords, list) {
+               for (index = 0; kwl->kw[index].kw != NULL; index++) {
+                       make_word_fingerprint(list_sig, kwl->kw[index].kw);
+                       dist = word_fingerprint_distance(word_sig, list_sig);
+                       if (dist < best_dist) {
+                               best_dist = dist;
+                               best_kw   = &kwl->kw[index];
+                               best_ptr  = best_kw->kw;
+                       }
+               }
+       }
+
+       while (extra && *extra) {
+               make_word_fingerprint(list_sig, *extra);
+               dist = word_fingerprint_distance(word_sig, list_sig);
+               if (dist < best_dist) {
+                       best_dist = dist;
+                       best_kw   = NULL;
+                       best_ptr  = *extra;
+               }
+               extra++;
+       }
+
+       /* eliminate too different ones, with more tolerance for prefixes
+        * when they're known to exist (not from extra list).
+        */
+       if (best_ptr &&
+           (best_dist > (2 + (best_kw && best_kw->match_pfx)) * strlen(word) ||
+            best_dist > (2 + (best_kw && best_kw->match_pfx)) * strlen(best_ptr)))
+               best_ptr = NULL;
+
+       return best_ptr;
+}