[PATCH 1/6] shell32/autocomplete: Introduce helpers for proper enumeration

Huw Davies huw at codeweavers.com
Wed Oct 24 02:49:58 CDT 2018


On Tue, Oct 23, 2018 at 02:26:02PM +0300, Gabriel Ivăncescu wrote:
> These will be used to implement proper string enumeration, because Windows
> doesn't reset and re-enumerate it everytime autocompletion happens, and it
> also sorts them like Windows does.
> 
> Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
> ---
> 
> For now, the first two patches in the series do nothing because the helpers
> are unused; they will be used afterwards, and were split to avoid the
> patches becoming too large.

Please don't do this.  Every patch needs to stand by itself; adding unused
code doesn't count.

> Merge Sort has been used to sort the strings because it is stable, and
> because it minimizes the amount of comparisons, which is essential for
> case-insensitive string comparisons.

I don't see why do you need a stable sort here.  Using libc's qsort
should be fine at first.

> +static void enumerate_strings(IAutoCompleteImpl *ac)
> +{
> +    /*
> +       Enumerate all of the strings and sort them in the internal list. Rough summary:
> +
> +         - Enumerate the strings and place their addresses in a chain of blocks (stack-like)
> +         - Sort pairs from the chain of blocks into a contiguous array of pointers to them
> +         - Merge Sort the contiguous array/list (excluding pairs, since it's already done)
> +
> +       We don't free the enumerated strings (except on error) to avoid needless
> +       copies, until the next reset (or the object itself is destroyed)
> +    */
> +    struct
> +    {
> +        void *prev;
> +        LPOLESTR str[511 * 2];  /* this must be kept *even* */
> +    } *prevblock, *curblock;
> +
> +    UINT i, cur, numstrs = 0;
> +    LPOLESTR *strs;
> +
> +    prevblock = NULL;
> +    for (;;)
> +    {
> +        LONG rem;
> +        if ((curblock = heap_alloc(sizeof(*curblock))) == NULL)
> +        {
> +            if (!prevblock)
> +                return;
> +            curblock = prevblock;
> +            cur = ARRAY_SIZE(curblock->str);
> +            goto fail_and_free_blocks;
> +        }
> +        curblock->prev = prevblock;
> +        rem = ARRAY_SIZE(curblock->str);
> +
> +        while (rem > 0)
> +        {
> +            ULONG n = 0;
> +            cur = ARRAY_SIZE(curblock->str) - rem;
> +            IEnumString_Next(ac->enumstr, rem, &curblock->str[cur], &n);
> +            if (n == 0)
> +                goto break_from_enumeration;
> +            rem -= n;
> +        }
> +        prevblock = curblock;
> +        numstrs += ARRAY_SIZE(curblock->str);
> +    }
> +
> +break_from_enumeration:
> +    /* Allocate even if there were zero strings enumerated, to mark it non-NULL */
> +    numstrs += cur;
> +    if (!(strs = heap_alloc(numstrs * sizeof(*strs))))
> +    {
> +      fail_and_free_blocks:
> +        do
> +        {
> +            LPOLESTR *str = curblock->str;
> +            while (cur--)
> +                CoTaskMemFree(str[cur]);
> +            prevblock = curblock->prev;
> +            heap_free(curblock);
> +            curblock = prevblock;
> +            cur = ARRAY_SIZE(curblock->str);
> +        } while (curblock);
> +        return;
> +    }

And even though I've mentioned it twice already you're still using
gotos.  Please get them out of your system; there's no way anyone is
going sign off on this.  A 'goto fail' is ok, but the fail label needs
to be at the outer-level and near the end of the function.  If you
think you need a goto for anything else then it's a sign you need to
restructure your code.

Huw.



More information about the wine-devel mailing list