Annotation of libelwix/src/json.c, revision 1.2
1.2 ! misho 1: /*************************************************************************
! 2: * (C) 2017 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
! 3: * by Michael Pounov <misho@elwix.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: json.c,v 1.1.2.11 2017/11/30 13:45:38 misho Exp $
! 7: *
! 8: **************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004 - 2017
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
! 46: #include "global.h"
! 47:
! 48:
! 49: /* JSON error strings */
! 50: const char *jerrstr[] = {
! 51: "No error",
! 52: "Not enough tokens were provided",
! 53: "Invalid character",
! 54: "JSON string isn't full",
! 55: "Invalid parameter",
! 56: NULL
! 57: };
! 58:
! 59:
! 60: /*
! 61: * json_init() - Initialize JSON handler
! 62: *
! 63: * @json = JSON handler, if there is NULL then dynamically will be allocated
! 64: * @jstrict = JSON strict mode, when we select strict mode every unquoted value is error
! 65: * return: =NULL error or !=NULL ready for use JSON handler and should be free with json_free()
! 66: */
! 67: json_t *
! 68: json_init(json_t * __restrict json, int jstrict)
! 69: {
! 70: json_t *j = json;
! 71:
! 72: if (!j) {
! 73: j = e_malloc(sizeof(json_t));
! 74: if (!j) {
! 75: LOGERR;
! 76: return NULL;
! 77: }
! 78: }
! 79:
! 80: memset(j, 0, sizeof(json_t));
! 81: j->h_parent = -1;
! 82: j->h_strict = jstrict;
! 83:
! 84: /* handler is dynamically allocated! */
! 85: if (!json)
! 86: j->h_alloc = j;
! 87:
! 88: return j;
! 89: }
! 90:
! 91: /*
! 92: * json_free() - Free JSON handler
! 93: *
! 94: * @json = JSON handler
! 95: * return: none
! 96: */
! 97: void
! 98: json_free(json_t * __restrict json)
! 99: {
! 100: if (json) {
! 101: if (json->h_alloc)
! 102: e_free(json);
! 103: else
! 104: memset(json, 0, sizeof(json_t));
! 105: }
! 106: }
! 107:
! 108: static jtok_t *
! 109: json_gettoken(json_t * __restrict json, jtok_t * __restrict jtoks, u_int toksnum)
! 110: {
! 111: jtok_t *tok;
! 112:
! 113: assert(json || !(!jtoks && toksnum));
! 114:
! 115: if (json->h_next >= toksnum) {
! 116: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 117: return NULL;
! 118: } else
! 119: tok = &jtoks[json->h_next];
! 120: tok->tok_idx = json->h_next++;
! 121: tok->tok_start = tok->tok_end = tok->tok_parent = -1;
! 122: tok->tok_size = 0;
! 123:
! 124: return tok;
! 125: }
! 126:
! 127: inline void
! 128: json_filltoken(jtok_t * __restrict tok, jtype_t type, long start, long end, long parent)
! 129: {
! 130: assert(tok);
! 131:
! 132: tok->tok_type = type;
! 133: tok->tok_start = start;
! 134: tok->tok_end = end;
! 135: tok->tok_parent = parent;
! 136: tok->tok_size = 0;
! 137: }
! 138:
! 139: static int
! 140: json_parse_string(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
! 141: {
! 142: jtok_t *tok;
! 143: u_long pos;
! 144: char ch;
! 145: register int i;
! 146:
! 147: assert(json || jstr || !(!jtoks && toksnum));
! 148:
! 149: for (pos = json->h_pos++; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
! 150: ch = jstr[json->h_pos];
! 151:
! 152: if (ch == '\"') {
! 153: if (!jtoks)
! 154: return 0;
! 155: if (!(tok = json_gettoken(json, jtoks, toksnum))) {
! 156: json->h_pos = pos;
! 157: return -1;
! 158: } else
! 159: json_filltoken(tok, J_STRING, pos + 1, json->h_pos, json->h_parent);
! 160: return 0;
! 161: }
! 162:
! 163: if (ch == '\\' && json->h_pos + 1 < jlen) {
! 164: switch (jstr[++json->h_pos]) {
! 165: case '\"':
! 166: case '/':
! 167: case '\\':
! 168: case 'b':
! 169: case 'f':
! 170: case 'r':
! 171: case 'n':
! 172: case 't':
! 173: /* Allowed escaped symbols */
! 174: break;
! 175: case 'u':
! 176: /* Allows escaped symbol \uXXXX */
! 177: json->h_pos++;
! 178: for (i = 0; i < 4 && json->h_pos < jlen && jstr[json->h_pos]; i++, json->h_pos++) {
! 179: /* If it isn't a hex character we have an error */
! 180: if (!((jstr[json->h_pos] >= 48 && jstr[json->h_pos] <= 57) || /* 0-9 */
! 181: (jstr[json->h_pos] >= 65 && jstr[json->h_pos] <= 70) || /* A-F */
! 182: (jstr[json->h_pos] >= 97 && jstr[json->h_pos] <= 102))) { /* a-f */
! 183: json->h_pos = pos;
! 184: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 185: return -1;
! 186: }
! 187: }
! 188: json->h_pos--;
! 189: break;
! 190: default:
! 191: /* Unexpected symbol */
! 192: json->h_pos = pos;
! 193: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 194: return -1;
! 195: }
! 196: }
! 197: }
! 198:
! 199: json->h_pos = pos;
! 200: elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
! 201: return -1;
! 202: }
! 203:
! 204: static int
! 205: json_parse_value(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
! 206: {
! 207: jtok_t *tok;
! 208: u_long pos;
! 209:
! 210: assert(json || jstr || !(!jtoks && toksnum));
! 211:
! 212: for (pos = json->h_pos; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
! 213: switch (jstr[json->h_pos]) {
! 214: case ':':
! 215: if (json->h_strict)
! 216: goto found;
! 217: break;
! 218: case '\t':
! 219: case '\r':
! 220: case '\n':
! 221: case ' ':
! 222: case ',':
! 223: case ']':
! 224: case '}':
! 225: goto found;
! 226: }
! 227: if (jstr[json->h_pos] < 32 || jstr[json->h_pos] > 127) {
! 228: json->h_pos = pos;
! 229: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 230: return -1;
! 231: }
! 232: }
! 233:
! 234: if (json->h_strict) {
! 235: json->h_pos = pos;
! 236: elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
! 237: return -1;
! 238: }
! 239: found:
! 240: if (jtoks) {
! 241: if (!(tok = json_gettoken(json, jtoks, toksnum))) {
! 242: json->h_pos = pos;
! 243: return -1;
! 244: } else
! 245: json_filltoken(tok, J_VALUE, pos, json->h_pos, json->h_parent);
! 246: }
! 247:
! 248: json->h_pos--;
! 249: return 0;
! 250: }
! 251:
! 252: /*
! 253: * json_parse() - Parse JSON string
! 254: *
! 255: * @json = JSON handler
! 256: * @jstr = JSON string
! 257: * @jlen = JSON string length
! 258: * @jtoks = Token array
! 259: * @toksnum = Token array size, return number of allocated tokens in array
! 260: * return: -1 error or number of found tokens
! 261: */
! 262: u_int
! 263: json_parse(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
! 264: {
! 265: register int i;
! 266: register u_int cx;
! 267: jtype_t type;
! 268: jtok_t *tok;
! 269: char ch;
! 270:
! 271: if (!json || !jstr || (!jtoks && toksnum)) {
! 272: elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
! 273: return (u_int) -1;
! 274: }
! 275:
! 276: for (cx = json->h_next; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
! 277: switch ((ch = jstr[json->h_pos])) {
! 278: case '{':
! 279: case '[':
! 280: cx++; /* start new object/array token */
! 281: if (!jtoks)
! 282: break;
! 283:
! 284: tok = json_gettoken(json, jtoks, toksnum);
! 285: if (!tok)
! 286: return (u_int) -1;
! 287: if (json->h_parent != -1) {
! 288: jtoks[json->h_parent].tok_size++;
! 289: tok->tok_parent = json->h_parent;
! 290: }
! 291: tok->tok_type = (ch == '{' ? J_OBJECT : J_ARRAY);
! 292: tok->tok_start = json->h_pos;
! 293: json->h_parent = json->h_next - 1;
! 294: break;
! 295: case '}':
! 296: case ']':
! 297: if (!jtoks)
! 298: break;
! 299:
! 300: if (json->h_next < 1) {
! 301: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 302: return (u_int) -1;
! 303: }
! 304:
! 305: type = (ch == '}' ? J_OBJECT : J_ARRAY);
! 306: tok = &jtoks[json->h_next - 1];
! 307: while (42) {
! 308: if (tok->tok_start != -1 && tok->tok_end == -1) {
! 309: if (tok->tok_type != type) {
! 310: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 311: return (u_int) -1;
! 312: }
! 313: tok->tok_end = json->h_pos + 1;
! 314: json->h_parent = tok->tok_parent;
! 315: break;
! 316: }
! 317: if (tok->tok_parent == -1) {
! 318: if (tok->tok_type != type || json->h_parent == -1) {
! 319: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 320: return (u_int) -1;
! 321: }
! 322: break;
! 323: }
! 324: tok = &jtoks[tok->tok_parent];
! 325: }
! 326: break;
! 327: case '\"':
! 328: if (json_parse_string(json, jstr, jlen, jtoks, toksnum) == -1)
! 329: return (u_int) -1;
! 330: cx++; /* start new string token */
! 331: if (jtoks && json->h_parent != -1)
! 332: jtoks[json->h_parent].tok_size++;
! 333: break;
! 334: case '\t':
! 335: case '\r':
! 336: case '\n':
! 337: case ' ':
! 338: /* whitespace, skip */
! 339: break;
! 340: case ':':
! 341: json->h_parent = json->h_next - 1;
! 342: break;
! 343: case ',':
! 344: if (jtoks && json->h_parent != -1 &&
! 345: jtoks[json->h_parent].tok_type != J_OBJECT &&
! 346: jtoks[json->h_parent].tok_type != J_ARRAY)
! 347: json->h_parent = jtoks[json->h_parent].tok_parent;
! 348: break;
! 349: case '-':
! 350: case '0':
! 351: case '1':
! 352: case '2':
! 353: case '3':
! 354: case '4':
! 355: case '5':
! 356: case '6':
! 357: case '7':
! 358: case '8':
! 359: case '9':
! 360: case 't':
! 361: case 'f':
! 362: case 'n':
! 363: if (json->h_strict) {
! 364: if (jtoks && json->h_parent != -1) {
! 365: /* they must not be keys of the object */
! 366: if (jtoks[json->h_parent].tok_type == J_OBJECT ||
! 367: (jtoks[json->h_parent].tok_type == J_STRING &&
! 368: jtoks[json->h_parent].tok_size)) {
! 369: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 370: return (u_int) -1;
! 371: }
! 372: }
! 373:
! 374: if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
! 375: return (u_int) -1;
! 376: cx++; /* start new value token */
! 377: if (jtoks && json->h_parent != -1)
! 378: jtoks[json->h_parent].tok_size++;
! 379: break;
! 380: }
! 381: default:
! 382: if (json->h_strict) {
! 383: elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
! 384: return (u_int) -1;
! 385: }
! 386:
! 387: if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
! 388: return (u_int) -1;
! 389: cx++; /* start new value token */
! 390: if (jtoks && json->h_parent != -1)
! 391: jtoks[json->h_parent].tok_size++;
! 392: break;
! 393: }
! 394: }
! 395:
! 396: if (jtoks) {
! 397: for (i = json->h_next - 1; i >= 0; i--) {
! 398: /* unmatched opened object or array */
! 399: if (jtoks[i].tok_start != -1 && jtoks[i].tok_end == -1) {
! 400: elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
! 401: return (u_int) -1;
! 402: }
! 403: }
! 404: } else
! 405: cx++; /* increment needed tokens number for termination empty token */
! 406:
! 407: return cx;
! 408: }
! 409:
! 410: /*
! 411: * json_token2val() - Return token to AIT variable
! 412: *
! 413: * @jstr = JSON string
! 414: * @tok = Token for convert
! 415: * @return =NULL error or !=NULL allocated variable, after use should be ait_freeVar()
! 416: */
! 417: ait_val_t *
! 418: json_token2val(const char *jstr, jtok_t * __restrict tok)
! 419: {
! 420: ait_val_t *v = NULL;
! 421:
! 422: if (!jstr || !tok)
! 423: return NULL;
! 424:
! 425: v = ait_allocVar();
! 426: if (!v)
! 427: return NULL;
! 428:
! 429: AIT_SET_STRSIZ(v, json_toklen(tok));
! 430: strncpy(AIT_GET_STR(v), json_tokstr(jstr, tok), AIT_LEN(v) - 1);
! 431:
! 432: return v;
! 433: }
! 434:
! 435: /*
! 436: * json_token2str() - Return token to string
! 437: *
! 438: * @jstr = JSON string
! 439: * @tok = Token for convert
! 440: * @return =NULL error or !=NULL allocated str, after use should be e_free()
! 441: */
! 442: char *
! 443: json_token2str(const char *jstr, jtok_t * __restrict tok)
! 444: {
! 445: char *str = NULL;
! 446: size_t len;
! 447:
! 448: if (!jstr || !tok)
! 449: return NULL;
! 450:
! 451: len = json_toklen(tok);
! 452: str = e_malloc(len + 1);
! 453: if (!str)
! 454: return NULL;
! 455: else {
! 456: strncpy(str, json_tokstr(jstr, tok), len);
! 457: str[len] = 0;
! 458: }
! 459:
! 460: return str;
! 461: }
! 462:
! 463: /*
! 464: * json_token2num() - Return token to numeric
! 465: *
! 466: * @jstr = JSON string
! 467: * @tok = Token for convert
! 468: * @return number
! 469: */
! 470: long
! 471: json_token2num(const char *jstr, jtok_t * __restrict tok)
! 472: {
! 473: long ret = 0;
! 474: char *str;
! 475:
! 476: str = json_token2str(jstr, tok);
! 477: if (!str)
! 478: return 0;
! 479:
! 480: ret = strtol(str, NULL, 0);
! 481: e_free(str);
! 482: return ret;
! 483: }
! 484:
! 485: /*
! 486: * json_findbykey() - Find data by key
! 487: *
! 488: * @jstr = JSON string
! 489: * @key = Search key
! 490: * @toks = Parsed tokens
! 491: * @toksnum = Number of parsed tokens
! 492: * return: =NULL error or !=NULL data token found
! 493: */
! 494: jtok_t *
! 495: json_findbykey(const char *jstr, const char *key, jtok_t * __restrict toks, int toksnum)
! 496: {
! 497: jtok_t *tok = NULL;
! 498: register int i;
! 499: int klen;
! 500:
! 501: if (!jstr || !key || !toks)
! 502: return NULL;
! 503: else
! 504: klen = strlen(key);
! 505:
! 506: for (i = 1; i < toksnum; i++) {
! 507: if (toks[i].tok_type == J_STRING &&
! 508: klen == toks[i].tok_end - toks[i].tok_start &&
! 509: !strncmp(jstr + toks[i].tok_start, key, klen)) {
! 510: tok = toks + i + 1;
! 511: break;
! 512: }
! 513: }
! 514:
! 515: return tok;
! 516: }
! 517:
! 518: /*
! 519: * json_token2array() - Convert token to string array
! 520: *
! 521: * @jstr = JSON string
! 522: * @tok = Token for convert
! 523: * return: =NULL error or !=NULL allocated array with string variables,
! 524: * after use should be ait_freeVars()
! 525: */
! 526: array_t *
! 527: json_token2array(const char *jstr, jtok_t * __restrict tok)
! 528: {
! 529: array_t *arr = NULL;
! 530: register int i;
! 531: int siz;
! 532: ait_val_t *v;
! 533: jtok_t *t;
! 534:
! 535: if (!jstr || !tok)
! 536: return NULL;
! 537:
! 538: siz = tok->tok_size;
! 539: if (!siz && json_toktype(tok) != J_ARRAY && json_toktype(tok) != J_OBJECT)
! 540: siz++;
! 541:
! 542: arr = ait_allocVars(siz);
! 543: if (!arr)
! 544: return NULL;
! 545:
! 546: if (tok->tok_type == J_STRING || tok->tok_type == J_VALUE) {
! 547: v = ait_getVars(&arr, 0);
! 548: AIT_SET_STRSIZ(v, json_toklen(tok) + 1);
! 549: json_tokstrcpy(AIT_GET_STR(v), jstr, tok);
! 550: } else if (tok->tok_type == J_ARRAY) {
! 551: for (i = 0; i < tok->tok_size; i++) {
! 552: t = &tok[i + 1];
! 553: v = ait_getVars(&arr, i);
! 554: AIT_SET_STRSIZ(v, json_toklen(t) + 1);
! 555: json_tokstrcpy(AIT_GET_STR(v), jstr, t);
! 556: }
! 557: } else if (tok->tok_type == J_OBJECT) {
! 558: for (i = 0; tok->tok_idx <= tok[i + 1].tok_parent; i++) {
! 559: t = &tok[i + 1];
! 560: v = ait_getVars(&arr, i);
! 561: AIT_SET_STRSIZ(v, json_toklen(t) + 1);
! 562: json_tokstrcpy(AIT_GET_STR(v), jstr, t);
! 563: }
! 564: } else {
! 565: elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
! 566: ait_freeVars(&arr);
! 567: return NULL;
! 568: }
! 569:
! 570: return arr;
! 571: }
! 572:
! 573:
! 574:
! 575: /*
! 576: * json_add_begin_object() - Adds begin of object {
! 577: *
! 578: * @jstr = JSON string
! 579: * @jlen = JSON string length
! 580: * @wspace = whitespace include
! 581: * return: -1 error or !=-1 actual JSON string length
! 582: */
! 583: int
! 584: json_add_begin_object(char * __restrict jstr, int jlen, int wspace)
! 585: {
! 586: int len;
! 587: size_t eos;
! 588:
! 589: if (!jstr)
! 590: return -1;
! 591: else
! 592: eos = strlen(jstr);
! 593:
! 594:
! 595: if (wspace)
! 596: len = strlcat(jstr, "{ ", jlen);
! 597: else
! 598: len = strlcat(jstr, "{", jlen);
! 599:
! 600: if (len >= jlen) {
! 601: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 602: jstr[eos] = 0;
! 603: return -1;
! 604: }
! 605:
! 606: return len;
! 607: }
! 608:
! 609: /*
! 610: * json_add_end_object() - Adds end of object }
! 611: *
! 612: * @jstr = JSON string
! 613: * @jlen = JSON string length
! 614: * @wspace = whitespace include
! 615: * return: -1 error or !=-1 actual JSON string length
! 616: */
! 617: int
! 618: json_add_end_object(char * __restrict jstr, int jlen, int wspace)
! 619: {
! 620: int len;
! 621: size_t eos;
! 622:
! 623: if (!jstr)
! 624: return -1;
! 625: else
! 626: eos = strlen(jstr);
! 627:
! 628: if (wspace)
! 629: len = strlcat(jstr, " }", jlen);
! 630: else
! 631: len = strlcat(jstr, "}", jlen);
! 632:
! 633: if (len >= jlen) {
! 634: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 635: jstr[eos] = 0;
! 636: return -1;
! 637: }
! 638:
! 639: return len;
! 640: }
! 641:
! 642: /*
! 643: * json_add_begin_array() - Adds begin of array [
! 644: *
! 645: * @jstr = JSON string
! 646: * @jlen = JSON string length
! 647: * @wspace = whitespace include
! 648: * return: -1 error or !=-1 actual JSON string length
! 649: */
! 650: int
! 651: json_add_begin_array(char * __restrict jstr, int jlen, int wspace)
! 652: {
! 653: int len;
! 654: size_t eos;
! 655:
! 656: if (!jstr)
! 657: return -1;
! 658: else
! 659: eos = strlen(jstr);
! 660:
! 661: if (wspace)
! 662: len = strlcat(jstr, "[ ", jlen);
! 663: else
! 664: len = strlcat(jstr, "[", jlen);
! 665:
! 666: if (len >= jlen) {
! 667: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 668: jstr[eos] = 0;
! 669: return -1;
! 670: }
! 671:
! 672: return len;
! 673: }
! 674:
! 675: /*
! 676: * json_add_end_array() - Adds end of array ]
! 677: *
! 678: * @jstr = JSON string
! 679: * @jlen = JSON string length
! 680: * @wspace = whitespace include
! 681: * return: -1 error or !=-1 actual JSON string length
! 682: */
! 683: int
! 684: json_add_end_array(char * __restrict jstr, int jlen, int wspace)
! 685: {
! 686: int len;
! 687: size_t eos;
! 688:
! 689: if (!jstr)
! 690: return -1;
! 691: else
! 692: eos = strlen(jstr);
! 693:
! 694: if (wspace)
! 695: len = strlcat(jstr, " ]", jlen);
! 696: else
! 697: len = strlcat(jstr, "]", jlen);
! 698:
! 699: if (len >= jlen) {
! 700: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 701: jstr[eos] = 0;
! 702: return -1;
! 703: }
! 704:
! 705: return len;
! 706: }
! 707:
! 708: /*
! 709: * json_add_char() - Adds character
! 710: *
! 711: * @jstr = JSON string
! 712: * @jlen = JSON string length
! 713: * @ch = Character
! 714: * return: -1 error or !=-1 actual JSON string length
! 715: */
! 716: int
! 717: json_add_char(char * __restrict jstr, int jlen, u_char ch)
! 718: {
! 719: int len;
! 720:
! 721: if (!jstr)
! 722: return -1;
! 723:
! 724: len = strlen(jstr) + 1;
! 725: if (len >= jlen) {
! 726: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 727: return -1;
! 728: } else {
! 729: jstr[len++] = (char) ch;
! 730: jstr[len] = 0;
! 731: }
! 732:
! 733: return len;
! 734: }
! 735:
! 736: /*
! 737: * json_add_colon() - Adds key/value pair delimiter colon :
! 738: *
! 739: * @jstr = JSON string
! 740: * @jlen = JSON string length
! 741: * @wspace = whitespace include
! 742: * return: -1 error or !=-1 actual JSON string length
! 743: */
! 744: int
! 745: json_add_colon(char * __restrict jstr, int jlen, int wspace)
! 746: {
! 747: int len;
! 748: size_t eos;
! 749:
! 750: if (!jstr)
! 751: return -1;
! 752: else
! 753: eos = strlen(jstr);
! 754:
! 755: if (wspace)
! 756: len = strlcat(jstr, ": ", jlen);
! 757: else
! 758: len = strlcat(jstr, ":", jlen);
! 759:
! 760: if (len >= jlen) {
! 761: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 762: jstr[eos] = 0;
! 763: return -1;
! 764: }
! 765:
! 766: return len;
! 767: }
! 768:
! 769: /*
! 770: * json_add_comma() - Adds value delimiter comma ,
! 771: *
! 772: * @jstr = JSON string
! 773: * @jlen = JSON string length
! 774: * @wspace = whitespace include
! 775: * return: -1 error or !=-1 actual JSON string length
! 776: */
! 777: int
! 778: json_add_comma(char * __restrict jstr, int jlen, int wspace)
! 779: {
! 780: int len;
! 781: size_t eos;
! 782:
! 783: if (!jstr)
! 784: return -1;
! 785: else
! 786: eos = strlen(jstr);
! 787:
! 788: if (wspace)
! 789: len = strlcat(jstr, ", ", jlen);
! 790: else
! 791: len = strlcat(jstr, ",", jlen);
! 792:
! 793: if (len >= jlen) {
! 794: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 795: jstr[eos] = 0;
! 796: return -1;
! 797: }
! 798:
! 799: return len;
! 800: }
! 801:
! 802: /*
! 803: * json_add_string() - Adds string
! 804: *
! 805: * @jstr = JSON string
! 806: * @jlen = JSON string length
! 807: * @unquot = Unquoted string
! 808: * @str = String, it can't be NULL
! 809: * return: -1 error or !=-1 actual JSON string length
! 810: */
! 811: int
! 812: json_add_string(char * __restrict jstr, int jlen, int unquot, const char *str)
! 813: {
! 814: int len;
! 815: size_t eos;
! 816:
! 817: if (!jstr || !str)
! 818: return -1;
! 819: else
! 820: eos = strlen(jstr);
! 821:
! 822: if (!unquot) {
! 823: len = strlcat(jstr, "\"", jlen);
! 824: if (len >= jlen) {
! 825: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 826: jstr[eos] = 0;
! 827: return -1;
! 828: }
! 829: }
! 830: len = strlcat(jstr, str, jlen);
! 831: if (len >= jlen) {
! 832: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 833: jstr[eos] = 0;
! 834: return -1;
! 835: }
! 836: if (!unquot) {
! 837: len = strlcat(jstr, "\"", jlen);
! 838: if (len >= jlen) {
! 839: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 840: jstr[eos] = 0;
! 841: return -1;
! 842: }
! 843: }
! 844:
! 845: return len;
! 846: }
! 847:
! 848: /*
! 849: * json_add_value() - Adds value
! 850: *
! 851: * @jstr = JSON string
! 852: * @jlen = JSON string length
! 853: * @unquot = Unquoted number
! 854: * @num = Number
! 855: * return: -1 error or !=-1 actual JSON string length
! 856: */
! 857: int
! 858: json_add_value(char * __restrict jstr, int jlen, int unquot, long num)
! 859: {
! 860: int len;
! 861: char wrk[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
! 862: size_t eos;
! 863:
! 864: if (!jstr)
! 865: return -1;
! 866: else
! 867: eos = strlen(jstr);
! 868:
! 869: if (!unquot) {
! 870: len = strlcat(jstr, "\"", jlen);
! 871: if (len >= jlen) {
! 872: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 873: jstr[eos] = 0;
! 874: return -1;
! 875: }
! 876: }
! 877: snprintf(wrk, sizeof wrk, "%ld", num);
! 878: len = strlcat(jstr, wrk, jlen);
! 879: if (len >= jlen) {
! 880: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 881: jstr[eos] = 0;
! 882: return -1;
! 883: }
! 884: if (!unquot) {
! 885: len = strlcat(jstr, "\"", jlen);
! 886: if (len >= jlen) {
! 887: elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
! 888: jstr[eos] = 0;
! 889: return -1;
! 890: }
! 891: }
! 892:
! 893: return len;
! 894: }
! 895:
! 896: /*
! 897: * json_add_pair() - Adds key/value pair
! 898: *
! 899: * @jstr = JSON string
! 900: * @jlen = JSON string length
! 901: * @wspace = whitespace include
! 902: * @key = Key string
! 903: * @val = Value string
! 904: * return: -1 error or !=-1 actual JSON string length
! 905: */
! 906: int
! 907: json_add_pair(char * __restrict jstr, int jlen, int wspace, const char *key, const char *val)
! 908: {
! 909: int len = -1;
! 910: size_t eos;
! 911:
! 912: if (!jstr || !key || !val)
! 913: return -1;
! 914: else
! 915: eos = strlen(jstr);
! 916:
! 917: if (json_add_string(jstr, jlen, 0, key) == -1) {
! 918: jstr[eos] = 0;
! 919: return -1;
! 920: }
! 921: if (json_add_colon(jstr, jlen, wspace) == -1) {
! 922: jstr[eos] = 0;
! 923: return -1;
! 924: }
! 925: if ((len = json_add_string(jstr, jlen, 0, val)) == -1) {
! 926: jstr[eos] = 0;
! 927: return -1;
! 928: }
! 929:
! 930: return len;
! 931: }
! 932:
! 933: /*
! 934: * json_add_array() - Adds array
! 935: *
! 936: * @jstr = JSON string
! 937: * @jlen = JSON string length
! 938: * @wspace = whitespace include
! 939: * @arr = Array with variables
! 940: * return: -1 error or !=-1 actual JSON string length
! 941: */
! 942: int
! 943: json_add_array(char * __restrict jstr, int jlen, int wspace, array_t * __restrict arr)
! 944: {
! 945: int len = -1;
! 946: register int i;
! 947: ait_val_t *v;
! 948: size_t eos;
! 949:
! 950: if (!jstr || !arr)
! 951: return -1;
! 952: else
! 953: eos = strlen(jstr);
! 954:
! 955: if (json_add_begin_array(jstr, jlen, wspace) == -1) {
! 956: jstr[eos] = 0;
! 957: return -1;
! 958: }
! 959: for (i = 0; i < array_Size(arr); i++) {
! 960: v = array(arr, i, ait_val_t*);
! 961: if (v) {
! 962: if (AIT_TYPE(v) == string) {
! 963: if (json_add_string(jstr, jlen, 0, AIT_GET_STR(v)) == -1) {
! 964: jstr[eos] = 0;
! 965: return -1;
! 966: }
! 967: } else {
! 968: if (json_add_value(jstr, jlen, 0, AIT_GET_LIKE(v, long)) == -1) {
! 969: jstr[eos] = 0;
! 970: return -1;
! 971: }
! 972: }
! 973: if (i < array_Size(arr) - 1 && json_add_comma(jstr, jlen, wspace) == -1) {
! 974: jstr[eos] = 0;
! 975: return -1;
! 976: }
! 977: }
! 978: }
! 979: if ((len = json_add_end_array(jstr, jlen, wspace)) == -1) {
! 980: jstr[eos] = 0;
! 981: return -1;
! 982: }
! 983:
! 984: return len;
! 985: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>