summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_conf_json.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/nxt_conf_json.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/src/nxt_conf_json.c b/src/nxt_conf_json.c
index cf0190f4..109edf22 100644
--- a/src/nxt_conf_json.c
+++ b/src/nxt_conf_json.c
@@ -69,6 +69,20 @@ static u_char *nxt_conf_json_parse_number(u_char *pos, u_char *end,
nxt_conf_json_value_t *value, nxt_mem_pool_t *pool);
+static uintptr_t nxt_conf_json_print_value(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_integer(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_string(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_array(u_char *pos,
+ nxt_conf_json_value_t *value);
+static uintptr_t nxt_conf_json_print_object(u_char *pos,
+ nxt_conf_json_value_t *value);
+
+static uintptr_t nxt_conf_json_escape(u_char *dst, u_char *src, size_t size);
+
+
static const nxt_lvlhsh_proto_t nxt_conf_json_object_hash_proto
nxt_aligned(64) =
{
@@ -774,3 +788,318 @@ nxt_conf_json_parse_number(u_char *pos, u_char *end,
return NULL;
}
+
+
+nxt_buf_t *
+nxt_conf_json_print(nxt_conf_json_value_t *value, nxt_mem_pool_t *pool)
+{
+ size_t size;
+ nxt_buf_t *b;
+
+ size = nxt_conf_json_print_value(NULL, value);
+
+ b = nxt_buf_mem_alloc(pool, size, 0);
+ if (nxt_slow_path(b == NULL)) {
+ return NULL;
+ }
+
+ b->mem.free = (u_char *) nxt_conf_json_print_value(b->mem.free, value);
+
+ return b;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_value(u_char *pos, nxt_conf_json_value_t *value)
+{
+ static const u_char null[4] = "null";
+ static const u_char true[4] = "true";
+ static const u_char false[5] = "false";
+
+ switch (value->type) {
+
+ case NXT_CONF_JSON_NULL:
+
+ if (pos == NULL) {
+ return sizeof(null);
+ }
+
+ return (uintptr_t) nxt_cpymem(pos, null, sizeof(null));
+
+ case NXT_CONF_JSON_BOOLEAN:
+
+ if (pos == NULL) {
+ return value->u.boolean ? 4 : 5;
+ }
+
+ if (value->u.boolean) {
+ return (uintptr_t) nxt_cpymem(pos, true, sizeof(true));
+ }
+
+ return (uintptr_t) nxt_cpymem(pos, false, sizeof(false));
+
+ case NXT_CONF_JSON_INTEGER:
+ return nxt_conf_json_print_integer(pos, value);
+
+ case NXT_CONF_JSON_NUMBER:
+ /* TODO */
+ return (pos == NULL) ? 0 : (uintptr_t) pos;
+
+ case NXT_CONF_JSON_SHORT_STRING:
+ case NXT_CONF_JSON_STRING:
+ return nxt_conf_json_print_string(pos, value);
+
+ case NXT_CONF_JSON_ARRAY:
+ return nxt_conf_json_print_array(pos, value);
+
+ case NXT_CONF_JSON_OBJECT:
+ return nxt_conf_json_print_object(pos, value);
+ }
+
+ nxt_unreachable();
+
+ return (pos == NULL) ? 0 : (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_integer(u_char *pos, nxt_conf_json_value_t *value)
+{
+ int64_t num;
+
+ num = value->u.integer;
+
+ if (pos == NULL) {
+ num = llabs(num);
+
+ if (num <= 9999) {
+ return sizeof("-9999") - 1;
+ }
+
+ if (num <= 99999999999) {
+ return sizeof("-99999999999") - 1;
+ }
+
+ return NXT_INT64_T_LEN;
+ }
+
+ return (uintptr_t) nxt_sprintf(pos, pos + NXT_INT64_T_LEN, "%L", num);
+}
+
+
+static uintptr_t
+nxt_conf_json_print_string(u_char *pos, nxt_conf_json_value_t *value)
+{
+ size_t len;
+ u_char *s;
+
+ if (value->type == NXT_CONF_JSON_SHORT_STRING) {
+ len = value->u.str[0];
+ s = &value->u.str[1];
+
+ } else {
+ len = value->u.string->length;
+ s = value->u.string->start;
+ }
+
+ if (pos == NULL) {
+ return 2 + len + nxt_conf_json_escape(NULL, s, len);
+ }
+
+ *pos++ = '"';
+
+ pos = (u_char *) nxt_conf_json_escape(pos, s, len);
+
+ *pos++ = '"';
+
+ return (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_array(u_char *pos, nxt_conf_json_value_t *value)
+{
+ size_t len;
+ uint32_t n;
+ nxt_array_t *array;
+
+ array = value->u.array;
+
+ if (pos == NULL) {
+ len = 2;
+
+ value = array->elts;
+
+ for (n = 0; n < array->nelts; n++) {
+ len += nxt_conf_json_print_value(NULL, &value[n]);
+ }
+
+ return n + len;
+ }
+
+ *pos++ = '[';
+
+ if (array->nelts != 0) {
+ value = array->elts;
+
+ pos = (u_char *) nxt_conf_json_print_value(pos, &value[0]);
+
+ for (n = 1; n < array->nelts; n++) {
+ *pos++ = ',';
+ pos = (u_char *) nxt_conf_json_print_value(pos, &value[n]);
+ }
+ }
+
+ *pos++ = ']';
+
+ return (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_print_object(u_char *pos, nxt_conf_json_value_t *value)
+{
+ size_t len;
+ nxt_lvlhsh_t *object;
+ nxt_lvlhsh_each_t lhe;
+ nxt_conf_json_obj_member_t *member;
+
+ nxt_memzero(&lhe, sizeof(nxt_lvlhsh_each_t));
+
+ lhe.proto = &nxt_conf_json_object_hash_proto;
+
+ object = value->u.object;
+
+ if (pos == NULL) {
+ len = 2;
+
+ for ( ;; ) {
+ member = nxt_lvlhsh_each(object, &lhe);
+
+ if (member == NULL) {
+ break;
+ }
+
+ len += nxt_conf_json_print_string(NULL, &member->name) + 1
+ + nxt_conf_json_print_value(NULL, &member->value) + 1;
+ }
+
+ return len;
+ }
+
+ *pos++ = '{';
+
+ member = nxt_lvlhsh_each(object, &lhe);
+
+ if (member != NULL) {
+
+ for ( ;; ) {
+ pos = (u_char *) nxt_conf_json_print_string(pos, &member->name);
+
+ *pos++ = ':';
+
+ pos = (u_char *) nxt_conf_json_print_value(pos, &member->value);
+
+ member = nxt_lvlhsh_each(object, &lhe);
+
+ if (member == NULL) {
+ break;
+ }
+
+ *pos++ = ',';
+ }
+ }
+
+ *pos++ = '}';
+
+ return (uintptr_t) pos;
+}
+
+
+static uintptr_t
+nxt_conf_json_escape(u_char *dst, u_char *src, size_t size)
+{
+ u_char ch;
+ size_t len;
+
+ if (dst == NULL) {
+ len = 0;
+
+ while (size) {
+ ch = *src++;
+
+ if (ch == '\\' || ch == '"') {
+ len++;
+
+ } else if (ch <= 0x1f) {
+
+ switch (ch) {
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\b':
+ case '\f':
+ len++;
+ break;
+
+ default:
+ len += sizeof("\\u001F") - 2;
+ }
+ }
+
+ size--;
+ }
+
+ return len;
+ }
+
+ while (size) {
+ ch = *src++;
+
+ if (ch > 0x1f) {
+
+ if (ch == '\\' || ch == '"') {
+ *dst++ = '\\';
+ }
+
+ *dst++ = ch;
+
+ } else {
+ *dst++ = '\\';
+
+ switch (ch) {
+ case '\n':
+ *dst++ = 'n';
+ break;
+
+ case '\r':
+ *dst++ = 'r';
+ break;
+
+ case '\t':
+ *dst++ = 't';
+ break;
+
+ case '\b':
+ *dst++ = 'b';
+ break;
+
+ case '\f':
+ *dst++ = 'f';
+ break;
+
+ default:
+ *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
+ *dst++ = '0' + (ch >> 4);
+
+ ch &= 0xf;
+
+ *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
+ }
+ }
+
+ size--;
+ }
+
+ return (uintptr_t) dst;
+}