[PATCH] Add ST_MaxMatch function

Introduce a new string tree function, ST_MaxMatch. This will be our main
helper function for tab completion.

Given a partial string, this function will search a string tree for strings
who's prefix matches the partial string. It will then return a string which is
the maximum common prefix of the matching strings (i.e. can be longer than the
given partial string.

For now, if the match is unique, the returned string has a space appended. I'm
not sure if I want to keep it like that as it feels like a bit of a hack. It
will do for now.

diff -urN b/common/shell.c head/common/shell.c
--- b/common/shell.c	2006-02-18 12:06:50.000000000 +1030
+++ head/common/shell.c	2006-02-15 14:47:30.000000000 +1030
@@ -157,6 +157,68 @@
     return ret;
 }
 
+/* ST_MaxMatch helper */
+static int
+ST_node_match(struct rb_node *n, const char *str, int min_match, int max_match)
+{
+    struct rb_string_node *sn;
+
+    if (n) {
+	max_match = ST_node_match(n->rb_left, str, min_match, max_match);
+
+	/* How much does this node match */
+	sn = rb_entry(n, struct rb_string_node, node);
+	while (max_match > min_match) {
+	    if (!strncasecmp(str, sn->string, max_match))
+		break;
+	    max_match--;
+	}
+
+	max_match = ST_node_match(n->rb_right, str, min_match, max_match);
+    }
+
+    return max_match;
+}
+
+/*
+ * Given a prefix, return the maximum common prefix of all other strings in
+ * the tree which match the given prefix.
+ */
+char *
+ST_MaxMatch(struct rb_string_root *root, const char *pfx)
+{
+    int max_match, min_match, match;
+    struct rb_node *n;
+    struct rb_string_node *sn;
+    char *result = NULL;
+
+    /* Can't be more than the shortest string */
+    max_match = root->minlen;
+    min_match = strlen(pfx);
+
+    n = root->root.rb_node;
+    sn = rb_entry(n, struct rb_string_node, node);
+
+    if (root->entries == 1) {
+	match = strlen(sn->string);
+	result = Z_Malloc(match + 2);
+	if (result) {
+	    strncpy(result, sn->string, match);
+	    result[match] = ' ';
+	    result[match + 1] = 0;
+	}
+    } else if (root->entries > 1) {
+	match = ST_node_match(n, sn->string, min_match, max_match);
+	result = Z_Malloc(match + 1);
+	if (result) {
+	    strncpy(result, sn->string, match);
+	    result[match] = 0;
+	}
+    }
+
+    return result;
+}
+
 const char **completions_list = NULL;
 static int num_completions = 0;
 
diff -urN b/include/shell.h head/include/shell.h
--- b/include/shell.h	2006-02-18 12:06:50.000000000 +1030
+++ head/include/shell.h	2006-02-15 12:22:41.000000000 +1030
@@ -50,6 +50,7 @@
 qboolean ST_Insert(struct rb_string_root *root, struct rb_string_node *node);
 qboolean ST_InsertAlloc(struct rb_string_root *root, const char *s,
 			struct rb_string_node *n);
+char *ST_MaxMatch(struct rb_string_root *root, const char *pfx);
 
 /*
  * Set up some basic completion helpers
