]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/objson/object.c
added license info and some additional comments
[Evergreen.git] / OpenSRF / src / objson / object.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service 
3 Bill Erickson <highfalutin@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 "object.h"
17 #include "json_parser.h"
18 #include <fcntl.h>
19
20
21
22 /* ---------------------------------------------------------------------- */
23 /* See object.h for function info */
24 /* ---------------------------------------------------------------------- */
25
26 object* new_object(char* string_value) {
27         return _init_object(string_value);
28 }
29
30 object* _init_object(char* string_value) {
31
32         object* obj                     = (object*) safe_malloc(sizeof(object));
33         obj->size                       = 0;
34         obj->data                       = NULL;
35
36         obj->push                       = &object_push;
37         obj->set_index          = &object_set_index;
38         obj->add_key            = &object_add_key;
39         obj->get_index          = &object_get_index;
40         obj->get_key            = &object_get_key;
41         obj->get_string = &object_get_string;
42         obj->set_string = &object_set_string;
43         obj->set_number = &object_set_number;
44         obj->set_class          = &object_set_class;
45         obj->set_double = &object_set_double;
46         obj->remove_index = &object_remove_index;
47         obj->remove_key = &object_remove_key;
48         obj->to_json            = &object_to_json;
49         obj->set_comment        = &object_set_comment;
50
51         if(string_value) {
52                 obj->is_string = 1;
53                 obj->string_data = strdup(string_value);
54         } else
55                 obj->is_null = 1;
56
57         return obj;
58 }
59
60 object_node* new_object_node(object* obj) {
61         object_node* node = (object_node*) safe_malloc(sizeof(object_node));
62         node->item = obj;
63         node->next = NULL;
64         node->index = -1;
65         return node;
66 }
67
68 unsigned long object_push(object* obj, object* new_obj) {
69         assert(obj != NULL);
70         object_clear_type(obj);
71         obj->is_array = 1;
72
73         if(new_obj == NULL) {
74                 new_obj = new_object(NULL);
75                 new_obj->is_null = 1;
76         }
77
78         object_node* node = new_object_node(new_obj);
79         node->index = obj->size++;
80
81         if( obj->size > MAX_OBJECT_NODES )
82                 return -1;
83
84         if(obj->data == NULL) {
85                 obj->data = node;
86
87         } else {
88                 /* append the node onto the end */
89                 object_node* tmp = obj->data;
90                 while(tmp) {
91                         if(tmp->next == NULL) break;
92                         tmp = tmp->next;
93                 }
94                 tmp->next = node;
95         }
96         return obj->size;
97 }
98
99 unsigned long  object_set_index(object* obj, unsigned long index, object* new_obj) {
100         assert(obj != NULL && index <= MAX_OBJECT_NODES);
101         object_clear_type(obj);
102         obj->is_array = 1;
103
104         if(obj->size <= index)
105                 obj->size = index + 1;
106
107         if(new_obj == NULL) {
108                 new_obj = new_object(NULL);
109                 new_obj->is_null = 1;
110         }
111
112         object_node* node = new_object_node(new_obj);
113         node->index = index;
114         
115         if( obj->data == NULL ) {
116                 obj->data = node;
117
118         } else {
119
120                 if(obj->data->index == index) {
121                         object_node* tmp = obj->data->next;
122                         free_object_node(obj->data);
123                         obj->data = node;
124                         node->next = tmp;
125
126                 } else {
127                 
128                         object_node* prev = obj->data;
129                         object_node* cur = prev->next;
130                         int inserted = 0;
131
132                         while(cur != NULL) {
133
134                                 /* replace an existing node */
135                                 if( cur->index == index ) {
136                                         object_node* tmp = cur->next;
137                                         free_object_node(cur);
138                                         node->next = tmp;
139                                         prev->next = node;
140                                         inserted = 1;
141                                         break;
142                                         
143                                         /* instert between two nodes */
144                                 } else if( prev->index < index && cur->index > index ) {
145                                         prev->next = node;
146                                         node->next = cur;
147                                         inserted = 1;
148                                         break;
149                                 }
150                                 prev = cur;
151                                 cur = cur->next;
152                         }
153
154                         /* shove on to the end */
155                         if(!inserted) 
156                                 prev->next = node;
157                 }
158         }
159
160         return obj->size;
161 }
162
163
164 void object_shift_index(object* obj, unsigned long index) {
165         assert(obj && index <= MAX_OBJECT_NODES);
166         if(obj->data == NULL) {
167                 obj->size = 0;
168                 return;
169         }
170
171         object_node* data = obj->data;
172         while(data) {
173                 if(data->index >= index)
174                         data->index--;
175                 data = data->next;
176         }
177         obj->size--;
178 }
179
180 unsigned long object_remove_index(object* obj, unsigned long index) {
181         assert(obj != NULL && index <= MAX_OBJECT_NODES);
182         if(obj->data == NULL) return 0;
183
184         /* removing the first item in the list */
185         if(obj->data->index == index) {
186                 object_node* tmp = obj->data->next;
187                 free_object_node(obj->data);
188                 obj->data = tmp;
189                 object_shift_index(obj,index);
190                 return obj->size;
191         }
192
193
194         object_node* prev = obj->data;
195         object_node* cur = prev->next;
196
197         while(cur) {
198                 if(cur->index == index) {
199                         object_node* tmp = cur->next;
200                         free_object_node(cur);
201                         prev->next = tmp;
202                         object_shift_index(obj,index);
203                         break;
204                 }
205                 prev = cur;
206                 cur = cur->next;
207         }
208
209         return obj->size;       
210 }
211
212
213 unsigned long object_remove_key(object* obj, char* key) {
214         assert(obj && key);
215         if(obj->data == NULL) return 0;
216
217         /* removing the first item in the list */
218         if(!strcmp(obj->data->key, key)) {
219                 object_node* tmp = obj->data->next;
220                 free_object_node(obj->data);
221                 obj->data = tmp;
222                 if(!obj->data) 
223                         obj->size = 0;
224
225                 return obj->size;
226         }
227
228         object_node* prev = obj->data;
229         object_node* cur = prev->next;
230
231         while(cur) {
232                 if(!strcmp(cur->key,key)) {
233                         object_node* tmp = cur->next;
234                         free_object_node(cur);
235                         prev->next = tmp;
236                         obj->size--;
237                         break;
238                 }
239                 prev = cur;
240                 cur = cur->next;
241         }
242
243         return obj->size;
244 }
245
246
247 unsigned long object_add_key(object* obj, char* key, object* new_obj) {
248
249         assert(obj != NULL && key != NULL);
250         object_clear_type(obj);
251         obj->is_hash = 1;
252
253
254         if(new_obj == NULL) {
255                 new_obj = new_object(NULL);
256                 new_obj->is_null = 1;
257         }
258
259         object_node* node = new_object_node(new_obj);
260         node->key = strdup(key);
261         
262         if( obj->data == NULL ) {
263                 obj->data = node;
264                 obj->size++;
265
266         } else {
267
268                 /* replace the first node */
269                 if(!strcmp(obj->data->key, key)) {
270                         object_node* tmp = obj->data->next;
271                         free_object_node(obj->data);
272                         obj->data = node;
273                         node->next = tmp;
274
275                 } else {
276                 
277                         object_node* prev = obj->data;
278                         object_node* cur = prev->next;
279                         int inserted = 0;
280
281                         while(cur != NULL) {
282
283                                 /* replace an existing node */
284                                 if( !strcmp(cur->key, key) ) {
285                                         object_node* tmp = cur->next;
286                                         free_object_node(cur);
287                                         node->next = tmp;
288                                         prev->next = node;
289                                         inserted = 1;
290                                         break;
291                                 }
292                                         
293                                 prev = cur;
294                                 cur = cur->next;
295                         }
296
297                         /* shove on to the end */
298                         if(!inserted) {
299                                 prev->next = node;
300                                 obj->size++;
301                         }
302                 }
303         }
304
305         return obj->size;
306 }
307
308
309 void free_object(object* obj) {
310
311         if(obj == NULL) return;
312         if(obj->classname) free(obj->classname);
313         if(obj->comment) free(obj->comment);
314
315         while(obj->data) {
316                 object_node* tmp = obj->data->next;
317                 free_object_node(obj->data);
318                 obj->data = tmp;
319         }
320
321         if(obj->string_data) 
322                 free(obj->string_data);
323         free(obj);
324 }
325
326 void free_object_node(object_node* node) {
327         if(node == NULL) return;
328         if(node->key) free(node->key);
329         free_object(node->item);
330         free(node);
331 }
332
333 object* object_get_index( object* obj, unsigned long index ) {
334         assert(obj != NULL && index <= MAX_OBJECT_NODES);
335         object_node* node = obj->data;
336         while(node) {
337                 if(node->index == index)
338                         return node->item;
339                 node = node->next;
340         }
341         return NULL;
342 }
343
344 object* object_get_key( object* obj, char* key ) {
345         assert(obj && key);
346         object_node* node = obj->data;
347
348         while(node) {
349                 if(node->key && !strcmp(node->key, key))
350                         return node->item;
351                 node = node->next;
352         }       
353
354         return NULL;
355 }
356
357 char* object_get_string(object* obj) {
358         assert(obj != NULL);
359         return obj->string_data;
360 }
361
362 void object_set_string(object* obj, char* string) {
363         assert(obj);
364         object_clear_type(obj);
365         obj->is_string = 1;
366         if(string)
367                 obj->string_data = strdup(string);
368 }
369
370
371 void object_set_number(object* obj, long num) {
372         assert(obj);
373         object_clear_type(obj);
374         obj->is_number = 1;
375         obj->num_value = num;
376 }
377
378 void object_set_double(object* obj, double num) {
379         assert(obj);
380         object_clear_type(obj);
381         obj->is_double = 1;
382         obj->double_value = num;
383 }
384
385
386 void object_set_class(object* obj, char* classname) {
387         assert(obj && classname);
388         obj->classname = strdup(classname);
389 }
390
391
392
393 char* object_to_json(object* obj) {
394
395         if(obj == NULL)
396                 return strdup("null");
397
398         growing_buffer* buf = buffer_init(64);
399
400         /* add class hints if we have a class name */
401         if(obj->classname) {
402                 buffer_add(buf,"/*--S ");
403                 buffer_add(buf,obj->classname);
404                 buffer_add(buf, "--*/");
405         }
406
407         if(obj->is_bool && obj->bool_value)
408                         buffer_add(buf, "true"); 
409
410         else if(obj->is_bool && ! obj->bool_value)
411                         buffer_add(buf, "false"); 
412
413         else if(obj->is_number) {
414                 char b[128];
415                 memset(b, 0, 128);
416                 sprintf(b, "%ld", obj->num_value);
417                 buffer_add(buf, b);
418         }
419
420         else if(obj->is_double) {
421                 char b[128];
422                 memset(b, 0, 128);
423                 sprintf(b, "%lf", obj->double_value);
424                 buffer_add(buf, b);
425         }
426
427         if(obj->is_null)
428                 buffer_add(buf, "null");
429
430         else if (obj->is_string) {
431
432                 buffer_add(buf, "\"");
433                 char* data = obj->string_data;
434                 int len = strlen(data);
435                 
436                 char* output = uescape(data, len, 1);
437                 buffer_add(buf, output);
438                 free(output);
439                 buffer_add(buf, "\"");
440
441         }  else if(obj->is_array) {
442
443                 buffer_add(buf, "[");
444                 int i;
445                 for( i = 0; i!= obj->size; i++ ) {
446                         char* data = object_to_json(obj->get_index(obj,i));
447                         buffer_add(buf, data);
448                         free(data);
449                         if(i != obj->size - 1)
450                                 buffer_add(buf, ",");
451                 }
452                 buffer_add(buf, "]");
453
454         } else if(obj->is_hash) {
455                 buffer_add(buf, "{");
456                 object_iterator* itr = new_iterator(obj);
457                 object_node* tmp;
458                 while( (tmp = itr->next(itr)) ) {
459                         buffer_add(buf, "\"");
460                         buffer_add(buf, tmp->key);
461                         buffer_add(buf, "\":");
462                         char* data =  object_to_json(tmp->item);
463                         buffer_add(buf, data);
464                         if(itr->has_next(itr))
465                                 buffer_add(buf, ",");
466                         free(data);
467                 }
468                 free_iterator(itr);
469                 buffer_add(buf, "}");
470         }
471
472         /* close out the object hint */
473         if(obj->classname) {
474                 buffer_add(buf, "/*--E ");
475                 buffer_add(buf, obj->classname);
476                 buffer_add(buf, "--*/");
477         }
478
479         if(obj->comment) {
480                 buffer_add(buf, " /*");
481                 buffer_add(buf, obj->comment);
482                 buffer_add(buf, "*/");
483         }
484
485         char* data = buffer_data(buf);
486         buffer_free(buf);
487         return data;
488
489 }
490
491
492 void object_clear_type(object* obj) {
493         if(obj == NULL) return;
494         obj->is_string = 0;
495         obj->is_hash    = 0;
496         obj->is_array   = 0;
497         obj->is_bool    = 0;
498         obj->is_null    = 0;
499 }
500
501
502 void object_set_comment(object* obj, char* com) {
503         assert(obj && com);
504         obj->comment = strdup(com);
505 }
506
507
508
509 /* ---------------------------------------------------------------------- */
510 /* Iterator */
511
512 object_iterator* new_iterator(object* obj) {
513         object_iterator* iter = safe_malloc(sizeof(object_iterator));
514         iter->obj = obj;
515         iter->current = obj->data;
516         iter->next = &object_iterator_next;
517         iter->has_next = &object_iterator_has_next;
518         return iter;
519 }
520
521 object_node* object_iterator_next(object_iterator* itr) {
522         assert( itr != NULL );
523
524         object_node* tmp = itr->current;
525         if(tmp == NULL) return NULL;
526         itr->current = itr->current->next;
527
528         return tmp;
529 }
530
531 void free_iterator(object_iterator* iter) { 
532         if(iter == NULL) return;
533         free(iter);
534 }
535
536 int object_iterator_has_next(object_iterator* itr) {
537         assert(itr);
538         if(itr->current) return 1;
539         return 0;
540 }
541
542