diff --git a/qstr.c b/qstr.c index c51cf51..d1da28d 100644 --- a/qstr.c +++ b/qstr.c @@ -239,13 +239,13 @@ size_t qstrrchr(qstr str, int c) return ii - 1; } -size_t qstrspni(qstr str, size_t start, qstr accept) +size_t qstrispn(qstr str, size_t start, qstr accept) { if (start >= QSZ(str)) return QSZ(str); return start + memspn(str.q_ptr + start, QSZ(str) - start, accept.q_ptr, QSZ(accept)); } -size_t qstrcspni(qstr str, size_t start, qstr accept) +size_t qstricspn(qstr str, size_t start, qstr accept) { if (start >= QSZ(str)) return QSZ(str); return start + memcspn(str.q_ptr + start, QSZ(str) - start, accept.q_ptr, QSZ(accept)); @@ -253,12 +253,12 @@ size_t qstrcspni(qstr str, size_t start, qstr accept) size_t qstrspn(qstr str, qstr accept) { - return qstrspni(str, 0, accept); + return qstrispn(str, 0, accept); } size_t qstrcspn(qstr str, qstr accept) { - return qstrcspni(str, 0, accept); + return qstricspn(str, 0, accept); } bool qstrsep(qstr *out, qstr in, qstr delim) @@ -332,7 +332,7 @@ const char *qstrdc(qstr *str) return (const char *)str->q_ptr; } -size_t qstrcpi(qstr out, size_t idx, qstr in) +size_t qstricpy(qstr out, size_t idx, qstr in) { size_t sz = QSZ(in); @@ -362,8 +362,8 @@ size_t qstrjoin(qstr out, qstr in[], size_t len, qstr delim) for (size_t ii = 0; ii < len; ii++) { - if (ii != 0) idx = qstrcpi(out, idx, delim); - idx = qstrcpi(out, idx, in[ii]); + if (ii != 0) idx = qstricpy(out, idx, delim); + idx = qstricpy(out, idx, in[ii]); } return idx; @@ -465,7 +465,7 @@ size_t qvfprintf(FILE *stream, qstr fmt, va_list va) retval += qfprint(stream, qstrslice(fmt, 0, pidx)); if (pidx < qstrlen(fmt)) { - size_t fidx = qstrcspni(fmt, pidx + 1, Q("%diouxXeEfFgGaAcsCSPnmQ")); + size_t fidx = qstricspn(fmt, pidx + 1, Q("%diouxXeEfFgGaAcsCSPnmQ")); retval += qfprintf_fmt(stream, qstrslice(fmt, pidx, fidx + 1), va); pidx = fidx + 1; } @@ -492,10 +492,37 @@ size_t qfprintf(FILE *stream, qstr fmt, ...) * Write the string to out, and return the number of bytes that would have * been written, even if it exceeds the size of out. * - * Note: fmemopen() in glibc always pads the end buffer with a '\0', so if + * Note: fmemopen() in glibc always pads the end buffer with a '\0', so when * `out` is too small to hold the whole string, it will contain an ending - * '\0'. + * '\0'. Use fopencookie() instead. */ +#if defined(__GLIBC__) + +/* Avoid defining __GNU_SOURCE just to pull in this function declaration */ +FILE *fopencookie(void *restrict cookie, const char *restrict mode, cookie_io_functions_t io_funcs); + +struct qcookie +{ + uint8_t *oc_buf; + uint8_t *oc_end; +}; + +ssize_t qcookie_write(void *_cookie, const char *buf, size_t sz) +{ + struct qcookie *cookie = _cookie; + + if ((cookie->oc_end - cookie->oc_buf) < (ssize_t)sz) + { + sz = cookie->oc_end - cookie->oc_buf; + } + + memcpy(cookie->oc_buf, buf, sz); + cookie->oc_buf += sz; + + return sz; +} +#endif + size_t qsnprintf(qstr out, qstr fmt, ...) { FILE *stream; @@ -503,7 +530,17 @@ size_t qsnprintf(qstr out, qstr fmt, ...) size_t retval = 0; +#if defined(__GLIBC__) + struct qcookie qc; + memset(&qc, 0, sizeof(qc)); + + qc.oc_buf = out.q_ptr; + qc.oc_end = out.q_ptr + QSZ(out); + + stream = fopencookie(&qc, "w", (cookie_io_functions_t){ .write = qcookie_write }); +#else stream = fmemopen(out.q_ptr, QSZ(out), "wb"); +#endif if (stream == NULL) goto error; va_start(va, fmt); @@ -524,7 +561,7 @@ int main(int argc, char *argv[]) (void)global_test; - uint8_t buf[1024]; + uint8_t buf[39]; size_t qw = qsnprintf(QB(buf), Q("Hello %Q 1 2 3, argc=%d, float=%0.2f"), Q("b\0\0b"), argc, 1.0 / 3.0); qfprintf(stdout, Q("BUF(%zd) = %Q\n"), qw, qstrslice(QB(buf), 0, qw)); @@ -568,7 +605,7 @@ int main(int argc, char *argv[]) printf("Bork\n"); } - qfprintf(stdout, Q("%s\n"), qstrslice(q, 0, idx)); + qfprintf(stdout, Q("%Q\n"), qstrslice(q, 0, idx)); q = QB(buf);