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