Patch from Scott McKellar to increase const correctness in the JSON parser.
[OpenSRF.git] / src / libopensrf / osrf_json_parser.c
1 /*
2 Copyright (C) 2006  Georgia Public Library Service 
3 Bill Erickson <billserickson@gmail.com>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 */
15
16 #include <opensrf/osrf_json.h>
17 #include <opensrf/osrf_json_utils.h>
18 #include <ctype.h>
19
20
21 /* if the client sets a global error handler, this will point to it */
22 static void (*jsonClientErrorCallback) (const char*) = NULL;
23
24 /* these are the handlers for our internal parser */
25 static jsonParserHandler jsonInternalParserHandlerStruct = {
26         _jsonHandleStartObject,
27         _jsonHandleObjectKey,
28         _jsonHandleEndObject,
29         _jsonHandleStartArray,
30         _jsonHandleEndArray,
31         _jsonHandleNull,
32         _jsonHandleString,
33         _jsonHandleBool,
34         _jsonHandleNumber,
35         _jsonHandleError
36 };
37 static jsonParserHandler* 
38         jsonInternalParserHandler = &jsonInternalParserHandlerStruct; 
39
40
41 jsonParserContext* jsonNewParser( jsonParserHandler* handler, void* userData) {
42         jsonParserContext* ctx;
43         OSRF_MALLOC(ctx, sizeof(jsonParserContext));
44         ctx->stateStack                 = osrfNewList();
45         ctx->buffer                                     = buffer_init(512);
46         ctx->utfbuf                                     = buffer_init(5);
47         ctx->handler                            = handler;
48         ctx->state                                      = 0;
49         ctx->index                                      = 0;
50         ctx->chunk                                      = NULL;
51         ctx->userData                           = userData;
52         return ctx;
53 }
54
55 void jsonParserFree( jsonParserContext* ctx ) {
56         if(!ctx) return;
57         buffer_free(ctx->buffer);
58         buffer_free(ctx->utfbuf);
59         osrfListFree(ctx->stateStack);
60         free(ctx);
61 }
62
63
64 void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*)) {
65         jsonClientErrorCallback = errorHandler;
66 }
67
68
69 int _jsonParserError( jsonParserContext* ctx, char* err, ... ) {
70         if( ctx->handler->handleError ) {
71                 VA_LIST_TO_STRING(err);
72                 int pre = ctx->index - 15;
73                 int post= ctx->index + 15;
74                 while( pre < 0 ) pre++;
75                 while( post >= ctx->chunksize ) post--;
76                 int l = post - pre;
77                 char buf[l];
78                 snprintf(buf, sizeof(buf), ctx->chunk + pre);
79                 ctx->handler->handleError( ctx->userData, 
80                         "*JSON Parser Error\n - char  = %c\n "
81                         "- index = %d\n - near  => %s\n - %s", 
82                         ctx->chunk[ctx->index], ctx->index, buf, VA_BUF );
83         }
84         JSON_STATE_SET(ctx, JSON_STATE_IS_INVALID);
85         return -1;
86 }
87
88
89 int _jsonParserHandleUnicode( jsonParserContext* ctx ) {
90
91         /* collect as many of the utf characters as we can in this chunk */
92         JSON_CACHE_DATA(ctx, ctx->utfbuf, 4);
93
94         /* we ran off the end of the chunk */
95         if( ctx->utfbuf->n_used < 4 ) {
96                 JSON_STATE_SET(ctx, JSON_STATE_IN_UTF);
97                 return 1;
98         }
99
100         ctx->index--; /* push it back to index of the final utf char */
101
102         /* ----------------------------------------------------------------------- */
103         /* We have all of the escaped unicode data.  Write it to the buffer */
104         /* The following chunk is used with permission from 
105          * json-c http://oss.metaparadigm.com/json-c/ 
106          */
107         #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
108         unsigned char utf_out[4];
109         memset(utf_out, 0, sizeof(utf_out));
110         char* buf = ctx->utfbuf->buf;
111
112         unsigned int ucs_char =
113                 (hexdigit(buf[0] ) << 12) +
114                 (hexdigit(buf[1]) << 8) +
115                 (hexdigit(buf[2]) << 4) +
116                 hexdigit(buf[3]);
117
118         if (ucs_char < 0x80) {
119                 utf_out[0] = ucs_char;
120                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
121
122         } else if (ucs_char < 0x800) {
123                 utf_out[0] = 0xc0 | (ucs_char >> 6);
124                 utf_out[1] = 0x80 | (ucs_char & 0x3f);
125                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
126
127         } else {
128                 utf_out[0] = 0xe0 | (ucs_char >> 12);
129                 utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
130                 utf_out[2] = 0x80 | (ucs_char & 0x3f);
131                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
132         }
133         /* ----------------------------------------------------------------------- */
134         /* ----------------------------------------------------------------------- */
135
136         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_UTF);
137         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
138         OSRF_BUFFER_RESET(ctx->utfbuf);
139         return 0;
140 }
141
142
143
144 /* type : 0=null, 1=true, 2=false */
145 int _jsonParserHandleMatch( jsonParserContext* ctx, int type ) {
146
147         switch(type) {
148
149                 case 0: /* JSON null */
150
151                         /* first see if we have it all first */
152                         if( ctx->chunksize > (ctx->index + 3) ) {
153                                 if( strncasecmp(ctx->chunk + ctx->index, "null", 4) ) 
154                                         return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
155                                 if( ctx->handler->handleNull ) 
156                                         ctx->handler->handleNull(ctx->userData);
157                                 ctx->index += 4;
158                                 break;
159                         }
160
161                         JSON_CACHE_DATA(ctx, ctx->buffer, 4);
162                         if( ctx->buffer->n_used < 4 ) {
163                                 JSON_STATE_SET(ctx, JSON_STATE_IN_NULL);
164                                 return 1;
165                         } 
166
167                         if( strncasecmp(ctx->buffer->buf, "null", 4) ) 
168                                 return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
169                         if( ctx->handler->handleNull ) 
170                                 ctx->handler->handleNull(ctx->userData);
171                         break;
172
173                 case 1: /* JSON true */
174
175                         /* see if we have it all first */
176                         if( ctx->chunksize > (ctx->index + 3) ) {
177                                 if( strncasecmp(ctx->chunk + ctx->index, "true", 4) ) 
178                                         return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
179                                 if( ctx->handler->handleBool ) 
180                                         ctx->handler->handleBool(ctx->userData, 1);
181                                 ctx->index += 4;
182                                 break;
183                         }
184
185                         JSON_CACHE_DATA(ctx, ctx->buffer, 4);
186                         if( ctx->buffer->n_used < 4 ) {
187                                 JSON_STATE_SET(ctx, JSON_STATE_IN_TRUE);
188                                 return 1;
189                         } 
190                         if( strncasecmp( ctx->buffer->buf, "true", 4 ) ) {
191                                 return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
192                         }
193                         if( ctx->handler->handleBool ) 
194                                 ctx->handler->handleBool(ctx->userData, 1);
195                         break;
196
197                 case 2: /* JSON false */
198
199                         /* see if we have it all first */
200                         if( ctx->chunksize > (ctx->index + 4) ) {
201                                 if( strncasecmp(ctx->chunk + ctx->index, "false", 5) ) 
202                                         return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
203                                 if( ctx->handler->handleBool ) 
204                                         ctx->handler->handleBool(ctx->userData, 0);
205                                 ctx->index += 5;
206                                 break;
207                         }
208
209                         JSON_CACHE_DATA(ctx, ctx->buffer, 5);
210                         if( ctx->buffer->n_used < 5 ) {
211                                 JSON_STATE_SET(ctx, JSON_STATE_IN_FALSE);
212                                 return 1;
213                         }
214                         if( strncasecmp( ctx->buffer->buf, "false", 5 ) ) 
215                                 return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
216                         if( ctx->handler->handleBool ) 
217                                 ctx->handler->handleBool(ctx->userData, 0);
218                         break;
219
220                 default: 
221                         fprintf(stderr, "Invalid type flag\n");
222                         return -1;
223
224         }
225
226         ctx->index--; /* set it back to the index of the final sequence character */
227         OSRF_BUFFER_RESET(ctx->buffer);
228         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NULL);
229         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_TRUE);
230         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_FALSE);
231
232         return 0;
233 }
234
235
236 int _jsonParserHandleString( jsonParserContext* ctx ) {
237
238         char c = ctx->chunk[ctx->index];
239
240         if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_ESCAPE) ) {
241
242                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_UTF) ) {
243
244                         return _jsonParserHandleUnicode( ctx );
245                                                 
246                 } else {
247
248                         switch(c) {
249
250                                 /* handle all of the escape chars */
251                                 case '\\': OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\\' ); break;
252                                 case '"'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\"' ); break;
253                                 case 't'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\t' ); break;
254                                 case 'b'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\b' ); break;
255                                 case 'f'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\f' ); break;
256                                 case 'r'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\r' ); break;
257                                 case 'n'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\n' ); break;
258                                 case 'u'        : 
259                                         ctx->index++; /* progress to the first utf char */
260                                         return _jsonParserHandleUnicode( ctx );
261                                 default : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
262                         }
263                 }
264
265                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
266                 return 0;
267
268         } else {
269
270                 switch(c) {
271
272                         case '"'        : /* this string is ending */
273                                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_KEY) ) {
274
275                                         /* object key */
276                                         if(ctx->handler->handleObjectKey) {
277                                                 ctx->handler->handleObjectKey( 
278                                                         ctx->userData, ctx->buffer->buf);
279                                         }
280
281                                 } else { /* regular json string */
282
283                                         if(ctx->handler->handleString) {
284                                                 ctx->handler->handleString( 
285                                                         ctx->userData, ctx->buffer->buf );
286                                         }
287
288                                 }
289
290                                 OSRF_BUFFER_RESET(ctx->buffer); /* flush the buffer and states */
291                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_STRING);
292                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
293                                 break;
294
295                         case '\\' : JSON_STATE_SET(ctx, JSON_STATE_IN_ESCAPE); break;
296                         default  : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
297                 }
298         }
299         return 0;
300 }
301
302
303 int _jsonParserHandleNumber( jsonParserContext* ctx ) {
304         char c = ctx->chunk[ctx->index];
305
306         do {
307                 OSRF_BUFFER_ADD_CHAR(ctx->buffer, c);
308                 c = ctx->chunk[++(ctx->index)];
309         } while( strchr(JSON_NUMBER_CHARS, c) && ctx->index < ctx->chunksize );
310
311         /* if we're run off the end of the chunk and we're not parsing the last chunk,
312          * save the number and the state */
313         if( ctx->index >= ctx->chunksize && 
314                         ! JSON_PARSE_FLAG_CHECK(ctx, JSON_PARSE_LAST_CHUNK) ) {
315                 JSON_STATE_SET(ctx, JSON_STATE_IN_NUMBER);
316                 return 1;
317         }
318
319         /* make me more strict */
320         char* err = NULL;
321         double d = strtod(ctx->buffer->buf, &err);
322         if(err && err[0] != '\0') 
323                 return _jsonParserError(ctx, "Invalid number sequence");
324         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER);
325         OSRF_BUFFER_RESET(ctx->buffer);
326         if(ctx->handler->handleNumber)
327                 ctx->handler->handleNumber( ctx->userData, d );
328         ctx->index--; /* scooch back to the first non-digit number */
329         return 0;
330 }
331
332
333
334
335 int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags ) {
336
337         if( !( ctx && ctx->handler && data && datalen > 0 )) return -1;
338         ctx->chunksize  = datalen;
339         ctx->chunk              = data;
340         ctx->flags              = flags;
341         char c;
342
343         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_INVALID) )
344                 return _jsonParserError( ctx, "JSON Parser cannot continue after an error" );
345
346         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_DONE) )
347                 return _jsonParserError( ctx, "Extra content at end of JSON data" );
348
349         for( ctx->index = 0; (ctx->index < ctx->chunksize) && 
350                                 (c = ctx->chunk[ctx->index]); ctx->index++ ) {
351
352                 /* middle of parsing a string */
353                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_STRING)) {
354                         if( _jsonParserHandleString(ctx) == -1 )
355                                 return -1;
356                         continue;
357                 }
358
359                 /* middle of parsing a number */
360                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_NUMBER) ) {
361                         if( _jsonParserHandleNumber(ctx) == -1 )
362                                 return -1;
363                         continue;
364                 }
365
366
367 #ifdef OSRF_JSON_ALLOW_COMMENTS
368                 /* we just saw a bare '/' character */
369                 if( JSON_STATE_CHECK(ctx, JSON_STATE_START_COMMENT) ) {
370                         if(c == '*') {
371                                 JSON_STATE_REMOVE(ctx, JSON_STATE_START_COMMENT);
372                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
373                                 continue;
374                         } else {
375                                 return _jsonParserError( ctx, "Invalid comment initializer" );
376                         }
377                 }
378
379                 /* we're currently in the middle of a comment block */
380                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_COMMENT) ) {
381                         if(c == '*') {
382                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_COMMENT);
383                                 JSON_STATE_SET(ctx, JSON_STATE_END_COMMENT);
384                                 continue;
385                         } else {
386                                 continue;
387                         }
388                 }
389
390                 /* we're in a comment, and we just saw a '*' character */
391                 if( JSON_STATE_CHECK(ctx, JSON_STATE_END_COMMENT) ) {
392                         if( c == '/' ) { /* comment is finished */
393                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
394                                 continue;
395                         } else {
396                                 /* looks like this isn't the end of the comment after all */
397                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
398                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
399                         }
400                 }
401 #endif
402
403                 /* if we're in the middle of parsing a null/true/false sequence */
404                 if( JSON_STATE_CHECK(ctx, (JSON_STATE_IN_NULL | 
405                                         JSON_STATE_IN_TRUE | JSON_STATE_IN_FALSE)) ) {
406
407                         int type = (JSON_STATE_CHECK(ctx, JSON_STATE_IN_NULL)) ? 0 :
408                                 (JSON_STATE_CHECK(ctx, JSON_STATE_IN_TRUE)) ? 1 : 2;
409
410                         if( _jsonParserHandleMatch( ctx, type ) == -1 ) 
411                                 return -1;
412                         continue;
413                 }
414
415                 JSON_EAT_WS(ctx);
416
417                 /* handle all of the top level characters */
418                 switch(c) {
419
420                         case '{' : /* starting an object */
421                                 if( ctx->handler->handleStartObject) 
422                                         ctx->handler->handleStartObject( ctx->userData );
423                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_OBJECT);
424                                 JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
425                                 break;
426
427                         case '}' : /* ending an object */
428                                 if( ctx->handler->handleEndObject) 
429                                         ctx->handler->handleEndObject( ctx->userData ); 
430                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
431                                 JSON_STATE_POP(ctx);
432                                 if( JSON_STATE_PEEK(ctx) == NULL )
433                                         JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
434                                 break;
435
436                         case '[' : /* starting an array */
437                                 if( ctx->handler->handleStartArray )
438                                         ctx->handler->handleStartArray( ctx->userData );
439                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_ARRAY);
440                                 break;
441
442                         case ']': /* ending an array */
443                                 if( ctx->handler->handleEndArray )
444                                         ctx->handler->handleEndArray( ctx->userData );
445                                 JSON_STATE_POP(ctx);
446                                 if( JSON_STATE_PEEK(ctx) == NULL )
447                                         JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
448                                 break;
449                                 
450                         case ':' : /* done with the object key */
451                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
452                                 break;
453
454                         case ',' : /* after object or array item */
455                                 if( JSON_STATE_CHECK_STACK(ctx, JSON_STATE_IN_OBJECT) )
456                                         JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
457                                 break;
458
459                         case 'n' :
460                         case 'N' : /* null */
461                                 if( _jsonParserHandleMatch( ctx, 0 ) == -1)
462                                         return -1;
463                                 break;
464
465                         case 't' :
466                         case 'T' :
467                                 if( _jsonParserHandleMatch( ctx, 1 ) == -1 )
468                                         return -1;
469                                 break;
470
471                         case 'f' :
472                         case 'F' :
473                                 if( _jsonParserHandleMatch( ctx, 2 ) == -1)
474                                         return -1;
475                                 break;
476
477                         case '"' : 
478                                 JSON_STATE_SET(ctx, JSON_STATE_IN_STRING);
479                                 break;
480
481 #ifdef OSRF_JSON_ALLOW_COMMENTS
482                         case '/' :
483                                 JSON_STATE_SET(ctx, JSON_STATE_START_COMMENT);
484                                 break;
485 #endif
486
487                         default:
488                                 if( strchr(JSON_NUMBER_CHARS, c) ) {
489                                         if( _jsonParserHandleNumber( ctx ) == -1 )
490                                                 return -1;
491                                 } else {
492                                         return _jsonParserError( ctx, "Invalid Token" );
493                                 }
494                 }
495         }
496
497         return 0;
498 }
499
500
501 jsonInternalParser* _jsonNewInternalParser() {
502         jsonInternalParser* p;
503         OSRF_MALLOC(p, sizeof(jsonInternalParser));
504         p->ctx = jsonNewParser( jsonInternalParserHandler, p );
505         p->obj          = NULL;
506         p->lastkey      = NULL;
507         return p;
508 }
509
510 void _jsonInternalParserFree(jsonInternalParser* p) {
511         if(!p) return;
512         jsonParserFree(p->ctx);
513         free(p->lastkey);
514         free(p);
515 }
516
517 static jsonObject* _jsonParseStringImpl(const char* str, void (*errorHandler) (const char*) ) {
518         jsonInternalParser* parser = _jsonNewInternalParser();
519         parser->handleError = errorHandler;
520         jsonParseChunk( parser->ctx, str, strlen(str),  JSON_PARSE_LAST_CHUNK );
521         jsonObject* obj = parser->obj;
522         _jsonInternalParserFree(parser);
523         return obj;
524 }
525
526 jsonObject* jsonParseStringHandleError( 
527                 void (*errorHandler) (const char*), char* str, ... ) {
528         if(!str) return NULL;
529         VA_LIST_TO_STRING(str);
530         return _jsonParseStringImpl(VA_BUF, errorHandler);
531 }
532
533 jsonObject* jsonParseString( const char* str ) {
534         if(!str) return NULL;
535         jsonObject* obj =  _jsonParseStringImpl(str, NULL);
536         jsonObject* obj2 = jsonObjectDecodeClass(obj);
537         jsonObjectFree(obj);
538         return obj2;
539 }
540
541 jsonObject* jsonParseStringRaw( const char* str ) {
542         if(!str) return NULL;
543         return _jsonParseStringImpl(str, NULL);
544 }
545
546 jsonObject* jsonParseStringFmt( const char* str, ... ) {
547         if(!str) return NULL;
548         VA_LIST_TO_STRING(str);
549         return _jsonParseStringImpl(VA_BUF, NULL);
550 }
551
552
553 #define JSON_SHOVE_ITEM(ctx,type)  \
554         jsonInternalParser* p = (jsonInternalParser*) ctx;\
555         _jsonInsertParserItem(p, jsonNewObjectType(type));
556
557 void _jsonHandleStartObject(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_HASH); }
558 void _jsonHandleStartArray(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_ARRAY); }
559 void _jsonHandleNull(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_NULL); }
560
561 void _jsonHandleObjectKey(void* ctx, char* key) {
562         jsonInternalParser* p = (jsonInternalParser*) ctx;
563         free(p->lastkey);
564         p->lastkey = strdup(key);
565 }
566
567 void _jsonHandleEndObject(void* ctx) {
568         jsonInternalParser* p = (jsonInternalParser*) ctx;
569         p->current = p->current->parent;
570 }
571
572 void _jsonHandleEndArray(void* ctx) {
573         jsonInternalParser* p = (jsonInternalParser*) ctx;
574         p->current = p->current->parent;
575 }
576
577 void _jsonHandleString(void* ctx, char* string) {
578         jsonInternalParser* p = (jsonInternalParser*) ctx;
579         _jsonInsertParserItem(p, jsonNewObject(string));
580 }
581
582 void _jsonHandleBool(void* ctx, int boolval) {
583         jsonInternalParser* p = (jsonInternalParser*) ctx;
584         jsonObject* obj = jsonNewObjectType(JSON_BOOL);
585         obj->value.b = boolval;
586         _jsonInsertParserItem(p, obj);
587 }
588
589 void _jsonHandleNumber(void* ctx, double num) {
590         jsonInternalParser* p = (jsonInternalParser*) ctx;
591         _jsonInsertParserItem(p, jsonNewNumberObject(num));
592 }
593
594 void _jsonHandleError(void* ctx, char* str, ...) {
595         jsonInternalParser* p = (jsonInternalParser*) ctx;
596         VA_LIST_TO_STRING(str);
597
598         if( p->handleError ) 
599                 p->handleError(VA_BUF);
600         else 
601                 if( jsonClientErrorCallback ) 
602                         jsonClientErrorCallback(VA_BUF);
603
604         else fprintf(stderr, "%s\n", VA_BUF);
605         jsonObjectFree(p->obj);
606         p->obj = NULL;
607 }
608
609
610 void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo ) {
611
612         if( !p->obj ) {
613
614                 /* new parser, set the new object to our object */
615                 p->obj = p->current = newo;
616
617         } else {
618
619                 /* insert the new object into the current container object */
620                 switch(p->current->type) { 
621                         case JSON_HASH  : jsonObjectSetKey(p->current, p->lastkey, newo);  break;
622                         case JSON_ARRAY: jsonObjectPush(p->current, newo); break;
623                         default: fprintf(stderr, "%s:%d -> how?\n", JSON_LOG_MARK); 
624                 } 
625
626                 /* if the new object is a container object, make it our current container */
627                 if( newo->type == JSON_ARRAY || newo->type == JSON_HASH )
628                         p->current = newo;      
629         }
630 }
631
632