_c_public_ int c_shquote_parse_next(char **outp,
                                    size_t *n_outp,
                                    const char **inp,
                                    size_t *n_inp) {
        const char *in = *inp;
        size_t n_in = *n_inp;
        char *out = *outp;
        size_t n_out = *n_outp;
        bool got_output = false;
        int r;

        while (n_in > 0) {
                size_t len;

                switch (*in) {
                case '\'':
                        r = c_shquote_unquote_single(&out, &n_out, &in, &n_in);
                        if (r)
                                return r;

                        got_output = true;
                        break;
                case '\"':
                        r = c_shquote_unquote_double(&out, &n_out, &in, &n_in);
                        if (r)
                                return r;

                        got_output = true;
                        break;
                case '\\':
                        r = c_shquote_unescape_char_unquoted(&out, &n_out, &in, &n_in);
                        if (r)
                                return r;

                        if (n_out != *n_outp)
                                got_output = true;
                        break;
                case ' ':
                case '\t':
                case '\n':
                        c_shquote_discard_whitespace(&in, &n_in);

                        if (got_output)
                                goto out;

                        break;
                case '#':
                        if (!got_output) {
                                c_shquote_discard_comment(&in, &n_in);
                        } else {
                                r = c_shquote_consume_char(&out, &n_out, &in, &n_in);
                                if (r)
                                        return r;
                        }

                        break;
                default:
                        /*
                         * Consume until the next escape character. If none
                         * exists, consume the rest of the string.
                         */
                        len = c_shquote_strncspn(in, n_in, "'\"\\ \t\n#");
                        c_assert(len > 0);

                        r = c_shquote_consume_str(&out, &n_out, &in, &n_in, len);
                        if (r)
                                return r;

                        got_output = true;
                        break;
                }
        }

out:
        if (!got_output)
                return C_SHQUOTE_E_EOF;

        *outp = out;
        *n_outp = n_out;
        *inp = in;
        *n_inp = n_in;
        return 0;
}
_c_public_ int c_shquote_parse_next(char **outp,
                                    size_t *n_outp,
                                    const char **inp,
                                    size_t *n_inp) {
        const char *in = *inp;
        size_t n_in = *n_inp;
        char *out = *outp;
        size_t n_out = *n_outp;
        bool got_output = false;
        int r;

        while (n_in > 0) {
                size_t len;

                switch (*in) {
                case '\'':
                        r = c_shquote_unquote_single(&out, &n_out, &in, &n_in);
                        if (r)
                                return r;

                        got_output = true;
                        break;
                case '\"':
                        r = c_shquote_unquote_double(&out, &n_out, &in, &n_in);
                        if (r)
                                return r;

                        got_output = true;
                        break;
                case '\\':
                        r = c_shquote_unescape_char_unquoted(&out, &n_out, &in, &n_in);
                        if (r)
                                return r;

                        if (n_out != *n_outp)
                                got_output = true;
                        break;
                case ' ':
                case '\t':
                case '\n':
                        c_shquote_discard_whitespace(&in, &n_in);

                        if (got_output)
                                goto out;

                        break;
                case '#':
                        if (!got_output) {
                                c_shquote_discard_comment(&in, &n_in);
                        } else {
                                r = c_shquote_consume_char(&out, &n_out, &in, &n_in);
                                if (r)
                                        return r;
                        }

                        break;
                default:
                         
                        len = c_shquote_strncspn(in, n_in, "'\"\\ \t\n#");
                        c_assert(len > 0);

                        r = c_shquote_consume_str(&out, &n_out, &in, &n_in, len);
                        if (r)
                                return r;

                        got_output = true;
                        break;
                }
        }

out:
        if (!got_output)
                return C_SHQUOTE_E_EOF;

        *outp = out;
        *n_outp = n_out;
        *inp = in;
        *n_inp = n_in;
        return 0;
}