From e013fd7d0f5ae8f5c994aad4d02f5169946f1a26 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 15 Mar 2017 16:27:15 +0100 Subject: Simplify string formatter API. Emit characters with callbacks so we don't need to do two passes using vsnprintf to count, format, and copy the result. --- include/mupdf/fitz/buffer.h | 4 +-- include/mupdf/fitz/output.h | 12 +++++++- source/fitz/buffer.c | 41 ++++++------------------- source/fitz/output.c | 37 ++++++----------------- source/fitz/printf.c | 74 +++++++++++++++++++++++++++++++++------------ 5 files changed, 87 insertions(+), 81 deletions(-) diff --git a/include/mupdf/fitz/buffer.h b/include/mupdf/fitz/buffer.h index 96fcc185..73f254a3 100644 --- a/include/mupdf/fitz/buffer.h +++ b/include/mupdf/fitz/buffer.h @@ -112,8 +112,8 @@ void fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int x); void fz_append_int16_le(fz_context *ctx, fz_buffer *buf, int x); void fz_append_bits(fz_context *ctx, fz_buffer *buf, int value, int count); void fz_append_bits_pad(fz_context *ctx, fz_buffer *buf); -size_t fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...); -size_t fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args); +void fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...); +void fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args); void fz_append_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text); /* diff --git a/include/mupdf/fitz/output.h b/include/mupdf/fitz/output.h index 023153a9..48bcc502 100644 --- a/include/mupdf/fitz/output.h +++ b/include/mupdf/fitz/output.h @@ -271,7 +271,8 @@ static inline void fz_write_rune(fz_context *ctx, fz_output *out, int rune) } /* - fz_vsnprintf: Our customised vsnprintf routine. Takes %c, %d, %o, %s, %u, %x, as usual. + fz_format_string: Our customised 'printf'-like string formatter. + Takes %c, %d, %o, %s, %u, %x, as usual. Modifiers are not supported except for zero-padding ints (e.g. %02d, %03o, %04x, etc). %g output in "as short as possible hopefully lossless non-exponent" form, see fz_ftoa for specifics. @@ -282,6 +283,15 @@ static inline void fz_write_rune(fz_context *ctx, fz_output *out, int rune) %ll{d,u,x} indicates that the values are 64bit. %z{d,u,x} indicates that the value is a size_t. %Z{d,u,x} indicates that the value is a fz_off_t. + + user: An opaque pointer that is passed to the emit function. + emit: A function pointer called to emit output bytes as the string is being formatted. +*/ +void +fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args); + +/* + fz_vsnprintf: A vsnprintf work-alike, using our custom formatter. */ size_t fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args); diff --git a/source/fitz/buffer.c b/source/fitz/buffer.c index ab814728..d432e810 100644 --- a/source/fitz/buffer.c +++ b/source/fitz/buffer.c @@ -331,45 +331,24 @@ fz_append_bits_pad(fz_context *ctx, fz_buffer *buf) buf->unused_bits = 0; } -size_t +static void fz_append_emit(fz_context *ctx, void *buffer, int c) +{ + fz_append_byte(ctx, buffer, c); +} + +void fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...) { - size_t ret; va_list args; va_start(args, fmt); - ret = fz_append_vprintf(ctx, buffer, fmt, args); + fz_format_string(ctx, buffer, fz_append_emit, fmt, args); va_end(args); - return ret; } -size_t -fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list old_args) +void +fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args) { - size_t slack; - size_t len; - va_list args; - - slack = buffer->cap - buffer->len; - va_copy(args, old_args); - len = fz_vsnprintf((char *)buffer->data + buffer->len, slack, fmt, args); - va_copy_end(args); - - /* len is the number of characters in the formatted string (not including - * the terminating zero), so if (len > slack) the string was truncated. */ - if (len > slack) - { - /* Grow the buffer and retry */ - fz_ensure_buffer(ctx, buffer, buffer->len + len); - slack = buffer->cap - buffer->len; - - va_copy(args, old_args); - len = fz_vsnprintf((char *)buffer->data + buffer->len, slack, fmt, args); - va_copy_end(args); - } - - buffer->len += len; - - return len; + fz_format_string(ctx, buffer, fz_append_emit, fmt, args); } void diff --git a/source/fitz/output.c b/source/fitz/output.c index bd4dba66..961bafe5 100644 --- a/source/fitz/output.c +++ b/source/fitz/output.c @@ -266,36 +266,17 @@ fz_tell_output(fz_context *ctx, fz_output *out) return out->tell(ctx, out->state); } -void -fz_write_vprintf(fz_context *ctx, fz_output *out, const char *fmt, va_list old_args) +static void +fz_write_emit(fz_context *ctx, void *out, int c) { - char buffer[256], *p = buffer; - size_t len; - va_list args; + fz_write_byte(ctx, out, c); +} +void +fz_write_vprintf(fz_context *ctx, fz_output *out, const char *fmt, va_list args) +{ if (!out) return; - - /* First try using our fixed size buffer */ - va_copy(args, old_args); - len = fz_vsnprintf(buffer, sizeof buffer, fmt, args); - va_copy_end(args); - - /* If that failed, allocate a big enough buffer */ - if (len > sizeof buffer) - { - p = fz_malloc(ctx, len); - va_copy(args, old_args); - fz_vsnprintf(p, len, fmt, args); - va_copy_end(args); - } - - fz_try(ctx) - out->write(ctx, out->state, p, len); - fz_always(ctx) - if (p != buffer) - fz_free(ctx, p); - fz_catch(ctx) - fz_rethrow(ctx); + fz_format_string(ctx, out, fz_write_emit, fmt, args); } void @@ -304,7 +285,7 @@ fz_write_printf(fz_context *ctx, fz_output *out, const char *fmt, ...) va_list args; if (!out) return; va_start(args, fmt); - fz_write_vprintf(ctx, out, fmt, args); + fz_format_string(ctx, out, fz_write_emit, fmt, args); va_end(args); } diff --git a/source/fitz/printf.c b/source/fitz/printf.c index 65c98278..d0f95327 100644 --- a/source/fitz/printf.c +++ b/source/fitz/printf.c @@ -4,16 +4,14 @@ static const char *fz_hex_digits = "0123456789abcdef"; struct fmtbuf { - char *p; - size_t s; - size_t n; + fz_context *ctx; + void *user; + void (*emit)(fz_context *ctx, void *user, int c); }; -static void fmtputc(struct fmtbuf *out, int c) +static inline void fmtputc(struct fmtbuf *out, int c) { - if (out->n < out->s) - out->p[out->n] = c; - ++(out->n); + out->emit(out->ctx, out->user, c); } /* @@ -151,29 +149,31 @@ static void fmtquote(struct fmtbuf *out, const char *s, int sq, int eq) fmtputc(out, eq); } -size_t -fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args) +void +fz_format_string(fz_context *ctx, void *user, void (*emit)(fz_context *ctx, void *user, int c), const char *fmt, va_list args) { struct fmtbuf out; + int c, i, n, z; fz_matrix *m; fz_rect *r; fz_point *p; - int c, i, n, z; int64_t i64; double f; char *s; size_t length; - out.p = buffer; - out.s = space; - out.n = 0; + out.ctx = ctx; + out.user = user; + out.emit = emit; while ((c = *fmt++) != 0) { - if (c == '%') { + if (c == '%') + { c = *fmt++; if (c == 0) break; + z = 1; if (c == '0' && fmt[0] && fmt[1]) { z = *fmt++ - '0'; @@ -184,6 +184,7 @@ fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args) c = *fmt++; } } + /* Check for lengths */ length = 0; switch (c) { @@ -213,6 +214,7 @@ fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args) if (c == 0) break; /* Can't warn :( */ } + switch (c) { default: fmtputc(&out, '%'); @@ -326,22 +328,56 @@ fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args) fmtquote(&out, s, '(', ')'); break; } - } else { + } + else + { fmtputc(&out, c); } } +} - fmtputc(&out, 0); +struct snprintf_buffer +{ + char *p; + size_t s, n; +}; + +static void snprintf_emit(fz_context *ctx, void *out_, int c) +{ + struct snprintf_buffer *out = out_; + if (out->n < out->s) + out->p[out->n] = c; + ++(out->n); +} + +size_t +fz_vsnprintf(char *buffer, size_t space, const char *fmt, va_list args) +{ + struct snprintf_buffer out; + out.p = buffer; + out.s = space; + out.n = 0; + + /* Note: using a NULL context is safe here */ + fz_format_string(NULL, &out, snprintf_emit, fmt, args); + snprintf_emit(NULL, &out, 0); return out.n - 1; } size_t fz_snprintf(char *buffer, size_t space, const char *fmt, ...) { - size_t n; va_list ap; + struct snprintf_buffer out; + out.p = buffer; + out.s = space; + out.n = 0; + va_start(ap, fmt); - n = fz_vsnprintf(buffer, space, fmt, ap); + /* Note: using a NULL context is safe here */ + fz_format_string(NULL, &out, snprintf_emit, fmt, ap); + snprintf_emit(NULL, &out, 0); va_end(ap); - return n; + + return out.n - 1; } -- cgit v1.2.3