148 lines
3.6 KiB
C++
148 lines
3.6 KiB
C++
/*-------------------------------------------------------------------------
|
|
*
|
|
* json.c: - make json document.
|
|
*
|
|
* Copyright (c) 2018-2019, Postgres Professional
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "json.h"
|
|
|
|
static void json_add_indent(PQExpBuffer buf, int32 level);
|
|
static void json_add_escaped(PQExpBuffer buf, const char *str);
|
|
|
|
static bool add_comma = false;
|
|
|
|
/*
|
|
* Start or end json token. Currently it is a json object or array.
|
|
*
|
|
* Function modifies level value and adds indent if it appropriate.
|
|
*/
|
|
void
|
|
json_add(PQExpBuffer buf, JsonToken type, int32 *level)
|
|
{
|
|
switch (type)
|
|
{
|
|
case JT_BEGIN_ARRAY:
|
|
appendPQExpBufferChar(buf, '[');
|
|
*level += 1;
|
|
add_comma = false;
|
|
break;
|
|
case JT_END_ARRAY:
|
|
*level -= 1;
|
|
if (*level == 0)
|
|
appendPQExpBufferChar(buf, '\n');
|
|
else
|
|
json_add_indent(buf, *level);
|
|
appendPQExpBufferChar(buf, ']');
|
|
add_comma = true;
|
|
break;
|
|
case JT_BEGIN_OBJECT:
|
|
json_add_indent(buf, *level);
|
|
appendPQExpBufferChar(buf, '{');
|
|
*level += 1;
|
|
add_comma = false;
|
|
break;
|
|
case JT_END_OBJECT:
|
|
*level -= 1;
|
|
if (*level == 0)
|
|
appendPQExpBufferChar(buf, '\n');
|
|
else
|
|
json_add_indent(buf, *level);
|
|
appendPQExpBufferChar(buf, '}');
|
|
add_comma = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add json object's key. If it isn't first key we need to add a comma.
|
|
*/
|
|
void
|
|
json_add_key(PQExpBuffer buf, const char *name, int32 level)
|
|
{
|
|
if (add_comma)
|
|
appendPQExpBufferChar(buf, ',');
|
|
json_add_indent(buf, level);
|
|
|
|
json_add_escaped(buf, name);
|
|
appendPQExpBufferStr(buf, ": ");
|
|
|
|
add_comma = true;
|
|
}
|
|
|
|
/*
|
|
* Add json object's key and value. If it isn't first key we need to add a
|
|
* comma.
|
|
*/
|
|
void
|
|
json_add_value(PQExpBuffer buf, const char *name, const char *value,
|
|
int32 level, bool escaped)
|
|
{
|
|
json_add_key(buf, name, level);
|
|
|
|
if (escaped)
|
|
json_add_escaped(buf, value);
|
|
else
|
|
appendPQExpBufferStr(buf, value);
|
|
}
|
|
|
|
static void
|
|
json_add_indent(PQExpBuffer buf, int32 level)
|
|
{
|
|
uint16 i;
|
|
|
|
if (level == 0)
|
|
return;
|
|
|
|
appendPQExpBufferChar(buf, '\n');
|
|
for (i = 0; i < level; i++)
|
|
appendPQExpBufferStr(buf, " ");
|
|
}
|
|
|
|
static void
|
|
json_add_escaped(PQExpBuffer buf, const char *str)
|
|
{
|
|
const char *p;
|
|
|
|
appendPQExpBufferChar(buf, '"');
|
|
for (p = str; *p; p++)
|
|
{
|
|
switch (*p)
|
|
{
|
|
case '\b':
|
|
appendPQExpBufferStr(buf, "\\b");
|
|
break;
|
|
case '\f':
|
|
appendPQExpBufferStr(buf, "\\f");
|
|
break;
|
|
case '\n':
|
|
appendPQExpBufferStr(buf, "\\n");
|
|
break;
|
|
case '\r':
|
|
appendPQExpBufferStr(buf, "\\r");
|
|
break;
|
|
case '\t':
|
|
appendPQExpBufferStr(buf, "\\t");
|
|
break;
|
|
case '"':
|
|
appendPQExpBufferStr(buf, "\\\"");
|
|
break;
|
|
case '\\':
|
|
appendPQExpBufferStr(buf, "\\\\");
|
|
break;
|
|
default:
|
|
if ((unsigned char) *p < ' ')
|
|
appendPQExpBuffer(buf, "\\u%04x", (int) *p);
|
|
else
|
|
appendPQExpBufferChar(buf, *p);
|
|
break;
|
|
}
|
|
}
|
|
appendPQExpBufferChar(buf, '"');
|
|
}
|
|
|