summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/client/client.c187
-rw-r--r--source3/lib/readline.c24
2 files changed, 188 insertions, 23 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index b6c4b704a9..167f91ae16 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -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
diff --git a/source3/lib/readline.c b/source3/lib/readline.c
index 8b90c32c7f..ceb02ef749 100644
--- a/source3/lib/readline.c
+++ b/source3/lib/readline.c
@@ -116,6 +116,29 @@ char *smb_readline(char *prompt, void (*callback)(void),
}
/****************************************************************************
+ * 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
****************************************************************************/
int cmd_history(void)
@@ -135,3 +158,4 @@ int cmd_history(void)
return 0;
}
+