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

Code before:
            switch (*p) {
            case ' ':
            case '\n':
            case '\r':
            case '\t':
            case '\0': done = 1; break;
            case '"': inq = 1; break;
            case '\'': insq = 1; break;
            default: new_char = *p; break;
            }
        }
        if (new_char != -1) {
            if (len) (*len)++;
            if (dst) {
                *dst = (char)new_char;
                dst++;
            }
        }
        if (*p) {
            p++;
        }
    }
    return p - arg;
}

static int sdsnparsearg(const char *arg, const char *end, unsigned int *len, char *dst) {
    const char *p = arg;
    int inq = 0;  /* set to 1 if we are in "quotes" */
    int insq = 0; /* set to 1 if we are in 'single quotes' */
    int done = 0;

    if (end == NULL || p >= end) {
        return 0;
    }

    while (!done) {
        int new_char = -1;
        if (inq) {
            if (!*p) {
                /* unterminated quotes */
                return 0;
            } else if (p + 3 < end && (*p == '\\' && *(p + 1) == 'x' && is_hex_digit(*(p + 2)) && is_hex_digit(*(p + 3)))) {
                new_char = (hex_digit_to_int(*(p + 2)) * 16) + hex_digit_to_int(*(p + 3));
                p += 4;
            } else if (p + 1 < end && (*p == '\\' && *(p + 1))) {
                switch (*(p + 1)) {
                case 'n': new_char = '\n'; break;
                case 'r': new_char = '\r'; break;
                case 't': new_char = '\t'; break;
                case 'b': new_char = '\b'; break;
                case 'a': new_char = '\a'; break;

Review comment (refactor):
To avoid the duplicated code, can we just add `end` as an optional parameter in the existing `sdsparsearg`? I mean if NULL is used, you get the old behavior of `sdsparsearg`.

Code after:
            }
        } else if (insq) {
            if (!*p) {
                /* unterminated quotes */
                return 0;
            } else if (!isPtrExceedingEnd(p, 2, end) && (*p == '\\' && *(p + 1) == '\'')) {
                new_char = '\'';
                p += 2;
            } else if (*p == '\'') {
                insq = 0;
                p++;
            } else {
                new_char = *p;
                p++;
            }
        } else {
            switch (*p) {
            case ' ':
            case '\n':
            case '\r':
            case '\t':
            case '\0': done = 1; break;
            case '"': inq = 1; break;
            case '\'': insq = 1; break;
            default: new_char = *p; break;
            }
            if (*p != '\0') {
                p++;
            }
        }
        if (new_char != -1) {
            if (len) (*len)++;
            if (dst) {
                *dst = (char)new_char;
                dst++;
            }
        }
        if (isPtrExceedingEnd(p, 0, end)) {
            if (inq || insq) {
                /* unterminated quotes */
                return 0;
            } else {
                done = 1;
            }
        }
    }
    return p - arg;
}

/* Split a line into arguments, where every argument can be in the
 * following programming-language REPL-alike form: