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 /* ---------------------------------------------------------------------- */
26 object* new_object(char* string_value) {
27 return _init_object(string_value);
31 object* new_int_object(long num) {
32 object* o = new_object(NULL);
39 object* new_double_object(double num) {
40 object* o = new_object(NULL);
43 o->double_value = num;
47 object* _init_object(char* string_value) {
49 object* obj = (object*) safe_malloc(sizeof(object));
53 obj->push = &object_push;
54 obj->set_index = &object_set_index;
55 obj->add_key = &object_add_key;
56 obj->get_index = &object_get_index;
57 obj->get_key = &object_get_key;
58 obj->get_string = &object_get_string;
59 obj->set_string = &object_set_string;
60 obj->set_number = &object_set_number;
61 obj->set_class = &object_set_class;
62 obj->set_double = &object_set_double;
63 obj->remove_index = &object_remove_index;
64 obj->remove_key = &object_remove_key;
65 obj->to_json = &object_to_json;
66 obj->set_comment = &object_set_comment;
70 obj->string_data = strdup(string_value);
77 object_node* new_object_node(object* obj) {
78 object_node* node = (object_node*) safe_malloc(sizeof(object_node));
85 unsigned long object_push(object* obj, object* new_obj) {
87 object_clear_type(obj);
91 new_obj = new_object(NULL);
95 object_node* node = new_object_node(new_obj);
96 node->index = obj->size++;
98 if( obj->size > MAX_OBJECT_NODES )
101 if(obj->data == NULL) {
105 /* append the node onto the end */
106 object_node* tmp = obj->data;
108 if(tmp->next == NULL) break;
116 unsigned long object_set_index(object* obj, unsigned long index, object* new_obj) {
117 assert(obj != NULL && index <= MAX_OBJECT_NODES);
118 object_clear_type(obj);
121 if(obj->size <= index)
122 obj->size = index + 1;
124 if(new_obj == NULL) {
125 new_obj = new_object(NULL);
126 new_obj->is_null = 1;
129 object_node* node = new_object_node(new_obj);
132 if( obj->data == NULL ) {
137 if(obj->data->index == index) {
138 object_node* tmp = obj->data->next;
139 free_object_node(obj->data);
145 object_node* prev = obj->data;
146 object_node* cur = prev->next;
151 /* replace an existing node */
152 if( cur->index == index ) {
153 object_node* tmp = cur->next;
154 free_object_node(cur);
160 /* instert between two nodes */
161 } else if( prev->index < index && cur->index > index ) {
171 /* shove on to the end */
181 void object_shift_index(object* obj, unsigned long index) {
182 assert(obj && index <= MAX_OBJECT_NODES);
183 if(obj->data == NULL) {
188 object_node* data = obj->data;
190 if(data->index >= index)
197 unsigned long object_remove_index(object* obj, unsigned long index) {
198 assert(obj != NULL && index <= MAX_OBJECT_NODES);
199 if(obj->data == NULL) return 0;
201 /* removing the first item in the list */
202 if(obj->data->index == index) {
203 object_node* tmp = obj->data->next;
204 free_object_node(obj->data);
206 object_shift_index(obj,index);
211 object_node* prev = obj->data;
212 object_node* cur = prev->next;
215 if(cur->index == index) {
216 object_node* tmp = cur->next;
217 free_object_node(cur);
219 object_shift_index(obj,index);
230 unsigned long object_remove_key(object* obj, char* key) {
232 if(obj->data == NULL) return 0;
234 /* removing the first item in the list */
235 if(!strcmp(obj->data->key, key)) {
236 object_node* tmp = obj->data->next;
237 free_object_node(obj->data);
245 object_node* prev = obj->data;
246 object_node* cur = prev->next;
249 if(!strcmp(cur->key,key)) {
250 object_node* tmp = cur->next;
251 free_object_node(cur);
264 unsigned long object_add_key(object* obj, char* key, object* new_obj) {
266 assert(obj != NULL && key != NULL);
267 object_clear_type(obj);
271 if(new_obj == NULL) {
272 new_obj = new_object(NULL);
273 new_obj->is_null = 1;
276 object_node* node = new_object_node(new_obj);
277 node->key = strdup(key);
279 if( obj->data == NULL ) {
285 /* replace the first node */
286 if(!strcmp(obj->data->key, key)) {
287 object_node* tmp = obj->data->next;
288 free_object_node(obj->data);
294 object_node* prev = obj->data;
295 object_node* cur = prev->next;
300 /* replace an existing node */
301 if( !strcmp(cur->key, key) ) {
302 object_node* tmp = cur->next;
303 free_object_node(cur);
314 /* shove on to the end */
326 void free_object(object* obj) {
328 if(obj == NULL) return;
329 if(obj->classname) free(obj->classname);
330 if(obj->comment) free(obj->comment);
333 object_node* tmp = obj->data->next;
334 free_object_node(obj->data);
339 free(obj->string_data);
343 void free_object_node(object_node* node) {
344 if(node == NULL) return;
345 if(node->key) free(node->key);
346 free_object(node->item);
350 object* object_get_index( object* obj, unsigned long index ) {
351 assert(obj != NULL && index <= MAX_OBJECT_NODES);
352 object_node* node = obj->data;
354 if(node->index == index)
361 object* object_get_key( object* obj, char* key ) {
363 object_node* node = obj->data;
366 if(node->key && !strcmp(node->key, key))
374 char* object_get_string(object* obj) {
376 return obj->string_data;
379 void object_set_string(object* obj, char* string) {
381 object_clear_type(obj);
384 obj->string_data = strdup(string);
388 void object_set_number(object* obj, long num) {
390 object_clear_type(obj);
392 obj->num_value = num;
395 void object_set_double(object* obj, double num) {
397 object_clear_type(obj);
399 obj->double_value = num;
403 void object_set_class(object* obj, char* classname) {
404 assert(obj && classname);
405 obj->classname = strdup(classname);
410 char* object_to_json(object* obj) {
413 return strdup("null");
415 growing_buffer* buf = buffer_init(64);
417 /* add class hints if we have a class name */
419 buffer_add(buf,"/*--S ");
420 buffer_add(buf,obj->classname);
421 buffer_add(buf, "--*/");
424 if(obj->is_bool && obj->bool_value)
425 buffer_add(buf, "true");
427 else if(obj->is_bool && ! obj->bool_value)
428 buffer_add(buf, "false");
430 else if(obj->is_number) {
433 sprintf(b, "%ld", obj->num_value);
437 else if(obj->is_double) {
440 sprintf(b, "%lf", obj->double_value);
444 else if(obj->is_null)
445 buffer_add(buf, "null");
447 else if (obj->is_string) {
449 buffer_add(buf, "\"");
450 char* data = obj->string_data;
451 int len = strlen(data);
453 char* output = uescape(data, len, 1);
454 buffer_add(buf, output);
456 buffer_add(buf, "\"");
458 } else if(obj->is_array) {
460 buffer_add(buf, "[");
462 for( i = 0; i!= obj->size; i++ ) {
463 char* data = object_to_json(obj->get_index(obj,i));
464 #ifdef STRICT_JSON_WRITE
465 buffer_add(buf, data);
467 if(strcmp(data,"null")) /* only add the string if it isn't null */
468 buffer_add(buf, data);
471 if(i != obj->size - 1)
472 buffer_add(buf, ",");
474 buffer_add(buf, "]");
476 } else if(obj->is_hash) {
477 buffer_add(buf, "{");
478 object_iterator* itr = new_iterator(obj);
480 while( (tmp = itr->next(itr)) ) {
481 buffer_add(buf, "\"");
482 buffer_add(buf, tmp->key);
483 buffer_add(buf, "\":");
484 char* data = object_to_json(tmp->item);
486 #ifdef STRICT_JSON_WRITE
487 buffer_add(buf, data);
489 if(strcmp(data,"null")) /* only add the string if it isn't null */
490 buffer_add(buf, data);
493 if(itr->has_next(itr))
494 buffer_add(buf, ",");
498 buffer_add(buf, "}");
501 /* close out the object hint */
503 buffer_add(buf, "/*--E ");
504 buffer_add(buf, obj->classname);
505 buffer_add(buf, "--*/");
509 buffer_add(buf, " /*");
510 buffer_add(buf, obj->comment);
511 buffer_add(buf, "*/");
514 char* data = buffer_data(buf);
521 void object_clear_type(object* obj) {
522 if(obj == NULL) return;
531 void object_set_comment(object* obj, char* com) {
533 obj->comment = strdup(com);
538 /* ---------------------------------------------------------------------- */
541 object_iterator* new_iterator(object* obj) {
542 object_iterator* iter = safe_malloc(sizeof(object_iterator));
544 iter->current = obj->data;
545 iter->next = &object_iterator_next;
546 iter->has_next = &object_iterator_has_next;
550 object_node* object_iterator_next(object_iterator* itr) {
551 assert( itr != NULL );
553 object_node* tmp = itr->current;
554 if(tmp == NULL) return NULL;
555 itr->current = itr->current->next;
560 void free_iterator(object_iterator* iter) {
561 if(iter == NULL) return;
565 int object_iterator_has_next(object_iterator* itr) {
567 if(itr->current) return 1;