diff options
Diffstat (limited to 'upb/pb/textprinter.c')
-rw-r--r-- | upb/pb/textprinter.c | 217 |
1 files changed, 127 insertions, 90 deletions
diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c index 2fe3452..3770afc 100644 --- a/upb/pb/textprinter.c +++ b/upb/pb/textprinter.c @@ -5,11 +5,14 @@ * Author: Josh Haberman <jhaberman@gmail.com> */ +#include "upb/pb/textprinter.h" + #include <ctype.h> #include <float.h> #include <inttypes.h> +#include <stdio.h> #include <stdlib.h> -#include "upb/pb/textprinter.h" +#include <string.h> struct _upb_textprinter { upb_bytesink *sink; @@ -20,7 +23,7 @@ struct _upb_textprinter { #define CHECK(x) if ((x) < 0) goto err; -static int upb_textprinter_indent(upb_textprinter *p) { +static int indent(upb_textprinter *p) { if (!p->single_line) CHECK(upb_bytesink_putrepeated(p->sink, ' ', p->indent_depth*2)); return 0; @@ -28,37 +31,32 @@ err: return -1; } -static int upb_textprinter_endfield(upb_textprinter *p) { +static int endfield(upb_textprinter *p) { CHECK(upb_bytesink_putc(p->sink, p->single_line ? ' ' : '\n')); return 0; err: return -1; } -static int upb_textprinter_putescaped(upb_textprinter *p, - const upb_byteregion *bytes, - bool preserve_utf8) { +static int putescaped(upb_textprinter *p, const char *buf, size_t len, + bool preserve_utf8) { // Based on CEscapeInternal() from Google's protobuf release. - // TODO; we could read directly from a bytesrc's buffer instead. - // TODO; we could write byteregions to the sink when possible. - char dstbuf[512], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); - char *buf = malloc(upb_byteregion_len(bytes)), *src = buf; - char *end = src + upb_byteregion_len(bytes); - upb_byteregion_copyall(bytes, buf); + char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); + const char *end = buf + len; // I think hex is prettier and more useful, but proto2 uses octal; should // investigate whether it can parse hex also. const bool use_hex = false; bool last_hex_escape = false; // true if last output char was \xNN - for (; src < end; src++) { + for (; buf < end; buf++) { if (dstend - dst < 4) { CHECK(upb_bytesink_write(p->sink, dstbuf, dst - dstbuf)); dst = dstbuf; } bool is_hex_escape = false; - switch (*src) { + switch (*buf) { case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break; case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break; case '\t': *(dst++) = '\\'; *(dst++) = 't'; break; @@ -66,123 +64,123 @@ static int upb_textprinter_putescaped(upb_textprinter *p, case '\'': *(dst++) = '\\'; *(dst++) = '\''; break; case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break; default: - // Note that if we emit \xNN and the src character after that is a hex + // Note that if we emit \xNN and the buf character after that is a hex // digit then that digit must be escaped too to prevent it being // interpreted as part of the character code by C. - if ((!preserve_utf8 || (uint8_t)*src < 0x80) && - (!isprint(*src) || (last_hex_escape && isxdigit(*src)))) { - sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*src); + if ((!preserve_utf8 || (uint8_t)*buf < 0x80) && + (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) { + sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf); is_hex_escape = use_hex; dst += 4; } else { - *(dst++) = *src; break; + *(dst++) = *buf; break; } } last_hex_escape = is_hex_escape; } // Flush remaining data. CHECK(upb_bytesink_write(p->sink, dst, dst - dstbuf)); - free(buf); return 0; err: - free(buf); return -1; } -#define TYPE(member, fmt) \ - static upb_flow_t upb_textprinter_put ## member(void *_p, upb_value fval, \ - upb_value val) { \ +#define TYPE(name, ctype, fmt) \ + static bool put ## name(void *_p, void *fval, ctype val) { \ upb_textprinter *p = _p; \ - const upb_fielddef *f = upb_value_getfielddef(fval); \ - uint64_t start_ofs = upb_bytesink_getoffset(p->sink); \ - CHECK(upb_textprinter_indent(p)); \ + const upb_fielddef *f = fval; \ + CHECK(indent(p)); \ CHECK(upb_bytesink_writestr(p->sink, upb_fielddef_name(f))); \ CHECK(upb_bytesink_writestr(p->sink, ": ")); \ - CHECK(upb_bytesink_printf(p->sink, fmt, upb_value_get ## member(val))); \ - CHECK(upb_textprinter_endfield(p)); \ - return UPB_CONTINUE; \ + CHECK(upb_bytesink_printf(p->sink, fmt, val)); \ + CHECK(endfield(p)); \ + return true; \ err: \ - upb_bytesink_rewind(p->sink, start_ofs); \ - return UPB_BREAK; \ + return false; \ } #define STRINGIFY_HELPER(x) #x #define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x) -TYPE(double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") -TYPE(float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g") -TYPE(int64, "%" PRId64) -TYPE(uint64, "%" PRIu64) -TYPE(int32, "%" PRId32) -TYPE(uint32, "%" PRIu32); -TYPE(bool, "%hhu"); +TYPE(int32, int32_t, "%" PRId32) +TYPE(int64, int64_t, "%" PRId64) +TYPE(uint32, uint32_t, "%" PRIu32); +TYPE(uint64, uint64_t, "%" PRIu64) +TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g") +TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") +TYPE(bool, bool, "%hhu"); // Output a symbolic value from the enum if found, else just print as int32. -static upb_flow_t upb_textprinter_putenum(void *_p, upb_value fval, - upb_value val) { +static bool putenum(void *_p, void *fval, int32_t val) { upb_textprinter *p = _p; - uint64_t start_ofs = upb_bytesink_getoffset(p->sink); - const upb_fielddef *f = upb_value_getfielddef(fval); - const upb_enumdef *enum_def = - upb_downcast_enumdef_const(upb_fielddef_subdef(f)); - const char *label = upb_enumdef_iton(enum_def, upb_value_getint32(val)); + const upb_fielddef *f = fval; + const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f)); + const char *label = upb_enumdef_iton(enum_def, val); if (label) { CHECK(upb_bytesink_writestr(p->sink, label)); } else { - CHECK(upb_textprinter_putint32(_p, fval, val)); + CHECK(putint32(_p, fval, val)); } - return UPB_CONTINUE; + return true; err: - upb_bytesink_rewind(p->sink, start_ofs); - return UPB_BREAK; + return false; } -static upb_flow_t upb_textprinter_putstr(void *_p, upb_value fval, - upb_value val) { +static void *startstr(void *_p, void *fval, size_t size_hint) { + UPB_UNUSED(size_hint); + UPB_UNUSED(fval); upb_textprinter *p = _p; - uint64_t start_ofs = upb_bytesink_getoffset(p->sink); - const upb_fielddef *f = upb_value_getfielddef(fval); - CHECK(upb_bytesink_putc(p->sink, '"')); - CHECK(upb_textprinter_putescaped(p, upb_value_getbyteregion(val), - f->type == UPB_TYPE(STRING))); CHECK(upb_bytesink_putc(p->sink, '"')); - return UPB_CONTINUE; + return p; err: - upb_bytesink_rewind(p->sink, start_ofs); return UPB_BREAK; } -static upb_sflow_t upb_textprinter_startsubmsg(void *_p, upb_value fval) { +static bool endstr(void *_p, void *fval) { + UPB_UNUSED(fval); + upb_textprinter *p = _p; + CHECK(upb_bytesink_putc(p->sink, '"')); + return true; +err: + return false; +} + +static size_t putstr(void *_p, void *fval, const char *buf, size_t len) { upb_textprinter *p = _p; - uint64_t start_ofs = upb_bytesink_getoffset(p->sink); - const upb_fielddef *f = upb_value_getfielddef(fval); - CHECK(upb_textprinter_indent(p)); + const upb_fielddef *f = fval; + CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE(STRING))); + return len; +err: + return 0; +} + +static void *startsubmsg(void *_p, void *fval) { + upb_textprinter *p = _p; + const upb_fielddef *f = fval; + CHECK(indent(p)); CHECK(upb_bytesink_printf(p->sink, "%s {", upb_fielddef_name(f))); if (!p->single_line) CHECK(upb_bytesink_putc(p->sink, '\n')); p->indent_depth++; - return UPB_CONTINUE_WITH(_p); + return _p; err: - upb_bytesink_rewind(p->sink, start_ofs); - return UPB_SBREAK; + return UPB_BREAK; } -static upb_flow_t upb_textprinter_endsubmsg(void *_p, upb_value fval) { - (void)fval; +static bool endsubmsg(void *_p, void *fval) { + UPB_UNUSED(fval); upb_textprinter *p = _p; - uint64_t start_ofs = upb_bytesink_getoffset(p->sink); p->indent_depth--; - CHECK(upb_textprinter_indent(p)); + CHECK(indent(p)); CHECK(upb_bytesink_putc(p->sink, '}')); - CHECK(upb_textprinter_endfield(p)); - return UPB_CONTINUE; + CHECK(endfield(p)); + return true; err: - upb_bytesink_rewind(p->sink, start_ofs); - return UPB_BREAK; + return false; } -upb_textprinter *upb_textprinter_new(void) { +upb_textprinter *upb_textprinter_new() { upb_textprinter *p = malloc(sizeof(*p)); return p; } @@ -196,22 +194,61 @@ void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, p->indent_depth = 0; } -static void upb_textprinter_onfreg(void *c, upb_fhandlers *fh, const upb_fielddef *f) { +static void onmreg(void *c, upb_handlers *h) { (void)c; - upb_fhandlers_setstartsubmsg(fh, &upb_textprinter_startsubmsg); - upb_fhandlers_setendsubmsg(fh, &upb_textprinter_endsubmsg); -#define F(type) &upb_textprinter_put ## type - static upb_value_handler *fptrs[] = {NULL, F(double), F(float), F(int64), - F(uint64), F(int32), F(uint64), F(uint32), F(bool), F(str), - NULL, NULL, F(str), F(uint32), F(enum), F(int32), - F(int64), F(int32), F(int64)}; - upb_fhandlers_setvalue(fh, fptrs[f->type]); - upb_value fval; - upb_value_setfielddef(&fval, f); - upb_fhandlers_setfval(fh, fval); + const upb_msgdef *m = upb_handlers_msgdef(h); + upb_msg_iter i; + for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { + upb_fielddef *f = upb_msg_iter_field(&i); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_SINT32: + case UPB_TYPE_SFIXED32: + upb_handlers_setint32(h, f, putint32, f, NULL); + break; + case UPB_TYPE_SINT64: + case UPB_TYPE_SFIXED64: + case UPB_TYPE_INT64: + upb_handlers_setint64(h, f, putint64, f, NULL); + break; + case UPB_TYPE_UINT32: + case UPB_TYPE_FIXED32: + upb_handlers_setuint32(h, f, putuint32, f, NULL); + break; + case UPB_TYPE_UINT64: + case UPB_TYPE_FIXED64: + upb_handlers_setuint64(h, f, putuint64, f, NULL); + break; + case UPB_TYPE_FLOAT: + upb_handlers_setfloat(h, f, putfloat, f, NULL); + break; + case UPB_TYPE_DOUBLE: + upb_handlers_setdouble(h, f, putdouble, f, NULL); + break; + case UPB_TYPE_BOOL: + upb_handlers_setbool(h, f, putbool, f, NULL); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + upb_handlers_setstartstr(h, f, startstr, f, NULL); + upb_handlers_setstring(h, f, putstr, f, NULL); + upb_handlers_setendstr(h, f, endstr, f, NULL); + break; + case UPB_TYPE_GROUP: + case UPB_TYPE_MESSAGE: + upb_handlers_setstartsubmsg(h, f, &startsubmsg, f, NULL); + upb_handlers_setendsubmsg(h, f, &endsubmsg, f, NULL); + break; + case UPB_TYPE_ENUM: + upb_handlers_setint32(h, f, putenum, f, NULL); + default: + assert(false); + break; + } + } } -upb_mhandlers *upb_textprinter_reghandlers(upb_handlers *h, const upb_msgdef *m) { - return upb_handlers_regmsgdef( - h, m, NULL, &upb_textprinter_onfreg, NULL); +const upb_handlers *upb_textprinter_newhandlers(const void *owner, + const upb_msgdef *m) { + return upb_handlers_newfrozen(m, owner, &onmreg, NULL); } |