summaryrefslogtreecommitdiff
path: root/upb/pb/textprinter.c
diff options
context:
space:
mode:
Diffstat (limited to 'upb/pb/textprinter.c')
-rw-r--r--upb/pb/textprinter.c217
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);
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback