]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/osrf_json_parser.c
added cache cleanup code
[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         memset(buf, 0, l);
79                 snprintf(buf, l, ctx->chunk + pre);
80                 ctx->handler->handleError( ctx->userData, 
81                         "*JSON Parser Error\n - char  = %c\n "
82                         "- index = %d\n - near  => %s\n - %s", 
83                         ctx->chunk[ctx->index], ctx->index, buf, VA_BUF );
84         }
85         JSON_STATE_SET(ctx, JSON_STATE_IS_INVALID);
86         return -1;
87 }
88
89
90 int _jsonParserHandleUnicode( jsonParserContext* ctx ) {
91
92         /* collect as many of the utf characters as we can in this chunk */
93         JSON_CACHE_DATA(ctx, ctx->utfbuf, 4);
94
95         /* we ran off the end of the chunk */
96         if( ctx->utfbuf->n_used < 4 ) {
97                 JSON_STATE_SET(ctx, JSON_STATE_IN_UTF);
98                 return 1;
99         }
100
101         ctx->index--; /* push it back to index of the final utf char */
102
103         /* ----------------------------------------------------------------------- */
104         /* We have all of the escaped unicode data.  Write it to the buffer */
105         /* The following chunk is used with permission from 
106          * json-c http://oss.metaparadigm.com/json-c/ 
107          */
108         #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
109         unsigned char utf_out[4];
110         memset(utf_out,0,4);
111         char* buf = ctx->utfbuf->buf;
112
113         unsigned int ucs_char =
114                 (hexdigit(buf[0] ) << 12) +
115                 (hexdigit(buf[1]) << 8) +
116                 (hexdigit(buf[2]) << 4) +
117                 hexdigit(buf[3]);
118
119         if (ucs_char < 0x80) {
120                 utf_out[0] = ucs_char;
121                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
122
123         } else if (ucs_char < 0x800) {
124                 utf_out[0] = 0xc0 | (ucs_char >> 6);
125                 utf_out[1] = 0x80 | (ucs_char & 0x3f);
126                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
127
128         } else {
129                 utf_out[0] = 0xe0 | (ucs_char >> 12);
130                 utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
131                 utf_out[2] = 0x80 | (ucs_char & 0x3f);
132                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
133         }
134         /* ----------------------------------------------------------------------- */
135         /* ----------------------------------------------------------------------- */
136
137         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_UTF);
138         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
139         OSRF_BUFFER_RESET(ctx->utfbuf);
140         return 0;
141 }
142
143
144
145 /* type : 0=null, 1=true, 2=false */
146 int _jsonParserHandleMatch( jsonParserContext* ctx, int type ) {
147
148         switch(type) {
149
150                 case 0: /* JSON null */
151
152                         /* first see if we have it all first */
153                         if( ctx->chunksize > (ctx->index + 3) ) {
154                                 if( strncasecmp(ctx->chunk + ctx->index, "null", 4) ) 
155                                         return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
156                                 if( ctx->handler->handleNull ) 
157                                         ctx->handler->handleNull(ctx->userData);
158                                 ctx->index += 4;
159                                 break;
160                         }
161
162                         JSON_CACHE_DATA(ctx, ctx->buffer, 4);
163                         if( ctx->buffer->n_used < 4 ) {
164                                 JSON_STATE_SET(ctx, JSON_STATE_IN_NULL);
165                                 return 1;
166                         } 
167
168                         if( strncasecmp(ctx->buffer->buf, "null", 4) ) 
169                                 return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
170                         if( ctx->handler->handleNull ) 
171                                 ctx->handler->handleNull(ctx->userData);
172                         break;
173
174                 case 1: /* JSON true */
175
176                         /* see if we have it all first */
177                         if( ctx->chunksize > (ctx->index + 3) ) {
178                                 if( strncasecmp(ctx->chunk + ctx->index, "true", 4) ) 
179                                         return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
180                                 if( ctx->handler->handleBool ) 
181                                         ctx->handler->handleBool(ctx->userData, 1);
182                                 ctx->index += 4;
183                                 break;
184                         }
185
186                         JSON_CACHE_DATA(ctx, ctx->buffer, 4);
187                         if( ctx->buffer->n_used < 4 ) {
188                                 JSON_STATE_SET(ctx, JSON_STATE_IN_TRUE);
189                                 return 1;
190                         } 
191                         if( strncasecmp( ctx->buffer->buf, "true", 4 ) ) {
192                                 return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
193                         }
194                         if( ctx->handler->handleBool ) 
195                                 ctx->handler->handleBool(ctx->userData, 1);
196                         break;
197
198                 case 2: /* JSON false */
199
200                         /* see if we have it all first */
201                         if( ctx->chunksize > (ctx->index + 4) ) {
202                                 if( strncasecmp(ctx->chunk + ctx->index, "false", 5) ) 
203                                         return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
204                                 if( ctx->handler->handleBool ) 
205                                         ctx->handler->handleBool(ctx->userData, 0);
206                                 ctx->index += 5;
207                                 break;
208                         }
209
210                         JSON_CACHE_DATA(ctx, ctx->buffer, 5);
211                         if( ctx->buffer->n_used < 5 ) {
212                                 JSON_STATE_SET(ctx, JSON_STATE_IN_FALSE);
213                                 return 1;
214                         }
215                         if( strncasecmp( ctx->buffer->buf, "false", 5 ) ) 
216                                 return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
217                         if( ctx->handler->handleBool ) 
218                                 ctx->handler->handleBool(ctx->userData, 0);
219                         break;
220
221                 default: 
222                         fprintf(stderr, "Invalid type flag\n");
223                         return -1;
224
225         }
226
227         ctx->index--; /* set it back to the index of the final sequence character */
228         OSRF_BUFFER_RESET(ctx->buffer);
229         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NULL);
230         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_TRUE);
231         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_FALSE);
232
233         return 0;
234 }
235
236
237 int _jsonParserHandleString( jsonParserContext* ctx ) {
238
239         char c = ctx->chunk[ctx->index];
240
241         if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_ESCAPE) ) {
242
243                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_UTF) ) {
244
245                         return _jsonParserHandleUnicode( ctx );
246                                                 
247                 } else {
248
249                         switch(c) {
250
251                                 /* handle all of the escape chars */
252                                 case '\\': OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\\' ); break;
253                                 case '"'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\"' ); break;
254                                 case 't'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\t' ); break;
255                                 case 'b'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\b' ); break;
256                                 case 'f'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\f' ); break;
257                                 case 'r'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\r' ); break;
258                                 case 'n'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\n' ); break;
259                                 case 'u'        : 
260                                         ctx->index++; /* progress to the first utf char */
261                                         return _jsonParserHandleUnicode( ctx );
262                                 default : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
263                         }
264                 }
265
266                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
267                 return 0;
268
269         } else {
270
271                 switch(c) {
272
273                         case '"'        : /* this string is ending */
274                                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_KEY) ) {
275
276                                         /* object key */
277                                         if(ctx->handler->handleObjectKey) {
278                                                 ctx->handler->handleObjectKey( 
279                                                         ctx->userData, ctx->buffer->buf);
280                                         }
281
282                                 } else { /* regular json string */
283
284                                         if(ctx->handler->handleString) {
285                                                 ctx->handler->handleString( 
286                                                         ctx->userData, ctx->buffer->buf );
287                                         }
288
289                                 }
290
291                                 OSRF_BUFFER_RESET(ctx->buffer); /* flush the buffer and states */
292                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_STRING);
293                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
294                                 break;
295
296                         case '\\' : JSON_STATE_SET(ctx, JSON_STATE_IN_ESCAPE); break;
297                         default  : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
298                 }
299         }
300         return 0;
301 }
302
303
304 int _jsonParserHandleNumber( jsonParserContext* ctx ) {
305         char c = ctx->chunk[ctx->index];
306
307         do {
308                 OSRF_BUFFER_ADD_CHAR(ctx->buffer, c);
309                 c = ctx->chunk[++(ctx->index)];
310         } while( strchr(JSON_NUMBER_CHARS, c) && ctx->index < ctx->chunksize );
311
312         /* if we're run off the end of the chunk and we're not parsing the last chunk,
313          * save the number and the state */
314         if( ctx->index >= ctx->chunksize && 
315                         ! JSON_PARSE_FLAG_CHECK(ctx, JSON_PARSE_LAST_CHUNK) ) {
316                 JSON_STATE_SET(ctx, JSON_STATE_IN_NUMBER);
317                 return 1;
318         }
319
320         /* make me more strict */
321         char* err = NULL;
322         double d = strtod(ctx->buffer->buf, &err);
323         if(err && err[0] != '\0') 
324                 return _jsonParserError(ctx, "Invalid number sequence");
325         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER);
326         OSRF_BUFFER_RESET(ctx->buffer);
327         if(ctx->handler->handleNumber)
328                 ctx->handler->handleNumber( ctx->userData, d );
329         ctx->index--; /* scooch back to the first non-digit number */
330         return 0;
331 }
332
333
334
335
336 int jsonParseChunk( jsonParserContext* ctx, char* data, int datalen, int flags ) {
337
338         if( !( ctx && ctx->handler && data && datalen > 0 )) return -1;
339         ctx->chunksize  = datalen;
340         ctx->chunk              = data;
341         ctx->flags              = flags;
342         char c;
343
344         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_INVALID) )
345                 return _jsonParserError( ctx, "JSON Parser cannot continue after an error" );
346
347         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_DONE) )
348                 return _jsonParserError( ctx, "Extra content at end of JSON data" );
349
350         for( ctx->index = 0; (ctx->index < ctx->chunksize) && 
351                                 (c = ctx->chunk[ctx->index]); ctx->index++ ) {
352
353                 /* middle of parsing a string */
354                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_STRING)) {
355                         if( _jsonParserHandleString(ctx) == -1 )
356                                 return -1;
357                         continue;
358                 }
359
360                 /* middle of parsing a number */
361                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_NUMBER) ) {
362                         if( _jsonParserHandleNumber(ctx) == -1 )
363                                 return -1;
364                         continue;
365                 }
366
367
368 #ifdef OSRF_JSON_ALLOW_COMMENTS
369                 /* we just saw a bare '/' character */
370                 if( JSON_STATE_CHECK(ctx, JSON_STATE_START_COMMENT) ) {
371                         if(c == '*') {
372                                 JSON_STATE_REMOVE(ctx, JSON_STATE_START_COMMENT);
373                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
374                                 continue;
375                         } else {
376                                 return _jsonParserError( ctx, "Invalid comment initializer" );
377                         }
378                 }
379
380                 /* we're currently in the middle of a comment block */
381                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_COMMENT) ) {
382                         if(c == '*') {
383                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_COMMENT);
384                                 JSON_STATE_SET(ctx, JSON_STATE_END_COMMENT);
385                                 continue;
386                         } else {
387                                 continue;
388                         }
389                 }
390
391                 /* we're in a comment, and we just saw a '*' character */
392                 if( JSON_STATE_CHECK(ctx, JSON_STATE_END_COMMENT) ) {
393                         if( c == '/' ) { /* comment is finished */
394                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
395                                 continue;
396                         } else {
397                                 /* looks like this isn't the end of the comment after all */
398                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
399                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
400                         }
401                 }
402 #endif
403
404                 /* if we're in the middle of parsing a null/true/false sequence */
405                 if( JSON_STATE_CHECK(ctx, (JSON_STATE_IN_NULL | 
406                                         JSON_STATE_IN_TRUE | JSON_STATE_IN_FALSE)) ) {
407
408                         int type = (JSON_STATE_CHECK(ctx, JSON_STATE_IN_NULL)) ? 0 :
409                                 (JSON_STATE_CHECK(ctx, JSON_STATE_IN_TRUE)) ? 1 : 2;
410
411                         if( _jsonParserHandleMatch( ctx, type ) == -1 ) 
412                                 return -1;
413                         continue;
414                 }
415
416                 JSON_EAT_WS(ctx);
417
418                 /* handle all of the top level characters */
419                 switch(c) {
420
421                         case '{' : /* starting an object */
422                                 if( ctx->handler->handleStartObject) 
423                                         ctx->handler->handleStartObject( ctx->userData );
424                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_OBJECT);
425                                 JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
426                                 break;
427
428                         case '}' : /* ending an object */
429                                 if( ctx->handler->handleEndObject) 
430                                         ctx->handler->handleEndObject( ctx->userData ); 
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(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( 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( char* str ) {
542         if(!str) return NULL;
543         return _jsonParseStringImpl(str, NULL);
544 }
545
546 jsonObject* jsonParseStringFmt( 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