Repository: valkey-io/valkey
File: src/sds.c (C)

Code before:
 * The number of arguments is stored into *argc, and an array
 * of sds is returned.
 *
 * The caller should free the resulting array of sds strings with
 * sdsfreesplitres().
 *
 * Note that sdscatrepr() is able to convert back a string into
 * a quoted string in the same format sdssplitargs() is able to parse.
 *
 * The function returns the allocated tokens on success, even when the
 * input string is empty, or NULL if the input contains unbalanced
 * quotes or closed quotes followed by non space characters
 * as in: "foo"bar or "foo'.
 *
 * The sds strings returned by this function are not initialized with
 * extra space.
 */
sds *sdssplitargs(const char *line, int *argc) {
    return sdsnsplitargs(line, -1, argc);
}

/* Split a line into arguments, like sdssplitargs(), but with an explicit length parameter.
 * The number of arguments is stored into *argc, and an array of sds is returned.
 * The caller should free the resulting array with sdsfreesplitres().
 */
sds *sdsnsplitargs(const char *line, int len, int *argc) {
    const char *p = line;
    const char *end = len < 0 ? NULL : line + len;
    size_t cap = 0;
    sds *vector = NULL;

    *argc = 0;
    while (*p && is_ptr_exceeds_end(p, 0, end) <= 0) {
        /* skip blanks */
        while (*p && is_ptr_exceeds_end(p, 0, end) <= 0 && isspace(*p)) p++;
        if (!(*p && is_ptr_exceeds_end(p, 0, end) <= 0)) break;

        unsigned int token_len = 0;
        if (sdsparsearg(p, end, &token_len, NULL)) {
            sds current = sdsnewlen(SDS_NOINIT, token_len);
            int parsed_len = sdsparsearg(p, end, NULL, current);
            assert(parsed_len > 0);
            p += parsed_len;

            /* add the token to the vector */
            if ((size_t)*argc == cap) {
                cap = cap == 0 ? 8 : (cap * 2);
                vector = s_realloc(vector, sizeof(sds) * cap);
            }
            vector[(*argc)++] = current;
            current = NULL;

Review comment (suggestion):
Maybe it would be better to avoid integer type for len?
I mean we could do a:

```
sds *sdsnsplitargs(const char *line, const char *end, int *argc);
```

and implement:

```
sds *sdssplitargs(const char *line, int *argc) {
    return sdsnsplitargs_internal(line, NULL, argc);
}

sds *sdsnsplitargs(const char *line, size_t len, int *argc) {
    const char *end = len < 0 ? NULL : line + len;
    return sdsnsplitargs_internal(line, end, argc);
}
``` 


Code after:
 *
 * The number of arguments is stored into *argc, and an array
 * of sds is returned.
 *
 * The caller should free the resulting array of sds strings with
 * sdsfreesplitres().
 *
 * Note that sdscatrepr() is able to convert back a string into
 * a quoted string in the same format sdssplitargs() is able to parse.
 *
 * The function returns the allocated tokens on success, even when the
 * input string is empty, or NULL if the input contains unbalanced
 * quotes or closed quotes followed by non space characters
 * as in: "foo"bar or "foo'.
 *
 * The sds strings returned by this function are not initialized with
 * extra space.
 */
sds *sdsnsplitargs_internal(const char *line, const char *end, int *argc) {
    const char *p = line;
    size_t cap = 0;
    sds *vector = NULL;

    *argc = 0;
    while (*p && !isPtrExceedingEnd(p, 0, end)) {
        /* skip blanks */
        while (*p && !isPtrExceedingEnd(p, 0, end) && isspace(*p)) p++;
        if (!(*p && !isPtrExceedingEnd(p, 0, end))) break;

        unsigned int token_len = 0;
        if (sdsparsearg(p, end, &token_len, NULL)) {
            sds current = sdsnewlen(SDS_NOINIT, token_len);
            int parsed_len = sdsparsearg(p, end, NULL, current);
            assert(parsed_len > 0);
            p += parsed_len;

            /* add the token to the vector */
            if ((size_t)*argc == cap) {
                cap = cap == 0 ? 8 : (cap * 2);
                vector = s_realloc(vector, sizeof(sds) * cap);
            }
            vector[(*argc)++] = current;
            current = NULL;
        } else {
            while ((*argc)--) sdsfree(vector[*argc]);
            s_free(vector);
            *argc = 0;
            return NULL;
        }
    }
    /* Even on empty input string return something not NULL. */