some readline completion exancements
authorSimo Sorce <idra@samba.org>
Sat, 19 Apr 2003 15:40:32 +0000 (15:40 +0000)
committerSimo Sorce <idra@samba.org>
Sat, 19 Apr 2003 15:40:32 +0000 (15:40 +0000)
still need working, does not complete remote names yet
(This used to be commit 625eee8e03c3905a245e078ef9f1c26200e33d7c)

source3/client/client.c
source3/lib/readline.c

index b6c4b704a9b494c752182885fd223a5a32a1edcf..167f91ae16fd9b5d0c246de80babc1e0897bdf17 100644 (file)
@@ -2215,40 +2215,181 @@ static int process_command_string(char *cmd)
        return rc;
 }      
 
-/****************************************************************************
-handle completion of commands for readline
-****************************************************************************/
-static char **completion_fn(char *text, int start, int end)
-{
 #define MAX_COMPLETIONS 100
-       char **matches;
-       int i, count=0;
 
-       /* for words not at the start of the line fallback to filename completion */
-       if (start) return NULL;
+typedef struct {
+       pstring dirmask;
+       char **matches;
+       int count, samelen;
+       const char *text;
+       int len;
+} completion_remote_t;
 
-       matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
-       if (!matches) return NULL;
+static void completion_remote_filter(file_info *f, const char *mask, void *state)
+{
+       completion_remote_t *info = (completion_remote_t *)state;
 
-       matches[count++] = strdup(text);
-       if (!matches[0]) return NULL;
+       if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
+               if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
+                       info->matches[info->count] = strdup(f->name);
+               else {
+                       pstring tmp;
 
-       for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
-               if (strncmp(text, commands[i].name, strlen(text)) == 0) {
-                       matches[count] = strdup(commands[i].name);
-                       if (!matches[count]) return NULL;
-                       count++;
+                       if (info->dirmask[0] != 0)
+                               pstrcpy(tmp, info->dirmask);
+                       else
+                               tmp[0] = 0;
+                       pstrcat(tmp, f->name);
+                       if (f->mode & aDIR)
+                               pstrcat(tmp, "/");
+                       info->matches[info->count] = strdup(tmp);
                }
+               if (info->matches[info->count] == NULL)
+                       return;
+               if (f->mode & aDIR)
+                       smb_readline_ca_char(0);
+
+               if (info->count == 1)
+                       info->samelen = strlen(info->matches[info->count]);
+               else
+                       while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
+                               info->samelen--;
+               info->count++;
        }
+}
+
+static char **remote_completion(const char *text, int len)
+{
+       pstring dirmask;
+       int i;
+       completion_remote_t info = { "", NULL, 1, len, text, len };
+
+       if (len >= PATH_MAX)
+               return(NULL);
+
+       info.matches = (char **)malloc(sizeof(info.matches[0])*MAX_COMPLETIONS);
+       if (!info.matches) return NULL;
+       info.matches[0] = NULL;
+
+       for (i = len-1; i >= 0; i--)
+               if ((text[i] == '/') || (text[i] == '\\'))
+                       break;
+       info.text = text+i+1;
+       info.samelen = info.len = len-i-1;
 
-       if (count == 2) {
-               SAFE_FREE(matches[0]);
-               matches[0] = strdup(matches[1]);
+       if (i > 0) {
+               strncpy(info.dirmask, text, i+1);
+               info.dirmask[i+1] = 0;
+               snprintf(dirmask, sizeof(dirmask), "%s%*s*", cur_dir, i-1, text);
+       } else
+               snprintf(dirmask, sizeof(dirmask), "%s*", cur_dir);
+
+       if (cli_list(cli, dirmask, aDIR | aSYSTEM | aHIDDEN, completion_remote_filter, &info) < 0)
+               goto cleanup;
+
+       if (info.count == 2)
+               info.matches[0] = strdup(info.matches[1]);
+       else {
+               info.matches[0] = malloc(info.samelen+1);
+               if (!info.matches[0])
+                       goto cleanup;
+               strncpy(info.matches[0], info.matches[1], info.samelen);
+               info.matches[0][info.samelen] = 0;
        }
-       matches[count] = NULL;
-       return matches;
+       info.matches[info.count] = NULL;
+       return info.matches;
+
+cleanup:
+       for (i = 0; i < info.count; i++)
+               free(info.matches[i]);
+       free(info.matches);
+       return NULL;
 }
 
+static char **completion_fn(const char *text, int start, int end)
+{
+       smb_readline_ca_char(' ');
+
+       if (start) {
+               const char *buf, *sp;
+               int i;
+               char compl_type;
+
+               buf = smb_readline_get_line_buffer();
+               if (buf == NULL)
+                       return NULL;
+               
+               sp = strchr(buf, ' ');
+               if (sp == NULL)
+                       return NULL;
+               
+               for (i = 0; commands[i].name; i++)
+                       if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
+                               break;
+               if (commands[i].name == NULL)
+                       return NULL;
+
+               while (*sp == ' ')
+                       sp++;
+
+               if (sp == (buf + start))
+                       compl_type = commands[i].compl_args[0];
+               else
+                       compl_type = commands[i].compl_args[1];
+
+               if (compl_type == COMPL_REMOTE)
+                       return remote_completion(text, end - start);
+               else /* fall back to local filename completion */
+                       return NULL;
+       } else {
+               char **matches;
+               int i, len, samelen, count=1;
+
+               matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
+               if (!matches) return NULL;
+               matches[0] = NULL;
+
+               len = strlen(text);
+               for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
+                       if (strncmp(text, commands[i].name, len) == 0) {
+                               matches[count] = strdup(commands[i].name);
+                               if (!matches[count])
+                                       goto cleanup;
+                               if (count == 1)
+                                       samelen = strlen(matches[count]);
+                               else
+                                       while (strncmp(matches[count], matches[count-1], samelen) != 0)
+                                               samelen--;
+                               count++;
+                       }
+               }
+
+               switch (count) {
+               case 0: /* should never happen */
+               case 1:
+                       goto cleanup;
+               case 2:
+                       matches[0] = strdup(matches[1]);
+                       break;
+               default:
+                       matches[0] = malloc(samelen+1);
+                       if (!matches[0])
+                               goto cleanup;
+                       strncpy(matches[0], matches[1], samelen);
+                       matches[0][samelen] = 0;
+               }
+               matches[count] = NULL;
+               return matches;
+
+cleanup:
+               while (i >= 0) {
+                       free(matches[i]);
+                       i--;
+               }
+               free(matches);
+               return NULL;
+       }
+}
 
 /****************************************************************************
 make sure we swallow keepalives during idle time
index 8b90c32c7f9f1066c388f2c3bef10248b5b5baab..ceb02ef749c061f932fcc62e005e65d5e7fbabed 100644 (file)
@@ -115,6 +115,29 @@ char *smb_readline(char *prompt, void (*callback)(void),
        return smb_readline_replacement(prompt, callback, completion_fn);
 }
 
+/****************************************************************************
+ * return line buffer text
+ ****************************************************************************/
+const char *smb_readline_get_line_buffer(void)
+{
+#if defined(HAVE_LIBREADLINE)
+       return rl_line_buffer;
+#else
+       return NULL;
+#endif
+}
+
+
+/****************************************************************************
+ * set completion append character
+ ***************************************************************************/
+void smb_readline_ca_char(char c)
+{
+#if defined(HAVE_LIBREADLINE)
+       rl_completion_append_character = c;
+#endif
+}
+
 /****************************************************************************
 history
 ****************************************************************************/
@@ -135,3 +158,4 @@ int cmd_history(void)
 
        return 0;
 }
+