]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cfgparse: add cfg_find_best_match() to suggest an existing word
authorWilly Tarreau <w@1wt.eu>
Fri, 12 Mar 2021 08:08:04 +0000 (09:08 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 12 Mar 2021 13:13:21 +0000 (14:13 +0100)
Instead of just reporting "unknown keyword", let's provide a function which
will look through a list of registered keywords for a similar-looking word
to the one that wasn't matched. This will help callers suggest correct
spelling. Also, given that a large part of the config parser still relies
on a long chain of strcmp(), we'll need to be able to pass extra candidates.
Thus the function supports an optional extra list for this purpose.

include/haproxy/cfgparse.h
src/cfgparse.c

index 62973d81807d4821c39fe60193ba99a717bd8027..54bfa2a4c1521044efe6aace81a411fe1399381f 100644 (file)
@@ -113,6 +113,7 @@ int alertif_too_many_args(int maxarg, const char *file, int linenum, char **args
 int parse_process_number(const char *arg, unsigned long *proc, int max, int *autoinc, char **err);
 unsigned long parse_cpu_set(const char **args, unsigned long *cpu_set, char **err);
 void free_email_alert(struct proxy *p);
+const char *cfg_find_best_match(const char *word, const struct list *list, int section, const char **extra);
 
 /*
  * Sends a warning if proxy <proxy> does not have at least one of the
index 85995a5d1995bae4a02dee664f50fd95168c73ee..9c8efa2f6cd6f46c0fd38ab1d8be061a3e2408d9 100644 (file)
@@ -332,6 +332,52 @@ int warnif_cond_conflicts(const struct acl_cond *cond, unsigned int where, const
        return ERR_WARN;
 }
 
+/* try to find in <list> the word that looks closest to <word> by counting
+ * transitions between letters, digits and other characters. Will return the
+ * best matching word if found, otherwise NULL. 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 *cfg_find_best_match(const char *word, const struct list *list, int section, const char **extra)
+{
+       uint8_t word_sig[1024]; // 0..25=letter, 26=digit, 27=other, 28=begin, 29=end
+       uint8_t list_sig[1024];
+       const struct cfg_kw_list *kwl;
+       int index;
+       const char *best_ptr = NULL;
+       int dist, best_dist = INT_MAX;
+
+       make_word_fingerprint(word_sig, word);
+       list_for_each_entry(kwl, list, list) {
+               for (index = 0; kwl->kw[index].kw != NULL; index++) {
+                       if (kwl->kw[index].section != section)
+                               continue;
+
+                       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_ptr = kwl->kw[index].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_ptr = *extra;
+               }
+               extra++;
+       }
+
+       if (best_dist > 2 * strlen(word) || (best_ptr && best_dist > 2 * strlen(best_ptr)))
+               best_ptr = NULL;
+       return best_ptr;
+}
+
+
 /* Parse a string representing a process number or a set of processes. It must
  * be "all", "odd", "even", a number between 1 and <max> or a range with
  * two such numbers delimited by a dash ('-'). On success, it returns