瀏覽代碼

Change handling of ambiguous matches (issue https://trac.osgeo.org/grass/ticket/2409)

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@63744 15284696-431f-4ddb-bdfa-cd5b030d7da7
Glynn Clements 10 年之前
父節點
當前提交
841f04f87c
共有 1 個文件被更改,包括 70 次插入32 次删除
  1. 70 32
      lib/gis/parser.c

+ 70 - 32
lib/gis/parser.c

@@ -94,6 +94,8 @@ enum opt_error {
 
 #define KEYLENGTH 64
 
+#define MAX_MATCHES 50
+
 /* initialize the global struct */
 struct state state;
 struct state *st = &state;
@@ -941,11 +943,11 @@ void set_option(const char *string)
 {
     struct Option *at_opt = NULL;
     struct Option *opt = NULL;
-    int found;
-    int prefix;
     size_t key_len;
     char the_key[KEYLENGTH];
     char *ptr, *err;
+    struct Option *matches[MAX_MATCHES];
+    int found = 0;
 
     err = NULL;
 
@@ -955,37 +957,58 @@ void set_option(const char *string)
     string++;
 
     /* Find option with best keyword match */
-    found = 0;
-    prefix = 0;
     key_len = strlen(the_key);
     for (at_opt = &st->first_option; at_opt; at_opt = at_opt->next_opt) {
 	if (!at_opt->key)
 	    continue;
 
         if (strcmp(the_key, at_opt->key) == 0) {
-	    opt = at_opt;
+	    matches[0] = at_opt;
 	    found = 1;
 	    break; 
 	}
 
-        if (strncmp(the_key, at_opt->key, key_len) == 0) {
-	    opt = at_opt;
-	    found++;
-	    prefix++;
-	}
-	else if (match_option(the_key, at_opt->key)) {
-	    if (!found)
-		opt = at_opt;
-	    found++;
+        if (strncmp(the_key, at_opt->key, key_len) == 0 ||
+	    match_option(the_key, at_opt->key)) {
+	    if (found >= MAX_MATCHES)
+		G_fatal_error("too many matches (limit %d)", MAX_MATCHES);
+	    matches[found++] = at_opt;
 	}
     }
 
-    if (found > 1 && prefix > 1) {
-	G_asprintf(&err, _("%s: Sorry, <%s=> is ambiguous"), G_program_name(), the_key);
-	append_error(err);
-	return;
+    if (found > 1) {
+	int shortest = 0;
+	int length = strlen(matches[0]->key);
+	int prefix = 1;
+	int i;
+	for (i = 1; i < found; i++) {
+	    int len = strlen(matches[i]->key);
+	    if (len < length) {
+		length = len;
+		shortest = i;
+	    }
+	}
+	for (i = 0; prefix && i < found; i++)
+	    if (strncmp(matches[i]->key, matches[shortest]->key, length) != 0)
+		prefix = 0;
+	if (prefix) {
+	    matches[0] = matches[shortest];
+	    found = 1;
+	}
+	else {
+	    G_asprintf(&err, _("%s: Sorry, <%s=> is ambiguous"), G_program_name(), the_key);
+	    append_error(err);
+	    for (i = 0; i < found; i++) {
+		G_asprintf(&err, _("Option <%s=> matches"), matches[i]->key);
+		append_error(err);
+	    }
+	    return;
+	}
     }
 
+    if (found)
+	opt = matches[0];
+
     /* First, check if key has been renamed in GRASS 7 */
     if (found == 0) {
         const char *renamed_key = NULL;
@@ -1214,7 +1237,7 @@ int check_string(const char *ans, const char **opts, int *result)
 {
     int len = strlen(ans);
     int found = 0;
-    int prefix = 0;
+    int matches[MAX_MATCHES];
     int i;
 
     if (!opts)
@@ -1223,26 +1246,41 @@ int check_string(const char *ans, const char **opts, int *result)
     for (i = 0; opts[i]; i++) {
 	if (strcmp(ans, opts[i]) == 0)
 	    return 0;
-	if (strncmp(ans, opts[i], len) == 0) {
-	    *result = i;
-	    found++;
-	    prefix++;
+	if (strncmp(ans, opts[i], len) == 0 || match_option(ans, opts[i])) {
+	    if (found >= MAX_MATCHES)
+		G_fatal_error("too many matches (limit %d)", MAX_MATCHES);
+	    matches[found++] = i;
+	}
+    }
+
+    if (found > 1) {
+	int shortest = 0;
+	int length = strlen(opts[matches[0]]);
+	int prefix = 1;
+	int i;
+	for (i = 1; i < found; i++) {
+	    int len = strlen(opts[matches[i]]);
+	    if (len < length) {
+		length = len;
+		shortest = i;
+	    }
 	}
-	else if (match_option(ans, opts[i])) {
-	    if (!found)
-		*result = i;
-	    found++;
+	for (i = 0; prefix && i < found; i++)
+	    if (strncmp(opts[matches[i]], opts[matches[shortest]], length) != 0)
+		prefix = 0;
+	if (prefix) {
+	    matches[0] = matches[shortest];
+	    found = 1;
 	}
     }
 
+    if (found == 1)
+	*result = matches[0];
+
     switch (found) {
     case 0: return OUT_OF_RANGE;
     case 1: return REPLACED;
-    default:
-	switch (prefix) {
-	case 1: return REPLACED;
-	default: return AMBIGUOUS;
-	}
+    default: return AMBIGUOUS;
     }
 }