2 Copyright (C) 2005 Georgia Public Library Service
3 Bill Erickson <highfalutin@gmail.com>
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.
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.
17 #include "json_parser.h"
22 /* ---------------------------------------------------------------------- */
23 /* See object.h for function info */
24 /* ---------------------------------------------------------------------- */
27 char* __tabs(int count);
29 object* new_object(char* string_value) {
30 return _init_object(string_value);
34 object* new_int_object(long num) {
35 object* o = new_object(NULL);
42 object* new_double_object(double num) {
43 object* o = new_object(NULL);
46 o->double_value = num;
50 object* _init_object(char* string_value) {
52 object* obj = (object*) safe_malloc(sizeof(object));
56 obj->push = &object_push;
57 obj->set_index = &object_set_index;
58 obj->add_key = &object_add_key;
59 obj->get_index = &object_get_index;
60 obj->get_key = &object_get_key;
61 obj->get_string = &object_get_string;
62 obj->set_string = &object_set_string;
63 obj->set_number = &object_set_number;
64 obj->set_class = &object_set_class;
65 obj->set_double = &object_set_double;
66 obj->remove_index = &object_remove_index;
67 obj->remove_key = &object_remove_key;
68 obj->to_json = &object_to_json;
69 obj->set_comment = &object_set_comment;
73 obj->string_data = strdup(string_value);
80 object_node* new_object_node(object* obj) {
81 object_node* node = (object_node*) safe_malloc(sizeof(object_node));
88 unsigned long object_push(object* obj, object* new_obj) {
90 object_clear_type(obj);
94 new_obj = new_object(NULL);
98 object_node* node = new_object_node(new_obj);
99 node->index = obj->size++;
101 if( obj->size > MAX_OBJECT_NODES )
104 if(obj->data == NULL) {
108 /* append the node onto the end */
109 object_node* tmp = obj->data;
111 if(tmp->next == NULL) break;
119 unsigned long object_set_index(object* obj, unsigned long index, object* new_obj) {
120 assert(obj != NULL && index <= MAX_OBJECT_NODES);
121 object_clear_type(obj);
124 if(obj->size <= index)
125 obj->size = index + 1;
127 if(new_obj == NULL) {
128 new_obj = new_object(NULL);
129 new_obj->is_null = 1;
132 object_node* node = new_object_node(new_obj);
135 if( obj->data == NULL ) {
140 if(obj->data->index == index) {
141 object_node* tmp = obj->data->next;
142 free_object_node(obj->data);
148 object_node* prev = obj->data;
149 object_node* cur = prev->next;
154 /* replace an existing node */
155 if( cur->index == index ) {
156 object_node* tmp = cur->next;
157 free_object_node(cur);
163 /* instert between two nodes */
164 } else if( prev->index < index && cur->index > index ) {
174 /* shove on to the end */
184 void object_shift_index(object* obj, unsigned long index) {
185 assert(obj && index <= MAX_OBJECT_NODES);
186 if(obj->data == NULL) {
191 object_node* data = obj->data;
193 if(data->index >= index)
200 unsigned long object_remove_index(object* obj, unsigned long index) {
201 assert(obj != NULL && index <= MAX_OBJECT_NODES);
202 if(obj->data == NULL) return 0;
204 /* removing the first item in the list */
205 if(obj->data->index == index) {
206 object_node* tmp = obj->data->next;
207 free_object_node(obj->data);
209 object_shift_index(obj,index);
214 object_node* prev = obj->data;
215 object_node* cur = prev->next;
218 if(cur->index == index) {
219 object_node* tmp = cur->next;
220 free_object_node(cur);
222 object_shift_index(obj,index);
233 unsigned long object_remove_key(object* obj, char* key) {
235 if(obj->data == NULL) return 0;
237 /* removing the first item in the list */
238 if(!strcmp(obj->data->key, key)) {
239 object_node* tmp = obj->data->next;
240 free_object_node(obj->data);
248 object_node* prev = obj->data;
249 object_node* cur = prev->next;
252 if(!strcmp(cur->key,key)) {
253 object_node* tmp = cur->next;
254 free_object_node(cur);
267 unsigned long object_add_key(object* obj, char* key, object* new_obj) {
269 assert(obj != NULL && key != NULL);
270 object_clear_type(obj);
274 if(new_obj == NULL) {
275 new_obj = new_object(NULL);
276 new_obj->is_null = 1;
279 object_node* node = new_object_node(new_obj);
280 node->key = strdup(key);
282 if( obj->data == NULL ) {
288 /* replace the first node */
289 if(!strcmp(obj->data->key, key)) {
290 object_node* tmp = obj->data->next;
291 free_object_node(obj->data);
297 object_node* prev = obj->data;
298 object_node* cur = prev->next;
303 /* replace an existing node */
304 if( !strcmp(cur->key, key) ) {
305 object_node* tmp = cur->next;
306 free_object_node(cur);
317 /* shove on to the end */
329 void free_object(object* obj) {
331 if(obj == NULL) return;
332 if(obj->classname) free(obj->classname);
333 if(obj->comment) free(obj->comment);
336 object_node* tmp = obj->data->next;
337 free_object_node(obj->data);
342 free(obj->string_data);
346 void free_object_node(object_node* node) {
347 if(node == NULL) return;
348 if(node->key) free(node->key);
349 free_object(node->item);
353 object* object_get_index( object* obj, unsigned long index ) {
354 assert(obj != NULL && index <= MAX_OBJECT_NODES);
355 object_node* node = obj->data;
357 if(node->index == index)
364 object* object_get_key( object* obj, char* key ) {
366 object_node* node = obj->data;
369 if(node->key && !strcmp(node->key, key))
377 char* object_get_string(object* obj) {
379 return obj->string_data;
382 void object_set_string(object* obj, char* string) {
384 object_clear_type(obj);
387 obj->string_data = strdup(string);
391 void object_set_number(object* obj, long num) {
393 object_clear_type(obj);
395 obj->num_value = num;
398 void object_set_double(object* obj, double num) {
400 object_clear_type(obj);
402 obj->double_value = num;
406 void object_set_class(object* obj, char* classname) {
407 assert(obj && classname);
408 obj->classname = strdup(classname);
413 char* object_to_json(object* obj) {
416 return strdup("null");
418 growing_buffer* buf = buffer_init(64);
420 /* add class hints if we have a class name */
422 buffer_add(buf,"/*--S ");
423 buffer_add(buf,obj->classname);
424 buffer_add(buf, "--*/");
427 if(obj->is_bool && obj->bool_value)
428 buffer_add(buf, "true");
430 else if(obj->is_bool && ! obj->bool_value)
431 buffer_add(buf, "false");
433 else if(obj->is_number) {
436 sprintf(b, "%ld", obj->num_value);
440 else if(obj->is_double) {
443 sprintf(b, "%lf", obj->double_value);
447 else if(obj->is_null)
448 buffer_add(buf, "null");
450 else if (obj->is_string) {
452 buffer_add(buf, "\"");
453 char* data = obj->string_data;
454 int len = strlen(data);
456 char* output = uescape(data, len, 1);
457 buffer_add(buf, output);
459 buffer_add(buf, "\"");
461 } else if(obj->is_array) {
463 buffer_add(buf, "[");
465 for( i = 0; i!= obj->size; i++ ) {
466 char* data = object_to_json(obj->get_index(obj,i));
468 #ifdef STRICT_JSON_WRITE
469 buffer_add(buf, data);
471 if(strcmp(data,"null")) /* only add the string if it isn't null */
472 buffer_add(buf, data);
476 if(i != obj->size - 1)
477 buffer_add(buf, ",");
479 buffer_add(buf, "]");
481 } else if(obj->is_hash) {
483 buffer_add(buf, "{");
484 object_iterator* itr = new_iterator(obj);
487 while( (tmp = itr->next(itr)) ) {
488 buffer_add(buf, "\"");
489 buffer_add(buf, tmp->key);
490 buffer_add(buf, "\":");
491 char* data = object_to_json(tmp->item);
493 #ifdef STRICT_JSON_WRITE
494 buffer_add(buf, data);
496 if(strcmp(data,"null")) /* only add the string if it isn't null */
497 buffer_add(buf, data);
500 if(itr->has_next(itr))
501 buffer_add(buf, ",");
505 buffer_add(buf, "}");
508 /* close out the object hint */
510 buffer_add(buf, "/*--E ");
511 buffer_add(buf, obj->classname);
512 buffer_add(buf, "--*/");
516 buffer_add(buf, " /*");
517 buffer_add(buf, obj->comment);
518 buffer_add(buf, "*/");
521 char* data = buffer_data(buf);
528 void object_clear_type(object* obj) {
529 if(obj == NULL) return;
538 void object_set_comment(object* obj, char* com) {
540 obj->comment = strdup(com);
544 char* __tabs(int count) {
545 growing_buffer* buf = buffer_init(24);
547 for(i=0;i!=count;i++) buffer_add(buf, " ");
548 char* final = buffer_data( buf );
553 char* json_string_format(char* string) {
555 if(!string) return strdup("");
557 growing_buffer* buf = buffer_init(64);
561 for(i=0; i!= strlen(string); i++) {
563 if( string[i] == '{' || string[i] == '[' ) {
565 char* tab = __tabs(++depth);
566 buffer_fadd( buf, "%c\n%s", string[i], tab);
569 } else if( string[i] == '}' || string[i] == ']' ) {
571 char* tab = __tabs(--depth);
572 buffer_fadd( buf, "\n%s%c", tab, string[i]);
575 if(string[i+1] != ',') {
577 buffer_fadd( buf, "\n%s", tab );
581 } else if( string[i] == ',' ) {
583 char* tab = __tabs(depth);
584 buffer_fadd(buf, ",\n%s", tab);
587 } else { buffer_add_char(buf, string[i]); }
591 char* result = buffer_data(buf);
598 object* object_clone(object* o) {
600 char* json = o->to_json(o);
601 object* newo = json_parse_string(json);
608 /* ---------------------------------------------------------------------- */
611 object_iterator* new_iterator(object* obj) {
612 object_iterator* iter = safe_malloc(sizeof(object_iterator));
614 iter->current = obj->data;
615 iter->next = &object_iterator_next;
616 iter->has_next = &object_iterator_has_next;
620 object_node* object_iterator_next(object_iterator* itr) {
621 assert( itr != NULL );
623 object_node* tmp = itr->current;
624 if(tmp == NULL) return NULL;
625 itr->current = itr->current->next;
630 void free_iterator(object_iterator* iter) {
631 if(iter == NULL) return;
635 int object_iterator_has_next(object_iterator* itr) {
637 if(itr->current) return 1;
642 object* object_find_path(object* obj, char* format, ...) {
643 if(!obj || !format || strlen(format) < 1) return NULL;
645 /* build the string from the variable args */
647 va_list args, a_copy;
649 va_copy(a_copy, args);
651 va_start(args, format);
652 len = va_list_size(format, args);
656 va_start(a_copy, format);
657 vsnprintf(buf, len - 1, format, a_copy);
659 /* -------------------------------------------- */
662 /* tmp storage for strtok_r */
670 char* pathcopy = strdup(buf);
672 /* grab the root of the path */
673 token = strtok_r(t, "/", &tt);
675 if(!token) return NULL;
677 /* special case where path starts with // (start anywhere) */
678 if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
679 object* it = _object_find_path_recurse(obj, token, pathcopy + 1);
687 obj = obj->get_key(obj, token);
688 } while( (token = strtok_r(NULL, "/", &tt)) && obj);
690 return object_clone(obj);
695 object* _object_find_path_recurse(object* obj, char* root, char* path) {
697 if(!obj || ! root) return NULL;
698 object* arr = __object_find_path_recurse(obj, root);
699 object* newarr = json_parse_string("[]");
703 /* path is just /root or /root/ */
704 if( strlen(root) + 2 >= strlen(path) ) {
708 for( i = 0; i < arr->size; i++ ) {
710 fprintf(stderr, "Searching root %s and path %s and size %ld\n", root, path + strlen(root) + 1, arr->size);
712 object* a = arr->get_index(arr, i);
713 object* thing = object_find_path(a , path + strlen(root) + 1);
714 if(thing) newarr->push(newarr, thing);
722 object* __object_find_path_recurse(object* obj, char* root) {
724 object* arr = json_parse_string("[]");
726 object* o = obj->get_key(obj, root);
727 if(o) arr->push(arr, object_clone(o));
729 object_node* tmp = NULL;
731 object_iterator* itr = new_iterator(obj);
733 while( (tmp = itr->next(itr)) ) {
734 childarr = __object_find_path_recurse(tmp->item, root);
735 if(childarr && childarr->size > 0) {
737 for( i = 0; i!= childarr->size; i++ ) {
738 arr->push(arr, object_clone(childarr->get_index(childarr, i)));
742 free_object(childarr);