--- a/dav/main.c Sat Nov 23 11:46:45 2019 +0100 +++ b/dav/main.c Sat Nov 23 15:14:50 2019 +0100 @@ -186,28 +186,7 @@ || !strcasecmp(cmd, "--version")) { fprintf(stderr, "dav %s\n", DAV_VERSION); } else if(!strcasecmp(cmd, "complete")) { - if(args->argc < 2) { - return 1; - } - char *index_str = args->argv[0]; - int64_t index = 0; - if(!util_strtoint(index_str, &index)) { - return 1; - } - if(args->argc + 2 != argc) { - // we have to fix the index - - for(int i=2;i<args->argc;i++) { - if(index == i-2) { - break; - } - if(strcmp(argv[i+2], args->argv[i])) { - index--; - } - } - } - - ret = shell_completion(args, index); + ret = cmd_complete(args); } else { print_usage(argv[0]); } @@ -3002,15 +2981,98 @@ } -int shell_completion(CmdArgs *args, int index) { - if(args->argc < 2 || args->argc < 3) { +static char** read_args_from_stdin(int *argc) { + // read stdin into buffer + UcxBuffer *in = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); + ucx_stream_copy(stdin, in, (read_func)fread, (write_func)ucx_buffer_write); + + // split input into lines + ssize_t count = 0; + sstr_t *lines = scstrsplit(scstrn(in->space, in->pos), SC("\n"), &count); + + char **args = NULL; + if(count > 0) { + args = calloc(count, sizeof(char*)); + for(int i=0;i<count;i++) { + args[i] = lines[i].ptr; + } + free(lines); + + *argc = count; + } else { + *argc = 0; + } + + // cleanup + ucx_buffer_free(in); + + return args; +} + +int cmd_complete(CmdArgs *args) { + if(args->argc != 1) { + return 1; + } + char *index_str = args->argv[0]; + int64_t index = 0; + if(!util_strtoint(index_str, &index)) { return 1; } + // The completion bash script passes the input words to stdin + int comp_argc; + char **comp_argv = read_args_from_stdin(&comp_argc); + + // Try to parse the args + char *cmd = NULL; + if(comp_argc > 1) { + cmd = comp_argv[1]; + } + CmdArgs *comp_args = cmd_parse_args(comp_argc - 2, comp_argv + 2); + if(comp_args) { + // check whether the arglist contains options + if(comp_args->argc + 2 != comp_argc) { + // index points to the arg in the raw arglist, however we have to + // know the index for this item in comp_args->argv + // any arg that is an option or an option value creates a + // difference between the two lists + + // adjust index to comp_args->argv + int j = 0; + for(int i=0;i<comp_argc-2;i++) { + if(index == i-2) { + break; + } + + if(strcmp(comp_argv[i+2], comp_args->argv[j])) { + index--; + } else { + j++; + } + } + } + } else { + comp_args = NULL; + } + + // generate output for shell completion + int ret = 1; + if(comp_args) { + ret = shell_completion(cmd, comp_args, index); + } + + // cleanup + cmd_args_free(comp_args); + free(comp_argv); + return ret; + +} + +int shell_completion(char *cmd, CmdArgs *args, int index) { if(index == 1) { sstr_t prefix = { NULL, 0 }; - if(args->argc > 2) { - prefix = sstr(args->argv[2]); + if(cmd) { + prefix = sstr(cmd); } for(int i=0;;i++) { char *str = cmdusageinfo[i]; @@ -3035,13 +3097,12 @@ return 0; } - char *cmd = args->argv[2]; if(!strcmp(cmd, "date")) { return 0; } // get already typed URL or NULL, if the user hasn't started typing yet - char *url = args->argc > 3 ? args->argv[3] : NULL; + char *url = args->argc > 0 ? args->argv[0] : NULL; //printf("index: {%s}\n", args->argv[0]); //printf("dav: {%s}\n", args->argv[1]); @@ -3050,21 +3111,21 @@ if(index == 2) { // url completion - return url_completion(url); + return url_completion(args, url); } else if (index == 3) { if(!strcmp(cmd, "put") || !strcmp(cmd, "import")) { // file completion return 12; } else if(!strcmp(cmd, "copy") || !strcmp(cmd, "cp") || !strcmp(cmd, "move") || !strcmp(cmd, "mv")) { // url completion - return url_completion(url); + return url_completion(args, url); } } return 0; } -int url_completion(char *u) { +int url_completion(CmdArgs *args, char *u) { sstr_t url; url.ptr = u; url.length = u ? strlen(u) : 0; @@ -3108,19 +3169,17 @@ } } else { // url completion - - CmdArgs a; - memset(&a, 0, sizeof(CmdArgs)); - a.options = ucx_map_new(4); - ucx_map_cstr_put(a.options, "noinput", ""); + ucx_map_cstr_put(args->options, "noinput", ""); char *path = NULL; Repository *repo = url2repo_s(url, &path); - DavSession *sn = connect_to_repo(repo, path, &a); - ucx_map_free(a.options); + DavSession *sn = connect_to_repo(repo, path, args); if(!sn) { return 0; } + if(set_session_config(sn, args)) { + return 0; + } size_t plen = strlen(path);