Diff for /libelwix/src/json.c between versions 1.1.2.2 and 1.10

version 1.1.2.2, 2017/11/24 15:52:57 version 1.10, 2024/10/28 09:58:51
Line 12  terms: Line 12  terms:
 All of the documentation and software included in the ELWIX and AITNET  All of the documentation and software included in the ELWIX and AITNET
 Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>  Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   
Copyright 2004 - 2017Copyright 2004 - 2024
         by Michael Pounov <misho@elwix.org>.  All rights reserved.          by Michael Pounov <misho@elwix.org>.  All rights reserved.
   
 Redistribution and use in source and binary forms, with or without  Redistribution and use in source and binary forms, with or without
Line 105  json_free(json_t * __restrict json) Line 105  json_free(json_t * __restrict json)
         }          }
 }  }
   
   static jtok_t *
   json_gettoken(json_t * __restrict json, jtok_t * __restrict jtoks, u_int toksnum)
   {
           jtok_t *tok;
   
           assert(json || !(!jtoks && toksnum));
   
           if (json->h_next >= toksnum) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   return NULL;
           } else
                   tok = &jtoks[json->h_next];
           tok->tok_idx = json->h_next++;
           tok->tok_start = tok->tok_end = tok->tok_parent = -1;
           tok->tok_size = 0;
   
           return tok;
   }
   
   inline void
   json_filltoken(jtok_t * __restrict tok, jtype_t type, long start, long end, long parent)
   {
           assert(tok);
   
           tok->tok_type = type;
           tok->tok_start = start;
           tok->tok_end = end;
           tok->tok_parent = parent;
           tok->tok_size = 0;
   }
   
   static int
   json_parse_string(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
   {
           jtok_t  *tok;
           u_long pos;
           char ch;
           register int i;
   
           assert(json || jstr || !(!jtoks && toksnum));
   
           for (pos = json->h_pos++; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
                   ch = jstr[json->h_pos];
   
                   if (ch == '\"') {
                           if (!jtoks)
                                   return 0;
                           if (!(tok = json_gettoken(json, jtoks, toksnum))) {
                                   json->h_pos = pos;
                                   return -1;
                           } else
                                   json_filltoken(tok, J_STRING, pos + 1, json->h_pos, json->h_parent);
                           return 0;
                   }
   
                   if (ch == '\\' && json->h_pos + 1 < jlen) {
                           switch (jstr[++json->h_pos]) {
                                   case '\"':
                                   case '/':
                                   case '\\':
                                   case 'b':
                                   case 'f':
                                   case 'r':
                                   case 'n':
                                   case 't':
                                           /* Allowed escaped symbols */
                                           break;
                                   case 'u':
                                           /* Allows escaped symbol \uXXXX */
                                           json->h_pos++;
                                           for (i = 0; i < 4 && json->h_pos < jlen && jstr[json->h_pos]; i++, json->h_pos++) {
                                                   /* If it isn't a hex character we have an error */
                                                   if (!((jstr[json->h_pos] >= 48 && jstr[json->h_pos] <= 57) || /* 0-9 */
                                                                   (jstr[json->h_pos] >= 65 && jstr[json->h_pos] <= 70) || /* A-F */
                                                                   (jstr[json->h_pos] >= 97 && jstr[json->h_pos] <= 102))) { /* a-f */
                                                           json->h_pos = pos;
                                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                                           return -1;
                                                   }
                                           }
                                           json->h_pos--;
                                           break;
                                   default:
                                           /* Unexpected symbol */
                                           json->h_pos = pos;
                                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                           return -1;
                           }
                   }
           }
   
           json->h_pos = pos;
           elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
           return -1;
   }
   
   static int
   json_parse_value(json_t * __restrict json, const char *jstr, size_t jlen, jtok_t * __restrict jtoks, u_int toksnum)
   {
           jtok_t  *tok;
           u_long pos;
   
           assert(json || jstr || !(!jtoks && toksnum));
   
           for (pos = json->h_pos; json->h_pos < jlen && jstr[json->h_pos]; json->h_pos++) {
                   switch (jstr[json->h_pos]) {
                           case ':':
                                   if (json->h_strict)
                                           goto found;
                                   break;
                           case '\t':
                           case '\r':
                           case '\n':
                           case ' ':
                           case ',':
                           case ']':
                           case '}':
                                   goto found;
                   }
                   if (jstr[json->h_pos] < 32 || (u_char) jstr[json->h_pos] > 127) {
                           json->h_pos = pos;
                           elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                           return -1;
                   }
           }
   
           if (json->h_strict) {
                   json->h_pos = pos;
                   elwix_SetErr(J_ERR_PART, "%s", jerrstr[J_ERR_PART]);
                   return -1;
           }
   found:
           if (jtoks) {
                   if (!(tok = json_gettoken(json, jtoks, toksnum))) {
                           json->h_pos = pos;
                           return -1;
                   } else
                           json_filltoken(tok, J_VALUE, pos, json->h_pos, json->h_parent);
           }
   
           json->h_pos--;
           return 0;
   }
   
 /*  /*
  * json_parse() - Parse JSON string   * json_parse() - Parse JSON string
  *   *
Line 133  json_parse(json_t * __restrict json, const char *jstr, Line 277  json_parse(json_t * __restrict json, const char *jstr,
                 switch ((ch = jstr[json->h_pos])) {                  switch ((ch = jstr[json->h_pos])) {
                         case '{':                          case '{':
                         case '[':                          case '[':
                                cx++;   /* start new token */                                cx++;   /* start new object/array token */
                                 if (!jtoks)                                  if (!jtoks)
                                         break;                                          break;
   
                                 tok = json_gettoken(json, jtoks, toksnum);                                  tok = json_gettoken(json, jtoks, toksnum);
                                if (!tok) {                                if (!tok)
                                        elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]); 
                                         return (u_int) -1;                                          return (u_int) -1;
                                 }  
                                 if (json->h_parent != -1) {                                  if (json->h_parent != -1) {
                                         jtoks[json->h_parent].tok_size++;                                          jtoks[json->h_parent].tok_size++;
                                         tok->tok_parent = json->h_parent;                                          tok->tok_parent = json->h_parent;
Line 183  json_parse(json_t * __restrict json, const char *jstr, Line 325  json_parse(json_t * __restrict json, const char *jstr,
                                 }                                  }
                                 break;                                  break;
                         case '\"':                          case '\"':
                                if (json_parse_string(json, jstr, jlen, jtoks, toksnum) == -1) {                                if (json_parse_string(json, jstr, jlen, jtoks, toksnum) == -1)
                                        elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); 
                                         return (u_int) -1;                                          return (u_int) -1;
                                }                                cx++;   /* start new string token */
                                cx++; 
                                 if (jtoks && json->h_parent != -1)                                  if (jtoks && json->h_parent != -1)
                                         jtoks[json->h_parent].tok_size++;                                          jtoks[json->h_parent].tok_size++;
                                 break;                                  break;
Line 220  json_parse(json_t * __restrict json, const char *jstr, Line 360  json_parse(json_t * __restrict json, const char *jstr,
                         case 't':                          case 't':
                         case 'f':                          case 'f':
                         case 'n':                          case 'n':
                                if (!json->h_strict)                                if (json->h_strict) {
                                        break;                                        if (jtoks && json->h_parent != -1) {
                                                 /* they must not be keys of the object */
                                                 if (jtoks[json->h_parent].tok_type == J_OBJECT || 
                                                                 (jtoks[json->h_parent].tok_type == J_STRING && 
                                                                  jtoks[json->h_parent].tok_size)) {
                                                         elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
                                                         return (u_int) -1;
                                                 }
                                         }
   
                                if (jtoks && json->h_parent != -1) {                                        if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
                                        /* they must not be keys of the object */ 
                                        if (jtoks[json->h_parent].tok_type == J_OBJECT ||  
                                                        (jtoks[json->h_parent].tok_type == J_STRING &&  
                                                         jtoks[json->h_parent].tok_size)) { 
                                                elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]); 
                                                 return (u_int) -1;                                                  return (u_int) -1;
                                        }                                        cx++;   /* start new value token */
                                         if (jtoks && json->h_parent != -1)
                                                 jtoks[json->h_parent].tok_size++;
                                         break;
                                 }                                  }
   
                                 if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)  
                                         return (u_int) -1;  
                                 cx++;  
                                 if (jtoks && json->h_parent != -1)  
                                         jtoks[json->h_parent].tok_size++;  
                                 break;  
                         default:                          default:
                                 if (json->h_strict) {                                  if (json->h_strict) {
                                         elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);                                          elwix_SetErr(J_ERR_INVAL, "%s", jerrstr[J_ERR_INVAL]);
Line 247  json_parse(json_t * __restrict json, const char *jstr, Line 386  json_parse(json_t * __restrict json, const char *jstr,
   
                                 if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)                                  if (json_parse_value(json, jstr, jlen, jtoks, toksnum) == -1)
                                         return (u_int) -1;                                          return (u_int) -1;
                                cx++;                                cx++;   /* start new value token */
                                 if (jtoks && json->h_parent != -1)                                  if (jtoks && json->h_parent != -1)
                                         jtoks[json->h_parent].tok_size++;                                          jtoks[json->h_parent].tok_size++;
                                 break;                                  break;
Line 262  json_parse(json_t * __restrict json, const char *jstr, Line 401  json_parse(json_t * __restrict json, const char *jstr,
                                 return (u_int) -1;                                  return (u_int) -1;
                         }                          }
                 }                  }
        }        } else
                 cx++;   /* increment needed tokens number for termination empty token */
   
         return cx;          return cx;
   }
   
   /*
    * json_token2val() - Return token to AIT variable
    *
    * @jstr = JSON string
    * @tok = Token for convert
    * @return =NULL error or !=NULL allocated variable, after use should be ait_freeVar()
    */
   ait_val_t *
   json_token2val(const char *jstr, jtok_t * __restrict tok)
   {
           ait_val_t *v = NULL;
   
           if (!jstr || !tok)
                   return NULL;
   
           v = ait_allocVar();
           if (!v)
                   return NULL;
   
           AIT_SET_STRSIZ(v, json_toklen(tok));
           if (AIT_GET_STR(v))
                   strncpy(AIT_GET_STR(v), json_tokstr(jstr, tok), AIT_LEN(v) - 1);
           else
                   ait_freeVar(&v);
   
           return v;
   }
   
   /*
    * json_token2str() - Return token to string
    *
    * @jstr = JSON string
    * @tok = Token for convert
    * @return =NULL error or !=NULL allocated str, after use should be json_freestr()|e_free()
    */
   char *
   json_token2str(const char *jstr, jtok_t * __restrict tok)
   {
           char *s, *s2, *wrk, *str = NULL;
           size_t len;
   
           if (!jstr || !tok)
                   return NULL;
   
   
           len = json_toklen(tok);
           str = e_malloc(len + 1);
           if (!str)
                   return NULL;
           else {
                   memset(str, 0, len + 1);
   
                   wrk = e_strdup(json_tokstr(jstr, tok));
                   wrk[len] = 0;
                   for (s = wrk, s2 = str; *s; s++)
                           *s2++ = (*s != '\\') ? *s : *++s;
                   e_free(wrk);
           }
   
           return str;
   }
   
   /*
    * json_token2num() - Return token to numeric
    *
    * @jstr = JSON string
    * @tok = Token for convert
    * @return number
    */
   long
   json_token2num(const char *jstr, jtok_t * __restrict tok)
   {
           long ret = 0;
           char *str;
   
           str = json_token2str(jstr, tok);
           if (!str)
                   return 0;
   
           ret = strtol(str, NULL, 0);
           e_free(str);
           return ret;
   }
   
   /*
    * json_token2dbl() - Return token to double
    *
    * @jstr = JSON string
    * @tok = Token for convert
    * @return number
    */
   double
   json_token2dbl(const char *jstr, jtok_t * __restrict tok)
   {
           double ret = 0;
           char *str;
   
           str = json_token2str(jstr, tok);
           if (!str)
                   return 0;
   
           ret = strtod(str, NULL);
           e_free(str);
           return ret;
   }
   
   /*
    * json_token2bool() - Return token to bool int
    *
    * @jstr = JSON string
    * @tok = Token for convert
    * @return 0 for FALSE and !=0 for TRUE
    */
   int
   json_token2bool(const char *jstr, jtok_t * __restrict tok)
   {
           double ret = 0;
           char *str;
   
           str = json_token2str(jstr, tok);
           if (!str)
                   return 0;
   
           switch (*str) {
                   case 't':
                   case 'T':
                           ret = 1;
                           break;
                   case 'f':
                   case 'F':
                           ret = 0;
                           break;
                   default:
                           ret = (int) strtol(str, NULL, 10);
                           break;
           }
           e_free(str);
           return ret;
   }
   
   /*
    * json_findbykey() - Find token data by key
    *
    * @jstr = JSON string
    * @key = Search key
    * @type = Search key for particular token type, if is J_UNDEF this mean any type
    * @toks = Parsed tokens
    * @toksnum = Number of parsed tokens
    * return: =NULL error or !=NULL data token found 
    */
   jtok_t *
   json_findbykey(const char *jstr, const char *key, jtype_t type, jtok_t * __restrict toks, int toksnum)
   {
           jtok_t *tok = NULL;
           register int i;
           int klen;
   
           if (!jstr || !key || !toks)
                   return NULL;
           else
                   klen = strlen(key);
   
           for (i = 1; i < toksnum; i++) {
                   if (toks[i].tok_type == J_STRING && toks[i].tok_size == 1 && 
                                   klen == toks[i].tok_end - toks[i].tok_start && 
                                   !strncmp(jstr + toks[i].tok_start, key, klen)) {
                           if (type != J_UNDEF) {
                                   if (toks[i + 1].tok_type == type) {
                                           tok = toks + i + 1;
                                           break;
                                   }
                           } else {
                                   tok = toks + i + 1;
                                   break;
                           }
                   }
           }
   
           return tok;
   }
   
   /*
    * json_findbypos() - Find token by position on JSON string
    *
    * @pos = Offset from begin of JSON string
    * @toks = Parsed tokens
    * @toksnum = Number of parsed tokens
    * return: =NULL error or !=NULL token found 
    */
   jtok_t *
   json_findbypos(u_long pos, jtok_t * __restrict toks, int toksnum)
   {
           jtok_t *tok = NULL;
           register int i;
   
           if (!toks)
                   return NULL;
   
           for (i = 1; i < toksnum; i++)
                   if (pos <= toks[i].tok_end && pos >= toks[i].tok_start) {
                           tok = toks + i;
                           break;
                   }
   
           return tok;
   }
   
   /*
    * json_token2array() - Convert token to string array
    *
    * @jstr = JSON string
    * @tok = Token for convert
    * return: =NULL error or !=NULL allocated array with string variables, 
    *              after use should be ait_freeVars()
    */
   array_t *
   json_token2array(const char *jstr, jtok_t * __restrict tok)
   {
           array_t *arr = NULL;
           register int i, j;
           int siz;
           ait_val_t *v;
           jtok_t *t;
   
           if (!jstr || !tok)
                   return NULL;
   
           siz = tok->tok_size;
           if (!siz && json_toktype(tok) != J_ARRAY && json_toktype(tok) != J_OBJECT)
                   siz++;
   
           arr = ait_allocVars(siz);
           if (!arr)
                   return NULL;
   
           if (tok->tok_type == J_STRING || tok->tok_type == J_VALUE) {
                   v = ait_getVars(&arr, 0);
                   AIT_SET_STRSIZ(v, json_toklen(tok) + 1);
                   if (AIT_GET_STR(v)) {
                           json_tokstrcpy(AIT_GET_STR(v), jstr, tok);
                   } else {
                           ait_freeVar(&v);
                   }
           } else if (tok->tok_type == J_ARRAY) {
                   for (i = 0, j = 1; i < tok->tok_size; i++) {
                           t = &tok[i + j];
                           v = ait_getVars(&arr, i);
                           AIT_SET_STRSIZ(v, json_toklen(t) + 1);
                           if (AIT_GET_STR(v)) {
                                   json_tokstrcpy(AIT_GET_STR(v), jstr, t);
                           } else {
                                   ait_freeVar(&v);
                           }
   
                           /* if there we have array from objects should parse all object tokens */
                           while (i < tok->tok_size - 1 && tok->tok_idx != tok[i + j + 1].tok_parent)
                                   j++;
                   }
           } else if (tok->tok_type == J_OBJECT) {
                   for (i = 0; tok->tok_idx <= tok[i + 1].tok_parent; i++) {
                           t = &tok[i + 1];
                           v = ait_getVars(&arr, i);
                           AIT_SET_STRSIZ(v, json_toklen(t) + 1);
                           if (AIT_GET_STR(v)) {
                                   json_tokstrcpy(AIT_GET_STR(v), jstr, t);
                           } else {
                                   ait_freeVar(&v);
                           }
                   }
           } else {
                   elwix_SetErr(J_ERR_PARAM, "%s", jerrstr[J_ERR_PARAM]);
                   ait_freeVars(&arr);
                   return NULL;
           }
   
           return arr;
   }
   
   
   
   /*
    * json_add_begin_object() - Adds begin of object {
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_begin_object(char * __restrict jstr, int jlen, int wspace)
   {
           int len;
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
   
           if (wspace)
                   len = strlcat(jstr, "{ ", jlen);
           else
                   len = strlcat(jstr, "{", jlen);
   
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_end_object() - Adds end of object }
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_end_object(char * __restrict jstr, int jlen, int wspace)
   {
           int len;
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (wspace)
                   len = strlcat(jstr, " }", jlen);
           else
                   len = strlcat(jstr, "}", jlen);
   
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_begin_array() - Adds begin of array [
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_begin_array(char * __restrict jstr, int jlen, int wspace)
   {
           int len;
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (wspace)
                   len = strlcat(jstr, "[ ", jlen);
           else
                   len = strlcat(jstr, "[", jlen);
   
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_end_array() - Adds end of array ]
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_end_array(char * __restrict jstr, int jlen, int wspace)
   {
           int len;
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (wspace)
                   len = strlcat(jstr, " ]", jlen);
           else
                   len = strlcat(jstr, "]", jlen);
   
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_char() - Adds character
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @ch = Character
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_char(char * __restrict jstr, int jlen, u_char ch)
   {
           int len;
   
           if (!jstr)
                   return -1;
   
           len = strlen(jstr) + 1;
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   return -1;
           } else {
                   jstr[len++] = (char) ch;
                   jstr[len] = 0;
           }
   
           return len;
   }
   
   /*
    * json_add_colon() - Adds key/value pair delimiter colon :
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_colon(char * __restrict jstr, int jlen, int wspace)
   {
           int len;
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (wspace)
                   len = strlcat(jstr, ": ", jlen);
           else
                   len = strlcat(jstr, ":", jlen);
   
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_comma() - Adds value delimiter comma ,
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_comma(char * __restrict jstr, int jlen, int wspace)
   {
           int len;
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (wspace)
                   len = strlcat(jstr, ", ", jlen);
           else
                   len = strlcat(jstr, ",", jlen);
   
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_string() - Adds string
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @unquot = Unquoted string
    * @str = String, it can't be NULL
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_string(char * __restrict jstr, int jlen, int unquot, const char *str)
   {
           int len;
           size_t eos;
   
           if (!jstr || !str)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (!unquot) {
                   len = strlcat(jstr, "\"", jlen);
                   if (len >= jlen) {
                           elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                           jstr[eos] = 0;
                           return -1;
                   }
           }
           len = strlcat(jstr, str, jlen);
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
           if (!unquot) {
                   len = strlcat(jstr, "\"", jlen);
                   if (len >= jlen) {
                           elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                           jstr[eos] = 0;
                           return -1;
                   }
           }
   
           return len;
   }
   
   /*
    * json_add_value() - Adds value
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @unquot = Unquoted number
    * @num = Number
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_value(char * __restrict jstr, int jlen, int unquot, long num)
   {
           int len;
           char wrk[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
           size_t eos;
   
           if (!jstr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (!unquot) {
                   len = strlcat(jstr, "\"", jlen);
                   if (len >= jlen) {
                           elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                           jstr[eos] = 0;
                           return -1;
                   }
           }
           snprintf(wrk, sizeof wrk, "%ld", num);
           len = strlcat(jstr, wrk, jlen);
           if (len >= jlen) {
                   elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                   jstr[eos] = 0;
                   return -1;
           }
           if (!unquot) {
                   len = strlcat(jstr, "\"", jlen);
                   if (len >= jlen) {
                           elwix_SetErr(J_ERR_NOMEM, "%s", jerrstr[J_ERR_NOMEM]);
                           jstr[eos] = 0;
                           return -1;
                   }
           }
   
           return len;
   }
   
   /*
    * json_add_pair() - Adds key/value pair
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * @key = Key string
    * @val = Value string
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_pair(char * __restrict jstr, int jlen, int wspace, const char *key, const char *val)
   {
           int len = -1;
           size_t eos;
   
           if (!jstr || !key || !val)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (json_add_string(jstr, jlen, 0, key) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
           if (json_add_colon(jstr, jlen, wspace) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
           if ((len = json_add_string(jstr, jlen, 0, val)) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_pair2() - Adds key/value pair with formated args
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * @key = Key string
    * @fmt = Format string for values
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_pair2(char * __restrict jstr, int jlen, int wspace, const char *key, const char *fmt, ...)
   {
           int len = -1;
           size_t eos;
           va_list lst;
           char szStr[BUFSIZ] = { [0 ... BUFSIZ - 1] = 0 };
   
           if (!jstr || !key || !fmt)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (json_add_string(jstr, jlen, 0, key) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
           if (json_add_colon(jstr, jlen, wspace) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
           va_start(lst, fmt);
           vsnprintf(szStr, sizeof szStr, fmt, lst);
           va_end(lst);
           if ((len = json_add_string(jstr, jlen, 0, szStr)) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_add_array() - Adds array
    *
    * @jstr = JSON string
    * @jlen = JSON string length
    * @wspace = whitespace include
    * @arr = Array with variables
    * return: -1 error or !=-1 actual JSON string length
    */
   int
   json_add_array(char * __restrict jstr, int jlen, int wspace, array_t * __restrict arr)
   {
           int len = -1;
           register int i;
           ait_val_t *v;
           size_t eos;
   
           if (!jstr || !arr)
                   return -1;
           else
                   eos = strlen(jstr);
   
           if (json_add_begin_array(jstr, jlen, wspace) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
           for (i = 0; i < array_Size(arr); i++) {
                   v = array(arr, i, ait_val_t*);
                   if (v) {
                           if (AIT_TYPE(v) == string) {
                                   if (json_add_string(jstr, jlen, 0, AIT_GET_STR(v)) == -1) {
                                           jstr[eos] = 0;
                                           return -1;
                                   }
                           } else {
                                   if (json_add_value(jstr, jlen, 0, AIT_GET_LIKE(v, long)) == -1) {
                                           jstr[eos] = 0;
                                           return -1;
                                   }
                           }
                           if (i < array_Size(arr) - 1 && json_add_comma(jstr, jlen, wspace) == -1) {
                                   jstr[eos] = 0;
                                   return -1;
                           }
                   }
           }
           if ((len = json_add_end_array(jstr, jlen, wspace)) == -1) {
                   jstr[eos] = 0;
                   return -1;
           }
   
           return len;
   }
   
   /*
    * json_dump_yaml() - Dump parsed JSON string to YAML format
    *
    * @f = Output handler
    * @jstr = JSON string
    * @toks = JSON tokens
    * @toksnum = Number of tokens
    * @indent = Start indent spaces
    * return: 0 done and 1 added one more item
    */
   int
   json_dump_yaml(FILE *f, const char *jstr, jtok_t *toks, int toksnum, int indent)
   {
           register int i, j, k;
   
           if (!toksnum || !toks)
                   return 0;
   
           if (toks->tok_type == J_VALUE) {
                   fprintf(f, "%.*s", (int) json_toklen(toks), json_tokstr(jstr, toks));
                   return 1;
           } else if (toks->tok_type == J_STRING) {
                   fprintf(f, "%.*s", (int) json_toklen(toks), json_tokstr(jstr, toks));
                   return 1;
           } else if (toks->tok_type == J_OBJECT) {
                   fprintf(f, "\n");
                   for (j = i = 0; i < json_toksize(toks); i++) {
                           for (k = 0; k < indent; k++)
                                   fprintf(f, "  ");
                           j += json_dump_yaml(f, jstr, toks + j + 1, toksnum - j, indent + 1);
                           fprintf(f, ": ");
                           j += json_dump_yaml(f, jstr, toks + j + 1, toksnum - j, indent + 1);
                           fprintf(f, "\n");
                   }
                   return j + 1;
           } else if (toks->tok_type == J_ARRAY) {
                   fprintf(f, "\n");
                   for (j = i = 0; i < json_toksize(toks); i++) {
                           for (k = 0; k < indent - 1; k++)
                                   fprintf(f, "  ");
                           fprintf(f, "   - ");
                           j += json_dump_yaml(f, jstr, toks + j + 1, toksnum - j, indent + 1);
                           fprintf(f, "\n");
                   }
                   return j + 1;
           }
   
           return 0;
   }
   
   /*
    * json_dump() - Dump parsed JSON string to structure format
    *
    * @f = Output handler
    * @jstr = JSON string
    * @toks = JSON tokens
    * @toksnum = Number of tokens
    * @indent = Start indent spaces
    * return: 0 done and 1 added one more item
    */
   int
   json_dump(FILE *f, const char *jstr, jtok_t *toks, int toksnum, int indent)
   {
           register int i, j, k;
   
           if (!toksnum)
                   return 0;
   
           if (toks->tok_type == J_VALUE) {
                   fprintf(f, "[idx=%ld type=VALUE start=%ld end=%ld size=%ld parent=%ld] = %.*s", 
                                   toks->tok_idx, toks->tok_start, toks->tok_end, toks->tok_size, toks->tok_parent, 
                                   (int) json_toklen(toks), json_tokstr(jstr, toks));
                   return 1;
           } else if (toks->tok_type == J_STRING) {
                   fprintf(f, "[idx=%ld type=STRING start=%ld end=%ld size=%ld parent=%ld] = %.*s", 
                                   toks->tok_idx, toks->tok_start, toks->tok_end, toks->tok_size, toks->tok_parent, 
                                   (int) json_toklen(toks), json_tokstr(jstr, toks));
                   return 1;
           } else if (toks->tok_type == J_OBJECT) {
                   fprintf(f, "\n");
                   fprintf(f, "object:: [idx=%ld type=OBJECT start=%ld end=%ld size=%ld parent=%ld]\n", 
                                   toks->tok_idx, toks->tok_start, toks->tok_end, toks->tok_size, toks->tok_parent);
                   for (j = i = 0; i < json_toksize(toks); i++) {
                           for (k = 0; k < indent; k++)
                                   fprintf(f, "  ");
                           j += json_dump(f, jstr, toks + j + 1, toksnum - j, indent + 1);
                           fprintf(f, ": ");
                           j += json_dump(f, jstr, toks + j + 1, toksnum - j, indent + 1);
                           fprintf(f, "\n");
                   }
                   return j + 1;
           } else if (toks->tok_type == J_ARRAY) {
                   fprintf(f, "\n");
                   fprintf(f, "array[] [idx=%ld type=ARRAY start=%ld end=%ld size=%ld parent=%ld]", 
                                   toks->tok_idx, toks->tok_start, toks->tok_end, toks->tok_size, toks->tok_parent);
                   for (j = i = 0; i < json_toksize(toks); i++) {
                           for (k = 0; k < indent - 1; k++)
                                   fprintf(f, "  ");
                           j += json_dump(f, jstr, toks + j + 1, toksnum - j, indent + 1);
                           fprintf(f, "\n");
                   }
                   return j + 1;
           }
   
           return 0;
 }  }

Removed from v.1.1.2.2  
changed lines
  Added in v.1.10


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>