Module Name: src Committed By: abhinav Date: Sun Sep 8 05:50:58 UTC 2019
Modified Files: src/lib/libedit: filecomplete.c src/lib/libedit/TEST: test_filecompletion.c Log Message: PR lib/54510: Fix file completion inside quotes which broke in rev 1.53 While there also fix handling character appending in the file completions when inside quotes. For example when inside a quote, if the completion is a directory then append a '/' but don't close the quote. On the other hand when inside a quote if the completion is a file name and it is the only match then we can close the quote. To generate a diff of this commit: cvs rdiff -u -r1.57 -r1.58 src/lib/libedit/filecomplete.c cvs rdiff -u -r1.4 -r1.5 src/lib/libedit/TEST/test_filecompletion.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libedit/filecomplete.c diff -u src/lib/libedit/filecomplete.c:1.57 src/lib/libedit/filecomplete.c:1.58 --- src/lib/libedit/filecomplete.c:1.57 Sun Jul 28 09:27:29 2019 +++ src/lib/libedit/filecomplete.c Sun Sep 8 05:50:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: filecomplete.c,v 1.57 2019/07/28 09:27:29 christos Exp $ */ +/* $NetBSD: filecomplete.c,v 1.58 2019/09/08 05:50:58 abhinav Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include "config.h" #if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: filecomplete.c,v 1.57 2019/07/28 09:27:29 christos Exp $"); +__RCSID("$NetBSD: filecomplete.c,v 1.58 2019/09/08 05:50:58 abhinav Exp $"); #endif /* not lint && not SCCSID */ #include <sys/types.h> @@ -192,7 +192,8 @@ unescape_string(const wchar_t *string, s } static char * -escape_filename(EditLine * el, const char *filename) +escape_filename(EditLine * el, const char *filename, int single_match, + const char *(*app_func)(const char *)) { size_t original_len = 0; size_t escaped_character_count = 0; @@ -204,6 +205,7 @@ escape_filename(EditLine * el, const cha size_t d_quoted = 0; /* does the input contain a double quote */ char *escaped_str; wchar_t *temp = el->el_line.buffer; + const char *append_char = NULL; if (filename == NULL) return NULL; @@ -246,6 +248,9 @@ escape_filename(EditLine * el, const cha if (s_quoted || d_quoted) newlen++; + if (single_match && app_func) + newlen++; + if ((escaped_str = el_malloc(newlen)) == NULL) return NULL; @@ -285,11 +290,24 @@ escape_filename(EditLine * el, const cha escaped_str[offset++] = c; } - /* close the quotes */ - if (s_quoted) - escaped_str[offset++] = '\''; - else if (d_quoted) - escaped_str[offset++] = '"'; + if (single_match && app_func) { + escaped_str[offset] = 0; + append_char = app_func(escaped_str); + /* we want to append space only if we are not inside quotes */ + if (append_char[0] == ' ') { + if (!s_quoted && !d_quoted) + escaped_str[offset++] = append_char[0]; + } else + escaped_str[offset++] = append_char[0]; + } + + /* close the quotes if single match and the match is not a directory */ + if (single_match && (append_char && append_char[0] == ' ')) { + if (s_quoted) + escaped_str[offset++] = '\''; + else if (d_quoted) + escaped_str[offset++] = '"'; + } escaped_str[offset] = 0; return escaped_str; @@ -596,6 +614,10 @@ find_word_to_complete(const wchar_t * cu if (ctemp - buffer >= 2 && ctemp[-2] == '\\') { ctemp -= 2; continue; + } else if (ctemp - buffer >= 2 && + (ctemp[-2] == '\'' || ctemp[-2] == '"')) { + ctemp--; + continue; } else break; } @@ -605,6 +627,10 @@ find_word_to_complete(const wchar_t * cu } len = (size_t) (cursor - ctemp); + if (len == 1 && (ctemp[0] == '\'' || ctemp[0] == '"')) { + len = 0; + ctemp++; + } *length = len; wchar_t *unescaped_word = unescape_string(ctemp, len); if (unescaped_word == NULL) @@ -689,31 +715,29 @@ fn_complete(EditLine *el, retval = CC_REFRESH; if (matches[0][0] != '\0') { - el_deletestr(el, (int) len); + el_deletestr(el, (int)len); if (!attempted_completion_function) - completion = escape_filename(el, matches[0]); + completion = escape_filename(el, matches[0], + single_match, app_func); else completion = strdup(matches[0]); if (completion == NULL) goto out; if (single_match) { - /* - * We found exact match. Add a space after - * it, unless we do filename completion and the - * object is a directory. Also do necessary escape quoting + /* We found exact match. Add a space after it, + * unless we do filename completion and the + * object is a directory. Also do necessary + * escape quoting */ el_winsertstr(el, - ct_decode_string(completion, &el->el_scratch)); - el_winsertstr(el, - ct_decode_string((*app_func)(completion), - &el->el_scratch)); + ct_decode_string(completion, &el->el_scratch)); } else { - /* - * Only replace the completed string with common part of - * possible matches if there is possible completion. + /* Only replace the completed string with + * common part of possible matches if there is + * possible completion. */ el_winsertstr(el, - ct_decode_string(completion, &el->el_scratch)); + ct_decode_string(completion, &el->el_scratch)); } free(completion); } Index: src/lib/libedit/TEST/test_filecompletion.c diff -u src/lib/libedit/TEST/test_filecompletion.c:1.4 src/lib/libedit/TEST/test_filecompletion.c:1.5 --- src/lib/libedit/TEST/test_filecompletion.c:1.4 Sun Mar 31 03:04:57 2019 +++ src/lib/libedit/TEST/test_filecompletion.c Sun Sep 8 05:50:58 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: test_filecompletion.c,v 1.4 2019/03/31 03:04:57 abhinav Exp $ */ +/* $NetBSD: test_filecompletion.c,v 1.5 2019/09/08 05:50:58 abhinav Exp $ */ /*- * Copyright (c) 2017 Abhinav Upadhyay <abhi...@netbsd.org> @@ -62,14 +62,14 @@ static test_input inputs[] = { L"ls \"dq_ang", "dq_ang", {"dq_ang<ular>test", NULL}, - L"ls \"dq_ang<ular>test\" " + L"ls \"dq_ang<ular>test\"" }, { /* test angular bracket inside singlq quotes: ls "sq_ang */ L"ls 'sq_ang", "sq_ang", {"sq_ang<ular>test", NULL}, - L"ls 'sq_ang<ular>test' " + L"ls 'sq_ang<ular>test'" }, { /* simple test for backslash */ @@ -83,14 +83,14 @@ static test_input inputs[] = { L"ls 'sback", "sback", {"sbackslash\\test", NULL}, - L"ls 'sbackslash\\test' " + L"ls 'sbackslash\\test'" }, { /* backslash inside double quotes */ L"ls \"dback", "dback", {"dbackslash\\test", NULL}, - L"ls \"dbackslash\\\\test\" " + L"ls \"dbackslash\\\\test\"" }, { /* test braces */ @@ -104,14 +104,14 @@ static test_input inputs[] = { L"ls 'sbr", "sbr", {"sbraces{test}", NULL}, - L"ls 'sbraces{test}' " + L"ls 'sbraces{test}'" }, { /* test braces inside double quotes */ L"ls \"dbr", "dbr", {"dbraces{test}", NULL}, - L"ls \"dbraces{test}\" " + L"ls \"dbraces{test}\"" }, { /* test dollar */ @@ -125,14 +125,14 @@ static test_input inputs[] = { L"ls 'sdoll", "sdoll", {"sdoll$artest", NULL}, - L"ls 'sdoll$artest' " + L"ls 'sdoll$artest'" }, { /* test dollar inside double quotes */ L"ls \"ddoll", "ddoll", {"ddoll$artest", NULL}, - L"ls \"ddoll\\$artest\" " + L"ls \"ddoll\\$artest\"" }, { /* test equals */ @@ -146,14 +146,14 @@ static test_input inputs[] = { L"ls 'seq", "seq", {"sequals==test", NULL}, - L"ls 'sequals==test' " + L"ls 'sequals==test'" }, { /* test equals inside double quotes */ L"ls \"deq", "deq", {"dequals==test", NULL}, - L"ls \"dequals==test\" " + L"ls \"dequals==test\"" }, { /* test \n */ @@ -167,14 +167,14 @@ static test_input inputs[] = { L"ls 'snew", "snew", {"snew\nline", NULL}, - L"ls 'snew\nline' " + L"ls 'snew\nline'" }, { /* test \n inside double quotes */ L"ls \"dnew", "dnew", {"dnew\nline", NULL}, - L"ls \"dnew\nline\" " + L"ls \"dnew\nline\"" }, { /* test single space */ @@ -188,14 +188,14 @@ static test_input inputs[] = { L"ls 's_spac", "s_spac", {"s_space test", NULL}, - L"ls 's_space test' " + L"ls 's_space test'" }, { /* test single space inside double quotes */ L"ls \"d_spac", "d_spac", {"d_space test", NULL}, - L"ls \"d_space test\" " + L"ls \"d_space test\"" }, { /* test multiple spaces */ @@ -209,14 +209,14 @@ static test_input inputs[] = { L"ls 's_multi", "s_multi", {"s_multi space test", NULL}, - L"ls 's_multi space test' " + L"ls 's_multi space test'" }, { /* test multiple spaces inside double quotes */ L"ls \"d_multi", "d_multi", {"d_multi space test", NULL}, - L"ls \"d_multi space test\" " + L"ls \"d_multi space test\"" }, { /* test double quotes */ @@ -230,14 +230,14 @@ static test_input inputs[] = { L"ls 's_doub", "s_doub", {"s_doub\"quotes", NULL}, - L"ls 's_doub\"quotes' " + L"ls 's_doub\"quotes'" }, { /* test double quotes inside double quotes */ L"ls \"d_doub", "d_doub", {"d_doub\"quotes", NULL}, - L"ls \"d_doub\\\"quotes\" " + L"ls \"d_doub\\\"quotes\"" }, { /* test multiple double quotes */ @@ -251,14 +251,14 @@ static test_input inputs[] = { L"ls 'smud", "smud", {"smud\"qu\"otes\"", NULL}, - L"ls 'smud\"qu\"otes\"' " + L"ls 'smud\"qu\"otes\"'" }, { /* test multiple double quotes inside double quotes */ L"ls \"dmud", "dmud", {"dmud\"qu\"otes\"", NULL}, - L"ls \"dmud\\\"qu\\\"otes\\\"\" " + L"ls \"dmud\\\"qu\\\"otes\\\"\"" }, { /* test one single quote */ @@ -272,14 +272,14 @@ static test_input inputs[] = { L"ls 'ssing", "ssing", {"ssingle'quote", NULL}, - L"ls 'ssingle'\\''quote' " + L"ls 'ssingle'\\''quote'" }, { /* test one single quote inside double quote */ L"ls \"dsing", "dsing", {"dsingle'quote", NULL}, - L"ls \"dsingle'quote\" " + L"ls \"dsingle'quote\"" }, { /* test multiple single quotes */ @@ -293,14 +293,14 @@ static test_input inputs[] = { L"ls 'smu_sing", "smu_sing", {"smu_single''quotes''", NULL}, - L"ls 'smu_single'\\'''\\''quotes'\\\'''\\''' " + L"ls 'smu_single'\\'''\\''quotes'\\\'''\\'''" }, { /* test multiple single quotes inside double quote */ L"ls \"dmu_sing", "dmu_sing", {"dmu_single''quotes''", NULL}, - L"ls \"dmu_single''quotes''\" " + L"ls \"dmu_single''quotes''\"" }, { /* test parenthesis */ @@ -314,14 +314,14 @@ static test_input inputs[] = { L"ls 'sparen", "sparen", {"sparen(test)", NULL}, - L"ls 'sparen(test)' " + L"ls 'sparen(test)'" }, { /* test parenthesis inside double quote */ L"ls \"dparen", "dparen", {"dparen(test)", NULL}, - L"ls \"dparen(test)\" " + L"ls \"dparen(test)\"" }, { /* test pipe */ @@ -335,14 +335,14 @@ static test_input inputs[] = { L"ls 'spip", "spip", {"spipe|test", NULL}, - L"ls 'spipe|test' ", + L"ls 'spipe|test'", }, { /* test pipe inside double quote */ L"ls \"dpip", "dpip", {"dpipe|test", NULL}, - L"ls \"dpipe|test\" " + L"ls \"dpipe|test\"" }, { /* test tab */ @@ -356,14 +356,14 @@ static test_input inputs[] = { L"ls 'sta", "sta", {"stab\ttest", NULL}, - L"ls 'stab\ttest' " + L"ls 'stab\ttest'" }, { /* test tab inside double quote */ L"ls \"dta", "dta", {"dtab\ttest", NULL}, - L"ls \"dtab\ttest\" " + L"ls \"dtab\ttest\"" }, { /* test back tick */ @@ -377,14 +377,14 @@ static test_input inputs[] = { L"ls 'stic", "stic", {"stick`test`", NULL}, - L"ls 'stick`test`' " + L"ls 'stick`test`'" }, { /* test back tick inside double quote */ L"ls \"dtic", "dtic", {"dtick`test`", NULL}, - L"ls \"dtick\\`test\\`\" " + L"ls \"dtick\\`test\\`\"" }, { /* test for @ */ @@ -398,14 +398,14 @@ static test_input inputs[] = { L"ls 'sat", "sat", {"satthe@rate", NULL}, - L"ls 'satthe@rate' " + L"ls 'satthe@rate'" }, { /* test for @ inside double quote */ L"ls \"dat", "dat", {"datthe@rate", NULL}, - L"ls \"datthe@rate\" " + L"ls \"datthe@rate\"" }, { /* test ; */ @@ -419,14 +419,14 @@ static test_input inputs[] = { L"ls 'ssemi", "ssemi", {"ssemi;colon;test", NULL}, - L"ls 'ssemi;colon;test' " + L"ls 'ssemi;colon;test'" }, { /* test ; inside double quote */ L"ls \"dsemi", "dsemi", {"dsemi;colon;test", NULL}, - L"ls \"dsemi;colon;test\" " + L"ls \"dsemi;colon;test\"" }, { /* test & */ @@ -440,14 +440,14 @@ static test_input inputs[] = { L"ls 'samp", "samp", {"sampers&and", NULL}, - L"ls 'sampers&and' " + L"ls 'sampers&and'" }, { /* test & inside double quote */ L"ls \"damp", "damp", {"dampers&and", NULL}, - L"ls \"dampers&and\" " + L"ls \"dampers&and\"" }, { /* test completion when cursor at \ */