plong

Unnamed repository; edit this file 'description' to name the repository.
git clone https://git.inz.fi/plong
Log | Files | Refs

json.c (4493B)


      1 #include <errno.h>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include "json.h"
      5 
      6 enum mode {
      7 	MODE_NONE = 0,
      8 	MODE_OBJECT_FIRST,
      9 	MODE_OBJECT,
     10 	MODE_OBJECT_VALUE,
     11 	MODE_ARRAY_FIRST,
     12 	MODE_ARRAY,
     13 };
     14 
     15 static enum mode _json_mode(struct json *j)
     16 {
     17 	if (j->depth == 0)
     18 		return MODE_NONE;
     19 	return j->modes[j->depth - 1];
     20 }
     21 
     22 static int _json_kw(struct json *j, const char *value, size_t vl)
     23 {
     24 	int r;
     25 
     26 	switch (_json_mode(j)) {
     27 	case MODE_ARRAY:
     28 		if ((r = buf_char(&j->b, ',')))
     29 			return r;
     30 		break;
     31 
     32 	case MODE_ARRAY_FIRST:
     33 		j->modes[j->depth - 1] = MODE_ARRAY;
     34 		break;
     35 
     36 	case MODE_OBJECT_VALUE:
     37 		j->modes[j->depth - 1] = MODE_OBJECT;
     38 		break;
     39 
     40 	default:
     41 		return EINVAL;
     42 	}
     43 
     44 	if (j->b.data + vl >= j->b.end)
     45 		return ENOMEM;
     46 	memcpy(j->b.data, value, vl);
     47 	j->b.data += vl;
     48 
     49 	return 0;
     50 }
     51 
     52 int _json_string(struct json *j, const char *value)
     53 {
     54 	int r;
     55 
     56 	switch (_json_mode(j)) {
     57 	case MODE_ARRAY:
     58 	case MODE_OBJECT:
     59 		if ((r = buf_char(&j->b, ',')))
     60 			return r;
     61 		break;
     62 
     63 	case MODE_ARRAY_FIRST:
     64 		j->modes[j->depth - 1] = MODE_ARRAY;
     65 		break;
     66 
     67 	case MODE_OBJECT_FIRST:
     68 	case MODE_OBJECT_VALUE:
     69 		break;
     70 
     71 	default:
     72 		return EINVAL;
     73 	}
     74 
     75 	if ((r = buf_char(&j->b, '"')))
     76 		return r;
     77 	for (; *value; value++) {
     78 		char c;
     79 		switch (*value) {
     80 		case '\r':
     81 			c = 'r';
     82 			break;
     83 		case '\n':
     84 			c = 'n';
     85 			break;
     86 		case '\b':
     87 			c = 'b';
     88 			break;
     89 		case '\f':
     90 			c = 'f';
     91 			break;
     92 
     93 		case '\\':
     94 		case '"':
     95 			c = *value;
     96 			break;
     97 
     98 		default:
     99 			if ((r = buf_char(&j->b, *value)))
    100 				return ENOMEM;
    101 			continue;
    102 		}
    103 		if ((r = buf_char(&j->b, '\\')) ||
    104 		    (r = buf_char(&j->b, c)))
    105 			return ENOMEM;
    106 	}
    107 
    108 	return buf_char(&j->b, '"');
    109 }
    110 
    111 int json_init(struct json *j, struct buf *b)
    112 {
    113 	j->b = *b;
    114 	j->buffer = b->data;
    115 	j->depth = 0;
    116 
    117 	return 0;
    118 }
    119 
    120 int json_obj_open(struct json *j)
    121 {
    122 	int r;
    123 
    124 	switch (_json_mode(j)) {
    125 	case MODE_OBJECT_FIRST:
    126 	case MODE_OBJECT:
    127 		return EINVAL;
    128 
    129 	case MODE_ARRAY:
    130 		if ((r = buf_char(&j->b, ',')))
    131 			return r;
    132 		break;
    133 
    134 	default:
    135 		break;
    136 	}
    137 
    138 	if (&j->modes[j->depth] == 1[&j->modes])
    139 		return ENOMEM;
    140 	j->modes[j->depth++] = MODE_OBJECT_FIRST;
    141 	return buf_char(&j->b, '{');
    142 }
    143 
    144 int json_obj_close(struct json *j)
    145 {
    146 	switch (_json_mode(j)) {
    147 	case MODE_OBJECT_FIRST:
    148 	case MODE_OBJECT:
    149 		break;
    150 
    151 	default:
    152 		return EINVAL;
    153 	}
    154 
    155 	j->depth--;
    156 	if (_json_mode(j) == MODE_OBJECT_VALUE)
    157 		j->modes[j->depth - 1] = MODE_OBJECT;
    158 	return buf_char(&j->b, '}');
    159 }
    160 
    161 int json_string(struct json *j, const char *value)
    162 {
    163 	int r;
    164 
    165 	switch (_json_mode(j)) {
    166 	case MODE_OBJECT_FIRST:
    167 	case MODE_OBJECT:
    168 		return EINVAL;
    169 
    170 	default:
    171 		break;
    172 	}
    173 
    174 	if ((r = _json_string(j, value)))
    175 		return r;
    176 	if (_json_mode(j) == MODE_OBJECT_VALUE)
    177 		j->modes[j->depth - 1] = MODE_OBJECT;
    178 	return 0;
    179 }
    180 
    181 int json_obj_key(struct json *j, const char *key)
    182 {
    183 	int r;
    184 
    185 	switch (_json_mode(j)) {
    186 	case MODE_OBJECT:
    187 	case MODE_OBJECT_FIRST:
    188 		break;
    189 
    190 	default:
    191 		return EINVAL;
    192 	}
    193 
    194 	if ((r = _json_string(j, key)))
    195 		return r;
    196 	j->modes[j->depth - 1] = MODE_OBJECT_VALUE;
    197 	return buf_char(&j->b, ':');
    198 }
    199 
    200 int json_arr_open(struct json *j) {
    201 	int r;
    202 
    203 	switch (_json_mode(j)) {
    204 	case MODE_OBJECT_FIRST:
    205 	case MODE_OBJECT:
    206 		return EINVAL;
    207 
    208 	case MODE_ARRAY:
    209 		if ((r = buf_char(&j->b, ',')))
    210 			return r;
    211 		break;
    212 
    213 	default:
    214 		break;
    215 	}
    216 
    217 	if (&j->modes[j->depth] == 1[&j->modes])
    218 		return ENOMEM;
    219 	j->modes[j->depth++] = MODE_ARRAY_FIRST;
    220 	return buf_char(&j->b, '[');
    221 }
    222 
    223 int json_arr_close(struct json *j)
    224 {
    225 	switch (_json_mode(j)) {
    226 	case MODE_ARRAY_FIRST:
    227 	case MODE_ARRAY:
    228 		break;
    229 
    230 	default:
    231 		return EINVAL;
    232 	}
    233 
    234 	j->depth--;
    235 	if (_json_mode(j) == MODE_OBJECT_VALUE)
    236 		j->modes[j->depth - 1] = MODE_OBJECT;
    237 	return buf_char(&j->b, ']');
    238 }
    239 
    240 int json_bool(struct json *j, int v)
    241 {
    242 	if (v)
    243 		return _json_kw(j, "true", sizeof("true") - 1);
    244 	return _json_kw(j, "false", sizeof("false") - 1);
    245 }
    246 
    247 int json_null(struct json *j)
    248 {
    249 	return _json_kw(j, "null", sizeof("null") - 1);
    250 }
    251 
    252 int json_int(struct json *j, intmax_t val)
    253 {
    254 	int r;
    255 
    256 	switch (_json_mode(j)) {
    257 	case MODE_ARRAY:
    258 		if ((r = buf_char(&j->b, ',')))
    259 			return r;
    260 		break;
    261 
    262 	case MODE_ARRAY_FIRST:
    263 		j->modes[j->depth - 1] = MODE_ARRAY;
    264 		break;
    265 
    266 	case MODE_OBJECT_VALUE:
    267 		j->modes[j->depth - 1] = MODE_OBJECT;
    268 		break;
    269 
    270 	default:
    271 		return EINVAL;
    272 	}
    273 
    274 	r = snprintf(j->b.data, j->b.end - j->b.data, "%jd", val);
    275 	if (j->b.data + r >= j->b.end - 1)
    276 		return ENOMEM;
    277 	j->b.data += r;
    278 
    279 	return 0;
    280 }
    281 
    282 int json_fini(struct json *j, struct buf *b)
    283 {
    284 	if (j->depth != 0)
    285 		return EINVAL;
    286 	b->data = j->buffer;
    287 	b->end = j->b.data;
    288 
    289 	return 0;
    290 }
    291