[PATCH 3/3] programs/cmd: implement filename completion

Jacek Caban jacek at codeweavers.com
Fri Mar 25 09:02:03 CDT 2022


Hi Eric,

On 3/24/22 14:46, Eric Pouech wrote:
> Signed-off-by: Eric Pouech <eric.pouech at gmail.com>
>
> ---
>   programs/cmd/batch.c |  279 +++++++++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 273 insertions(+), 6 deletions(-)
>
> diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c
> index 9a262c5fec5..934cbcc7a39 100644
> --- a/programs/cmd/batch.c
> +++ b/programs/cmd/batch.c
> @@ -227,6 +227,211 @@ WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, BOOL raw,
>     return WCMD_parameter_with_delims (s, n, start, raw, wholecmdline, L" \t,=;");
>   }
>   
> +struct completion_info
> +{
> +    WCHAR** subfiles;
> +    DWORD index_search;
> +    DWORD num_results;
> +};
> +
> +/* gets directory name out of 'path', appends 'in' and surround with quotes if needed */
> +static WCHAR* dup_quoted(const WCHAR* path, const WCHAR* in)
> +{
> +    const WCHAR* last = wcsrchr(path, L'/');
> +    size_t dirlen;
> +    size_t len;
> +    WCHAR* ret;
> +
> +    if (last)
> +    {
> +        WCHAR* last1 = wcschr(last + 1, L'\\');
> +        if (last1) last = last1;
> +    }
> +    else last = wcsrchr(path, L'\\');
> +    dirlen = last ? (last - path) + 1 : 0;


I think that last1 should use wcsrchr as well? Or maybe even replace the 
whole dirlen logic with a simple loop.


> +static BOOL init_completion(struct completion_info* ci, const WCHAR* from, DWORD len, BOOL forward)
> +{
> +    WCHAR* ptr;
> +    HANDLE hff;
> +    WIN32_FIND_DATAW fd;
> +    BOOL in_quotes = FALSE;
> +    DWORD i, j = 0;
> +
> +    ptr = malloc((len + 1 + 1) * sizeof(WCHAR));
> +    if (!ptr) return FALSE;
> +    for (i = 0; i < len; i++)
> +    {
> +        switch (from[i])
> +        {
> +        case L'"':
> +            in_quotes = !in_quotes;
> +            continue;
> +        case L'\\':
> +            if (!in_quotes && i + 1 < len && wcschr(L" \t\"\\", from[i + 1]) != NULL)
> +                ++i;
> +            break;
> +        case L' ':
> +        case L'\t':
> +            /* shouldn't happen, as 'from' should contain a single argument */
> +            if (!in_quotes)
> +            {
> +                free(ptr);
> +                return FALSE;
> +            }
> +            break;
> +        }
> +        ptr[j++] = from[i];
> +    }
> +    ptr[j] = L'*';
> +    ptr[j + 1] = L'\0';
> +    hff = FindFirstFileW(ptr, &fd);
> +    ci->num_results = 0;
> +    ci->subfiles = NULL;
> +    if (hff != INVALID_HANDLE_VALUE)
> +    {
> +        do
> +        {
> +            WCHAR** new;
> +            if (!wcscmp(fd.cFileName, L".") || !wcscmp(fd.cFileName, L".."))
> +                continue;
> +            new = realloc(ci->subfiles, (ci->num_results + 1) * sizeof(*ci->subfiles));
> +            if (!new)
> +            {
> +                FindClose(hff);
> +                free(ptr);
> +                return FALSE;
> +            }
> +            ci->subfiles = new;
> +            if (!(ci->subfiles[ci->num_results++] = dup_quoted(ptr, fd.cFileName)))
> +            {
> +                FindClose(hff);
> +                free(ptr);
> +                return FALSE;
> +            }
> +        } while (FindNextFileW(hff, &fd));
> +        FindClose(hff);
> +    }
> +    free(ptr);
> +    if (!ci->num_results) return FALSE;
> +    ci->index_search = forward ? 0 : ci->num_results - 1;
> +    return TRUE;
> +}


If I read it correctly, if another process creates a file when 
completion is already initialized, we will not take that into account. 
Is that intended?


Thanks,

Jacek




More information about the wine-devel mailing list