<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40673 >

The attached patch makes the /help command list all matching
option or command names when the user uses it on an ambiguous
name prefix.

For example, from the server console:
> help t
Help argument 't' is ambiguous.
Possible matches: team take timeoutincrease topology tinyisles 
temperature techlevel techpenalty timeout timeaddenemymove turnblock

This is achieved by augmenting the function match_prefix() to
take an int array that is filled in with the indices of all
of the potential matches. The resulting function is renamed to
match_prefix_full() and a convenience wrapper match_prefix()
is added so that existing code works without modification.

A function cmd_reply_matches() is added to stdinhand.c which
takes the array of indices and constructs a simple reply message
listing the matched names and sends it to the calling user.


-----------------------------------------------------------------------
あいまいさはいとおしい。
 server/stdinhand.c |   46 ++++++++++++++++++++++++++++++++++++++++++++--
 utility/shared.c   |   41 ++++++++++++++++++++++++++++++++++-------
 utility/shared.h   |   10 ++++++++++
 3 files changed, 88 insertions(+), 9 deletions(-)

diff --git a/server/stdinhand.c b/server/stdinhand.c
index af02e70..6930d9c 100644
--- a/server/stdinhand.c
+++ b/server/stdinhand.c
@@ -4120,6 +4120,44 @@ static void show_help_command_list(struct connection *caller,
 }
 
 /**************************************************************************
+  Send a reply to the caller listing the matched names from an ambiguous
+  prefix.
+**************************************************************************/
+static void cmd_reply_matches(enum command_id cmd,
+                              struct connection *caller,
+                              m_pre_accessor_fn_t accessor_fn,
+                              int *matches, int num_matches)
+{
+  char buf[MAX_LEN_MSG];
+  const char *src, *end;
+  char *dest;
+  int i;
+
+  if (accessor_fn == NULL || matches == NULL || num_matches < 1) {
+    return;
+  }
+
+  dest = buf;
+  end = buf + sizeof(buf) - 1;
+
+  for (i = 0; i < num_matches && dest < end; i++) {
+    src = accessor_fn(matches[i]);
+    if (!src) {
+      continue;
+    }
+    if (dest != buf) {
+      *dest++ = ' ';
+    }
+    while (*src != '\0' && dest < end) {
+      *dest++ = *src++;
+    }
+  }
+  *dest = '\0';
+
+  cmd_reply(cmd, caller, C_COMMENT, _("Possible matches: %s"), buf);
+}
+
+/**************************************************************************
   Additional 'help' arguments
 **************************************************************************/
 enum HELP_GENERAL_ARGS { HELP_GENERAL_COMMANDS, HELP_GENERAL_OPTIONS,
@@ -4153,14 +4191,16 @@ static const char *helparg_accessor(int i) {
 **************************************************************************/
 static bool show_help(struct connection *caller, char *arg)
 {
+  int matches[64], num_matches = 0;
   enum m_pre_result match_result;
   int ind;
 
   assert(!may_use_nothing(caller));
     /* no commands means no help, either */
 
-  match_result = match_prefix(helparg_accessor, HELP_ARG_NUM, 0,
-			      mystrncasecmp, NULL, arg, &ind);
+  match_result = match_prefix_full(helparg_accessor, HELP_ARG_NUM, 0,
+                                   mystrncasecmp, NULL, arg, &ind, matches,
+                                   ARRAY_SIZE(matches), &num_matches);
 
   if (match_result==M_PRE_EMPTY) {
     show_help_intro(caller, CMD_HELP);
@@ -4169,6 +4209,8 @@ static bool show_help(struct connection *caller, char *arg)
   if (match_result==M_PRE_AMBIGUOUS) {
     cmd_reply(CMD_HELP, caller, C_FAIL,
 	      _("Help argument '%s' is ambiguous."), arg);
+    cmd_reply_matches(CMD_HELP, caller, helparg_accessor,
+                      matches, num_matches);
     return FALSE;
   }
   if (match_result==M_PRE_FAIL) {
diff --git a/utility/shared.c b/utility/shared.c
index dc29a9e..fdb6ef3 100644
--- a/utility/shared.c
+++ b/utility/shared.c
@@ -1512,20 +1512,41 @@ const char *m_pre_description(enum m_pre_result result)
 }
 
 /***************************************************************************
+  See match_prefix_full().
+***************************************************************************/
+enum m_pre_result match_prefix(m_pre_accessor_fn_t accessor_fn,
+                               size_t n_names,
+                               size_t max_len_name,
+                               m_pre_strncmp_fn_t cmp_fn,
+                               m_strlen_fn_t len_fn,
+                               const char *prefix,
+                               int *ind_result)
+{
+  return match_prefix_full(accessor_fn, n_names, max_len_name, cmp_fn,
+                           len_fn, prefix, ind_result, NULL, 0, NULL);
+}
+
+/***************************************************************************
   Given n names, with maximum length max_len_name, accessed by
   accessor_fn(0) to accessor_fn(n-1), look for matching prefix
   according to given comparison function.
   Returns type of match or fail, and for return <= M_PRE_AMBIGUOUS
   sets *ind_result with matching index (or for ambiguous, first match).
   If max_len_name==0, treat as no maximum.
+  If the int array 'matches' is non-NULL, up to 'max_matches' ambiguous
+  matching names indices will be inserted into it. If 'pnum_matches' is
+  non-NULL, it will be set to the number of indices inserted into 'matches'.
 ***************************************************************************/
-enum m_pre_result match_prefix(m_pre_accessor_fn_t accessor_fn,
-			       size_t n_names,
-			       size_t max_len_name,
-			       m_pre_strncmp_fn_t cmp_fn,
-                               m_strlen_fn_t len_fn,
-			       const char *prefix,
-			       int *ind_result)
+enum m_pre_result match_prefix_full(m_pre_accessor_fn_t accessor_fn,
+                                    size_t n_names,
+                                    size_t max_len_name,
+                                    m_pre_strncmp_fn_t cmp_fn,
+                                    m_strlen_fn_t len_fn,
+                                    const char *prefix,
+                                    int *ind_result,
+                                    int *matches,
+                                    int max_matches,
+                                    int *pnum_matches)
 {
   int i, len, nmatches;
 
@@ -1552,6 +1573,9 @@ enum m_pre_result match_prefix(m_pre_accessor_fn_t accessor_fn,
       if (nmatches==0) {
 	*ind_result = i;	/* first match */
       }
+      if (matches != NULL && nmatches < max_matches) {
+        matches[nmatches] = i;
+      }
       nmatches++;
     }
   }
@@ -1559,6 +1583,9 @@ enum m_pre_result match_prefix(m_pre_accessor_fn_t accessor_fn,
   if (nmatches == 1) {
     return M_PRE_ONLY;
   } else if (nmatches > 1) {
+    if (pnum_matches != NULL) {
+      *pnum_matches = MIN(max_matches, nmatches);
+    }
     return M_PRE_AMBIGUOUS;
   } else {
     return M_PRE_FAIL;
diff --git a/utility/shared.h b/utility/shared.h
index df20992..fbc2d7d 100644
--- a/utility/shared.h
+++ b/utility/shared.h
@@ -235,6 +235,16 @@ enum m_pre_result match_prefix(m_pre_accessor_fn_t accessor_fn,
                                m_strlen_fn_t len_fn,
 			       const char *prefix,
 			       int *ind_result);
+enum m_pre_result match_prefix_full(m_pre_accessor_fn_t accessor_fn,
+                                    size_t n_names,
+                                    size_t max_len_name,
+                                    m_pre_strncmp_fn_t cmp_fn,
+                                    m_strlen_fn_t len_fn,
+                                    const char *prefix,
+                                    int *ind_result,
+                                    int *matches,
+                                    int max_matches,
+                                    int *pnum_matches);
 
 char *get_multicast_group(bool ipv6_prefered);
 void interpret_tilde(char* buf, size_t buf_size, const char* filename);
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to