git-svn-id: http://svn.metaparadigm.com/svn/json-c/trunk@2 327403b1-1117-474d-bef2-5cb71233fd97tags/json-c-0.10-20120530
| @@ -0,0 +1,40 @@ | |||||
| # $Id: Makefile,v 1.4 2004/07/22 01:37:44 mclark Exp $ | |||||
| CFLAGS += -g -Wall -std=gnu99 -D_GNU_SOURCE -D_REENTRANT | |||||
| LDFLAGS += | |||||
| LDLIBS += | |||||
| LIB_OBJS = debug.o \ | |||||
| linkhash.o \ | |||||
| printbuf.o \ | |||||
| arraylist.o \ | |||||
| json_object.o \ | |||||
| json_tokener.o | |||||
| LIB_HDRS = debug.h \ | |||||
| linkhash.h \ | |||||
| printbuf.h \ | |||||
| arraylist.h \ | |||||
| json_object.h \ | |||||
| json_tokener.h | |||||
| TESTS = test1 test2 | |||||
| all: tests | |||||
| tests: $(TESTS) | |||||
| test1: test1.o $(LIB_OBJS) | |||||
| test2: test2.o $(LIB_OBJS) | |||||
| clean: | |||||
| rm -f *.o *~ $(TESTS) | |||||
| cex.o: cex.c cex.h | |||||
| debug.o: debug.c debug.h | |||||
| linkhash.o: linkhash.c linkhash.h | |||||
| arraylist.o: arraylist.c arraylist.h | |||||
| json_object.o: json_object.c $(LIB_HDRS) | |||||
| json_tokener.o: json_tokener.c $(LIB_HDRS) | |||||
| test1.o: test1.c $(LIB_HDRS) | |||||
| test2.o: test2.c $(LIB_HDRS) | |||||
| @@ -0,0 +1,32 @@ | |||||
| <h2>JSON-C - A JSON implementation in C</h2> | |||||
| <p>Latest release: <a href="json-c-0.1.tar.gz">json-c-0.1.tar.gz</a></p> | |||||
| <p>JSON-C implements a reference counting object model that allows you | |||||
| to easily construct JSON objects in C, output them as JSON formatted strings | |||||
| and parse JSON formatted strings back into the C representation of JSON | |||||
| objects.</p> | |||||
| <p>Minimal documentation exists <a href="doc/html/json__object_8h.html">here</a>, | |||||
| Although you are probably better reading the example code in test1.c.</p> | |||||
| <p>JSON-C currently depends on some gcc 3.0+ features so can probably only be | |||||
| compiled with gcc 3.0+. It also uses some specifc glibc functions such as | |||||
| vasprintf. Patches welcome to port to other compilers / platforms.</p> | |||||
| <p>Please send bug reports to <a href="mailto:michael@metaparadigm.com">michael@metaparadigm.com</a></p> | |||||
| <h3>Anonymous CVS</h3> | |||||
| <p><code># <b>export CVSROOT=:pserver:anoncvs@cvs.metaparadigm.com:/cvsroot</b><br> | |||||
| # <b>cvs login</b><br> | |||||
| Logging in to :pserver:anoncvs@cvs.metaparadigm.com:2401/cvsroot<br> | |||||
| CVS password: <enter '<b>anoncvs</b>'><br> | |||||
| # <b>cvs co json-c</b></code></p> | |||||
| <p>Copyright Metaparadigm Pte. Ltd. 2004. <a href="mailto:michael@metaparadigm.com">Michael Clark </a></p> | |||||
| <p>This program is free software; you can redistribute it and/or | |||||
| modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| License as published by the Free Software Foundation; either | |||||
| version 2.1 of the License, or (at your option) any later version.</p> | |||||
| <hr> | |||||
| @@ -0,0 +1,94 @@ | |||||
| /* | |||||
| * $Id: arraylist.c,v 1.2 2004/07/21 01:24:33 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <strings.h> | |||||
| #include "bits.h" | |||||
| #include "arraylist.h" | |||||
| struct array_list* | |||||
| array_list_new(array_list_free_fn *free_fn) | |||||
| { | |||||
| struct array_list *this; | |||||
| if(!(this = calloc(1, sizeof(struct array_list)))) return NULL; | |||||
| this->size = ARRAY_LIST_DEFAULT_SIZE; | |||||
| this->length = 0; | |||||
| this->free_fn = free_fn; | |||||
| if(!(this->array = calloc(sizeof(void*), this->size))) { | |||||
| free(this); | |||||
| return NULL; | |||||
| } | |||||
| return this; | |||||
| } | |||||
| extern void | |||||
| array_list_free(struct array_list *this) | |||||
| { | |||||
| int i; | |||||
| for(i = 0; i < this->length; i++) | |||||
| if(this->array[i]) this->free_fn(this->array[i]); | |||||
| free(this->array); | |||||
| free(this); | |||||
| } | |||||
| void* | |||||
| array_list_get_idx(struct array_list *this, int i) | |||||
| { | |||||
| if(i >= this->length) return NULL; | |||||
| return this->array[i]; | |||||
| } | |||||
| static int array_list_expand_internal(struct array_list *this, int max) | |||||
| { | |||||
| void *t; | |||||
| int new_size; | |||||
| if(max < this->size) return 0; | |||||
| new_size = max(this->size << 1, max); | |||||
| if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1; | |||||
| this->array = t; | |||||
| bzero(this->array + this->size, (new_size-this->size)*sizeof(void*)); | |||||
| this->size = new_size; | |||||
| return 0; | |||||
| } | |||||
| int | |||||
| array_list_put_idx(struct array_list *this, int idx, void *data) | |||||
| { | |||||
| if(array_list_expand_internal(this, idx)) return -1; | |||||
| if(this->array[idx]) this->free_fn(this->array[idx]); | |||||
| this->array[idx] = data; | |||||
| if(this->length <= idx) this->length = idx + 1; | |||||
| return 0; | |||||
| } | |||||
| int | |||||
| array_list_add(struct array_list *this, void *data) | |||||
| { | |||||
| return array_list_put_idx(this, this->length, data); | |||||
| } | |||||
| int | |||||
| array_list_length(struct array_list *this) | |||||
| { | |||||
| return this->length; | |||||
| } | |||||
| @@ -0,0 +1,52 @@ | |||||
| /* | |||||
| * $Id: arraylist.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _arraylist_h_ | |||||
| #define _arraylist_h_ | |||||
| #define ARRAY_LIST_DEFAULT_SIZE 32 | |||||
| typedef void (array_list_free_fn) (void *data); | |||||
| struct array_list | |||||
| { | |||||
| void **array; | |||||
| int length; | |||||
| int size; | |||||
| array_list_free_fn *free_fn; | |||||
| }; | |||||
| extern struct array_list* | |||||
| array_list_new(array_list_free_fn *free_fn); | |||||
| extern void | |||||
| array_list_free(struct array_list *this); | |||||
| extern void* | |||||
| array_list_get_idx(struct array_list *this, int i); | |||||
| extern int | |||||
| array_list_put_idx(struct array_list *this, int i, void *data); | |||||
| extern int | |||||
| array_list_add(struct array_list *this, void *data); | |||||
| extern int | |||||
| array_list_length(struct array_list *this); | |||||
| #endif | |||||
| @@ -0,0 +1,38 @@ | |||||
| /* | |||||
| * $Id: bits.h,v 1.3 2004/07/21 10:10:22 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _bits_h_ | |||||
| #define _bits_h_ | |||||
| #define min(x,y) ({ \ | |||||
| typeof(x) _x = (x); \ | |||||
| typeof(y) _y = (y); \ | |||||
| (void) (&_x == &_y); \ | |||||
| _x < _y ? _x : _y; }) | |||||
| #define max(x,y) ({ \ | |||||
| typeof(x) _x = (x); \ | |||||
| typeof(y) _y = (y); \ | |||||
| (void) (&_x == &_y); \ | |||||
| _x > _y ? _x : _y; }) | |||||
| #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) | |||||
| #define error_ptr(error) ((void*)error) | |||||
| #define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) | |||||
| #endif | |||||
| @@ -0,0 +1,75 @@ | |||||
| /* | |||||
| * $Id: debug.c,v 1.3 2004/08/07 03:11:38 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <stdarg.h> | |||||
| #include <syslog.h> | |||||
| #include <unistd.h> | |||||
| #include <sys/param.h> | |||||
| #include "debug.h" | |||||
| static int _syslog = 0; | |||||
| static int _debug = 0; | |||||
| void mc_set_debug(int debug) { _debug = debug; } | |||||
| int mc_get_debug() { return _debug; } | |||||
| extern void mc_set_syslog(int syslog) | |||||
| { | |||||
| _syslog = syslog; | |||||
| } | |||||
| void mc_abort(const char *msg, ...) | |||||
| { | |||||
| va_list ap; | |||||
| va_start(ap, msg); | |||||
| if(_syslog) vsyslog(LOG_ERR, msg, ap); | |||||
| else vprintf(msg, ap); | |||||
| exit(1); | |||||
| } | |||||
| void mc_debug(const char *msg, ...) | |||||
| { | |||||
| va_list ap; | |||||
| if(_debug) { | |||||
| va_start(ap, msg); | |||||
| if(_syslog) vsyslog(LOG_DEBUG, msg, ap); | |||||
| else vprintf(msg, ap); | |||||
| } | |||||
| } | |||||
| void mc_error(const char *msg, ...) | |||||
| { | |||||
| va_list ap; | |||||
| va_start(ap, msg); | |||||
| if(_syslog) vsyslog(LOG_ERR, msg, ap); | |||||
| else vfprintf(stderr, msg, ap); | |||||
| } | |||||
| void mc_info(const char *msg, ...) | |||||
| { | |||||
| va_list ap; | |||||
| va_start(ap, msg); | |||||
| if(_syslog) vsyslog(LOG_INFO, msg, ap); | |||||
| else vfprintf(stderr, msg, ap); | |||||
| } | |||||
| @@ -0,0 +1,33 @@ | |||||
| /* | |||||
| * $Id: debug.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _DEBUG_H_ | |||||
| #define _DEBUG_H_ | |||||
| #define errstr strerror(errno) | |||||
| extern void mc_set_debug(int debug); | |||||
| extern int mc_get_debug(); | |||||
| extern void mc_set_syslog(int syslog); | |||||
| extern void mc_abort(const char *msg, ...); | |||||
| extern void mc_debug(const char *msg, ...); | |||||
| extern void mc_error(const char *msg, ...); | |||||
| extern void mc_info(const char *msg, ...); | |||||
| #endif | |||||
| @@ -0,0 +1,30 @@ | |||||
| /* | |||||
| * $Id: json.h,v 1.4 2004/08/07 03:13:52 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _json_h_ | |||||
| #define _json_h_ | |||||
| #include "bits.h" | |||||
| #include "debug.h" | |||||
| #include "linkhash.h" | |||||
| #include "arraylist.h" | |||||
| #include "json_util.h" | |||||
| #include "json_object.h" | |||||
| #include "json_tokener.h" | |||||
| #endif | |||||
| @@ -0,0 +1,493 @@ | |||||
| /* | |||||
| * $Id: json_object.c,v 1.10 2004/08/07 03:12:43 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include "debug.h" | |||||
| #include "printbuf.h" | |||||
| #include "linkhash.h" | |||||
| #include "arraylist.h" | |||||
| #include "json_object.h" | |||||
| #include "json_object_private.h" | |||||
| /* #define REFCOUNT_DEBUG */ | |||||
| char *json_number_chars = "0123456789.+-e"; | |||||
| char *json_hex_chars = "0123456789abcdef"; | |||||
| #ifdef REFCOUNT_DEBUG | |||||
| static char* json_type_name[] = { | |||||
| "null", | |||||
| "boolean", | |||||
| "double", | |||||
| "int", | |||||
| "object", | |||||
| "array", | |||||
| "string", | |||||
| }; | |||||
| #endif | |||||
| static void json_object_generic_delete(struct json_object* this); | |||||
| static struct json_object* json_object_new(enum json_type o_type); | |||||
| /* ref count debugging */ | |||||
| #ifdef REFCOUNT_DEBUG | |||||
| static struct lh_table *json_object_table; | |||||
| static void json_object_init() __attribute__ ((constructor)); | |||||
| static void json_object_init() { | |||||
| mc_debug("json_object_init: creating object table\n"); | |||||
| json_object_table = lh_kptr_table_new(128, "json_object_table", NULL); | |||||
| } | |||||
| static void json_object_fini() __attribute__ ((destructor)); | |||||
| static void json_object_fini() { | |||||
| struct lh_entry *ent; | |||||
| if(mc_get_debug() && json_object_table->count) { | |||||
| mc_debug("json_object_fini: %d referenced objects at exit\n", | |||||
| json_object_table->count); | |||||
| lh_foreach(json_object_table, ent) { | |||||
| struct json_object* obj = (struct json_object*)ent->v; | |||||
| mc_debug("\t%s:%p\n", json_type_name[obj->o_type], obj); | |||||
| } | |||||
| } | |||||
| mc_debug("json_object_fini: freeing object table\n"); | |||||
| lh_table_free(json_object_table); | |||||
| } | |||||
| #endif | |||||
| /* string escaping */ | |||||
| static int json_escape_str(struct printbuf *pb, char *str) | |||||
| { | |||||
| int pos = 0, start_offset = 0; | |||||
| char c; | |||||
| do { | |||||
| c = str[pos]; | |||||
| switch(c) { | |||||
| case '\b': | |||||
| case '\n': | |||||
| case '\r': | |||||
| case '\t': | |||||
| if(pos - start_offset > 0) | |||||
| printbuf_memappend(pb, str + start_offset, pos - start_offset); | |||||
| if(c == '\b') printbuf_memappend(pb, "\\b", 2); | |||||
| else if(c == '\n') printbuf_memappend(pb, "\\n", 2); | |||||
| else if(c == '\r') printbuf_memappend(pb, "\\r", 2); | |||||
| else if(c == '\t') printbuf_memappend(pb, "\\t", 2); | |||||
| start_offset = ++pos; | |||||
| break; | |||||
| default: | |||||
| if(c && c < ' ') { | |||||
| if(pos - start_offset > 0) | |||||
| printbuf_memappend(pb, str + start_offset, pos - start_offset); | |||||
| sprintbuf(pb, "\\u00%c%c", | |||||
| json_hex_chars[c >> 4], | |||||
| json_hex_chars[c & 0xf]); | |||||
| start_offset = ++pos; | |||||
| } else if(c) pos++; | |||||
| } | |||||
| } while(c); | |||||
| if(pos - start_offset > 0) | |||||
| printbuf_memappend(pb, str + start_offset, pos - start_offset); | |||||
| return 0; | |||||
| } | |||||
| /* reference counting */ | |||||
| extern struct json_object* json_object_get(struct json_object *this) | |||||
| { | |||||
| if(this) { | |||||
| this->_ref_count++; | |||||
| } | |||||
| return this; | |||||
| } | |||||
| extern void json_object_put(struct json_object *this) | |||||
| { | |||||
| if(this) { | |||||
| this->_ref_count--; | |||||
| if(!this->_ref_count) this->_delete(this); | |||||
| } | |||||
| } | |||||
| /* generic object construction and destruction parts */ | |||||
| static void json_object_generic_delete(struct json_object* this) | |||||
| { | |||||
| #ifdef REFCOUNT_DEBUG | |||||
| mc_debug("json_object_delete_%s: %p\n", | |||||
| json_type_name[this->o_type], this); | |||||
| lh_table_delete(json_object_table, this); | |||||
| #endif | |||||
| printbuf_free(this->_pb); | |||||
| free(this); | |||||
| } | |||||
| static struct json_object* json_object_new(enum json_type o_type) | |||||
| { | |||||
| struct json_object *this = calloc(sizeof(struct json_object), 1); | |||||
| if(!this) return NULL; | |||||
| this->o_type = o_type; | |||||
| this->_ref_count = 1; | |||||
| this->_delete = &json_object_generic_delete; | |||||
| #ifdef REFCOUNT_DEBUG | |||||
| lh_table_insert(json_object_table, this, this); | |||||
| mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this); | |||||
| #endif | |||||
| return this; | |||||
| } | |||||
| /* type checking functions */ | |||||
| int json_object_is_type(struct json_object *this, enum json_type type) | |||||
| { | |||||
| return (this->o_type == type); | |||||
| } | |||||
| enum json_type json_object_get_type(struct json_object *this) | |||||
| { | |||||
| return this->o_type; | |||||
| } | |||||
| /* json_object_to_json_string */ | |||||
| char* json_object_to_json_string(struct json_object *this) | |||||
| { | |||||
| if(!this) return "null"; | |||||
| if(!this->_pb) { | |||||
| if(!(this->_pb = printbuf_new())) return NULL; | |||||
| } else { | |||||
| printbuf_reset(this->_pb); | |||||
| } | |||||
| if(this->_to_json_string(this, this->_pb) < 0) return NULL; | |||||
| return this->_pb->buf; | |||||
| } | |||||
| /* json_object_object */ | |||||
| static int json_object_object_to_json_string(struct json_object* this, | |||||
| struct printbuf *pb) | |||||
| { | |||||
| int i=0; | |||||
| sprintbuf(pb, "{"); | |||||
| json_object_object_foreach(this, key, val) { | |||||
| if(i) sprintbuf(pb, ","); | |||||
| sprintbuf(pb, " \""); | |||||
| json_escape_str(pb, key); | |||||
| sprintbuf(pb, "\": "); | |||||
| if(val == NULL) sprintbuf(pb, "null"); | |||||
| else val->_to_json_string(val, pb); | |||||
| i++; | |||||
| } | |||||
| return sprintbuf(pb, " }"); | |||||
| } | |||||
| static void json_object_lh_entry_free(struct lh_entry *ent) | |||||
| { | |||||
| free(ent->k); | |||||
| json_object_put((struct json_object*)ent->v); | |||||
| } | |||||
| static void json_object_object_delete(struct json_object* this) | |||||
| { | |||||
| lh_table_free(this->o.c_object); | |||||
| json_object_generic_delete(this); | |||||
| } | |||||
| struct json_object* json_object_new_object() | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_object); | |||||
| if(!this) return NULL; | |||||
| this->_delete = &json_object_object_delete; | |||||
| this->_to_json_string = &json_object_object_to_json_string; | |||||
| this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES, | |||||
| NULL, &json_object_lh_entry_free); | |||||
| return this; | |||||
| } | |||||
| struct lh_table* json_object_get_object(struct json_object *this) | |||||
| { | |||||
| if(!this) return NULL; | |||||
| switch(this->o_type) { | |||||
| case json_type_object: | |||||
| return this->o.c_object; | |||||
| default: | |||||
| return NULL; | |||||
| } | |||||
| } | |||||
| void json_object_object_add(struct json_object* this, char *key, | |||||
| struct json_object *val) | |||||
| { | |||||
| lh_table_delete(this->o.c_object, key); | |||||
| lh_table_insert(this->o.c_object, strdup(key), val); | |||||
| } | |||||
| struct json_object* json_object_object_get(struct json_object* this, char *key) | |||||
| { | |||||
| return (struct json_object*) lh_table_lookup(this->o.c_object, key); | |||||
| } | |||||
| void json_object_object_del(struct json_object* this, char *key) | |||||
| { | |||||
| lh_table_delete(this->o.c_object, key); | |||||
| } | |||||
| /* json_object_boolean */ | |||||
| static int json_object_boolean_to_json_string(struct json_object* this, | |||||
| struct printbuf *pb) | |||||
| { | |||||
| if(this->o.c_boolean) return sprintbuf(pb, "true"); | |||||
| else return sprintbuf(pb, "false"); | |||||
| } | |||||
| struct json_object* json_object_new_boolean(boolean b) | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_boolean); | |||||
| if(!this) return NULL; | |||||
| this->_to_json_string = &json_object_boolean_to_json_string; | |||||
| this->o.c_boolean = b; | |||||
| return this; | |||||
| } | |||||
| boolean json_object_get_boolean(struct json_object *this) | |||||
| { | |||||
| if(!this) return FALSE; | |||||
| switch(this->o_type) { | |||||
| case json_type_boolean: | |||||
| return this->o.c_boolean; | |||||
| case json_type_int: | |||||
| return (this->o.c_int != 0); | |||||
| case json_type_double: | |||||
| return (this->o.c_double != 0); | |||||
| case json_type_string: | |||||
| if(strlen(this->o.c_string)) return TRUE; | |||||
| default: | |||||
| return TRUE; | |||||
| } | |||||
| } | |||||
| /* json_object_int */ | |||||
| static int json_object_int_to_json_string(struct json_object* this, | |||||
| struct printbuf *pb) | |||||
| { | |||||
| return sprintbuf(pb, "%d", this->o.c_int); | |||||
| } | |||||
| struct json_object* json_object_new_int(int i) | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_int); | |||||
| if(!this) return NULL; | |||||
| this->_to_json_string = &json_object_int_to_json_string; | |||||
| this->o.c_int = i; | |||||
| return this; | |||||
| } | |||||
| int json_object_get_int(struct json_object *this) | |||||
| { | |||||
| int cint; | |||||
| if(!this) return 0; | |||||
| switch(this->o_type) { | |||||
| case json_type_int: | |||||
| return this->o.c_int; | |||||
| case json_type_double: | |||||
| return this->o.c_double; | |||||
| case json_type_boolean: | |||||
| return this->o.c_boolean; | |||||
| case json_type_string: | |||||
| if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint; | |||||
| default: | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| /* json_object_double */ | |||||
| static int json_object_double_to_json_string(struct json_object* this, | |||||
| struct printbuf *pb) | |||||
| { | |||||
| return sprintbuf(pb, "%lf", this->o.c_double); | |||||
| } | |||||
| struct json_object* json_object_new_double(double d) | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_double); | |||||
| if(!this) return NULL; | |||||
| this->_to_json_string = &json_object_double_to_json_string; | |||||
| this->o.c_double = d; | |||||
| return this; | |||||
| } | |||||
| double json_object_get_double(struct json_object *this) | |||||
| { | |||||
| double cdouble; | |||||
| if(!this) return 0.0; | |||||
| switch(this->o_type) { | |||||
| case json_type_double: | |||||
| return this->o.c_double; | |||||
| case json_type_int: | |||||
| return this->o.c_int; | |||||
| case json_type_boolean: | |||||
| return this->o.c_boolean; | |||||
| case json_type_string: | |||||
| if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble; | |||||
| default: | |||||
| return 0.0; | |||||
| } | |||||
| } | |||||
| /* json_object_string */ | |||||
| static int json_object_string_to_json_string(struct json_object* this, | |||||
| struct printbuf *pb) | |||||
| { | |||||
| sprintbuf(pb, "\""); | |||||
| json_escape_str(pb, this->o.c_string); | |||||
| sprintbuf(pb, "\""); | |||||
| return 0; | |||||
| } | |||||
| static void json_object_string_delete(struct json_object* this) | |||||
| { | |||||
| free(this->o.c_string); | |||||
| json_object_generic_delete(this); | |||||
| } | |||||
| struct json_object* json_object_new_string(char *s) | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_string); | |||||
| if(!this) return NULL; | |||||
| this->_delete = &json_object_string_delete; | |||||
| this->_to_json_string = &json_object_string_to_json_string; | |||||
| this->o.c_string = strdup(s); | |||||
| return this; | |||||
| } | |||||
| struct json_object* json_object_new_string_len(char *s, int len) | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_string); | |||||
| if(!this) return NULL; | |||||
| this->_delete = &json_object_string_delete; | |||||
| this->_to_json_string = &json_object_string_to_json_string; | |||||
| this->o.c_string = strndup(s, len); | |||||
| return this; | |||||
| } | |||||
| char* json_object_get_string(struct json_object *this) | |||||
| { | |||||
| if(!this) return NULL; | |||||
| switch(this->o_type) { | |||||
| case json_type_string: | |||||
| return this->o.c_string; | |||||
| default: | |||||
| return json_object_to_json_string(this); | |||||
| } | |||||
| } | |||||
| /* json_object_array */ | |||||
| static int json_object_array_to_json_string(struct json_object* this, | |||||
| struct printbuf *pb) | |||||
| { | |||||
| sprintbuf(pb, "["); | |||||
| for(int i=0; i < json_object_array_length(this); i++) { | |||||
| if(i) sprintbuf(pb, ", "); | |||||
| else sprintbuf(pb, " "); | |||||
| struct json_object *val = json_object_array_get_idx(this, i); | |||||
| if(val == NULL) sprintbuf(pb, "null"); | |||||
| else val->_to_json_string(val, pb); | |||||
| } | |||||
| return sprintbuf(pb, " ]"); | |||||
| } | |||||
| static void json_object_array_entry_free(void *data) | |||||
| { | |||||
| json_object_put((struct json_object*)data); | |||||
| } | |||||
| static void json_object_array_delete(struct json_object* this) | |||||
| { | |||||
| array_list_free(this->o.c_array); | |||||
| json_object_generic_delete(this); | |||||
| } | |||||
| struct json_object* json_object_new_array() | |||||
| { | |||||
| struct json_object *this = json_object_new(json_type_array); | |||||
| if(!this) return NULL; | |||||
| this->_delete = &json_object_array_delete; | |||||
| this->_to_json_string = &json_object_array_to_json_string; | |||||
| this->o.c_array = array_list_new(&json_object_array_entry_free); | |||||
| return this; | |||||
| } | |||||
| struct array_list* json_object_get_array(struct json_object *this) | |||||
| { | |||||
| if(!this) return NULL; | |||||
| switch(this->o_type) { | |||||
| case json_type_array: | |||||
| return this->o.c_array; | |||||
| default: | |||||
| return NULL; | |||||
| } | |||||
| } | |||||
| int json_object_array_length(struct json_object *this) | |||||
| { | |||||
| return array_list_length(this->o.c_array); | |||||
| } | |||||
| int json_object_array_add(struct json_object *this,struct json_object *val) | |||||
| { | |||||
| return array_list_add(this->o.c_array, val); | |||||
| } | |||||
| int json_object_array_put_idx(struct json_object *this, int idx, | |||||
| struct json_object *val) | |||||
| { | |||||
| return array_list_put_idx(this->o.c_array, idx, val); | |||||
| } | |||||
| struct json_object* json_object_array_get_idx(struct json_object *this, | |||||
| int idx) | |||||
| { | |||||
| return (struct json_object*)array_list_get_idx(this->o.c_array, idx); | |||||
| } | |||||
| @@ -0,0 +1,300 @@ | |||||
| /* | |||||
| * $Id: json_object.h,v 1.8 2004/08/07 04:21:27 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _json_object_h_ | |||||
| #define _json_object_h_ | |||||
| #define JSON_OBJECT_DEF_HASH_ENTIRES 16 | |||||
| #undef FALSE | |||||
| #define FALSE ((boolean)0) | |||||
| #undef TRUE | |||||
| #define TRUE ((boolean)1) | |||||
| extern char *json_number_chars; | |||||
| extern char *json_hex_chars; | |||||
| /* forward structure definitions */ | |||||
| typedef int boolean; | |||||
| struct printbuf; | |||||
| struct lh_table; | |||||
| struct array_list; | |||||
| struct json_object; | |||||
| /* supported object types */ | |||||
| enum json_type { | |||||
| json_type_null, | |||||
| json_type_boolean, | |||||
| json_type_double, | |||||
| json_type_int, | |||||
| json_type_object, | |||||
| json_type_array, | |||||
| json_type_string, | |||||
| }; | |||||
| /* reference counting functions */ | |||||
| /** | |||||
| * Increment the reference count of json_object | |||||
| * @param this the json_object instance | |||||
| */ | |||||
| extern struct json_object* json_object_get(struct json_object *this); | |||||
| /** | |||||
| * Decrement the reference count of json_object and free if it reaches zero | |||||
| * @param this the json_object instance | |||||
| */ | |||||
| extern void json_object_put(struct json_object *this); | |||||
| /** | |||||
| * Check if the json_object is of a given type | |||||
| * @param this the json_object instance | |||||
| * @param type one of: | |||||
| json_type_boolean, | |||||
| json_type_double, | |||||
| json_type_int, | |||||
| json_type_object, | |||||
| json_type_array, | |||||
| json_type_string, | |||||
| */ | |||||
| extern int json_object_is_type(struct json_object *this, enum json_type type); | |||||
| /** | |||||
| * Get the type of the json_object | |||||
| * @param this the json_object instance | |||||
| * @returns type being one of: | |||||
| json_type_boolean, | |||||
| json_type_double, | |||||
| json_type_int, | |||||
| json_type_object, | |||||
| json_type_array, | |||||
| json_type_string, | |||||
| */ | |||||
| extern enum json_type json_object_get_type(struct json_object *this); | |||||
| /** Stringify object to json format | |||||
| * @param this the json_object instance | |||||
| * @returns a string in JSON format | |||||
| */ | |||||
| extern char* json_object_to_json_string(struct json_object *this); | |||||
| /* object type methods */ | |||||
| /** Create a new empty object | |||||
| * @returns a json_object of type json_type_object | |||||
| */ | |||||
| extern struct json_object* json_object_new_object(); | |||||
| /** Get the hashtable of a json_object of type json_type_object | |||||
| * @param this the json_object instance | |||||
| * @returns a linkhash | |||||
| */ | |||||
| extern struct lh_table* json_object_get_object(struct json_object *this); | |||||
| /** Add an object field to a json_object of type json_type_object | |||||
| * | |||||
| * The reference count will *not* be incremented. This is to make adding | |||||
| * fields to objects in code more compact. If you want to retain a reference | |||||
| * to an added object you must wrap the passed object with json_object_get | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @param key the object field name (a private copy will be duplicated) | |||||
| * @param val a json_object or NULL member to associate with the given field | |||||
| */ | |||||
| extern void json_object_object_add(struct json_object* this, char *key, | |||||
| struct json_object *val); | |||||
| /** Get the json_object associate with a given object field | |||||
| * @param this the json_object instance | |||||
| * @param key the object field name | |||||
| * @returns the json_object associated with the given field name | |||||
| */ | |||||
| extern struct json_object* json_object_object_get(struct json_object* this, | |||||
| char *key); | |||||
| /** Delete the given json_object field | |||||
| * | |||||
| * The reference count will be decremented for the deleted object | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @param key the object field name | |||||
| */ | |||||
| extern void json_object_object_del(struct json_object* this, char *key); | |||||
| /** Iterate through all keys and values of an object | |||||
| * @param this the json_object instance | |||||
| * @param key the local name for the char* key variable defined in the body | |||||
| * @param val the local name for the json_object* object variable defined in the body | |||||
| */ | |||||
| #define json_object_object_foreach(obj,key,val) \ | |||||
| char *key; struct json_object *val; \ | |||||
| for(struct lh_entry *entry = json_object_get_object(obj)->head; ({ if(entry) { key = (char*)entry->k; val = (struct json_object*)entry->v; } ; entry; }); entry = entry->next ) | |||||
| /* Array type methods */ | |||||
| /** Create a new empty json_object of type json_type_array | |||||
| * @returns a json_object of type json_type_array | |||||
| */ | |||||
| extern struct json_object* json_object_new_array(); | |||||
| /** Get the arraylist of a json_object of type json_type_array | |||||
| * @param this the json_object instance | |||||
| * @returns an arraylist | |||||
| */ | |||||
| extern struct array_list* json_object_get_array(struct json_object *this); | |||||
| /** Get the length of a json_object of type json_type_array | |||||
| * @param this the json_object instance | |||||
| * @returns an int | |||||
| */ | |||||
| extern int json_object_array_length(struct json_object *this); | |||||
| /** Add an element to the end of a json_object of type json_type_array | |||||
| * | |||||
| * The reference count will *not* be incremented. This is to make adding | |||||
| * fields to objects in code more compact. If you want to retain a reference | |||||
| * to an added object you must wrap the passed object with json_object_get | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @param val the json_object to be added | |||||
| */ | |||||
| extern int json_object_array_add(struct json_object *this, | |||||
| struct json_object *val); | |||||
| /** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) | |||||
| * | |||||
| * The reference count will *not* be incremented. This is to make adding | |||||
| * fields to objects in code more compact. If you want to retain a reference | |||||
| * to an added object you must wrap the passed object with json_object_get | |||||
| * | |||||
| * The reference count of a replaced object will be decremented. | |||||
| * | |||||
| * The array size will be automatically be expanded to the size of the | |||||
| * index if the index is larger than the current size. | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @param idx the index to insert the element at | |||||
| * @param val the json_object to be added | |||||
| */ | |||||
| extern int json_object_array_put_idx(struct json_object *this, int idx, | |||||
| struct json_object *val); | |||||
| /** Get the element at specificed index of the array (a json_object of type json_type_array) | |||||
| * @param this the json_object instance | |||||
| * @param idx the index to get the element at | |||||
| * @returns the json_object at the specified index (or NULL) | |||||
| */ | |||||
| extern struct json_object* json_object_array_get_idx(struct json_object *this, | |||||
| int idx); | |||||
| /* boolean type methods */ | |||||
| /** Create a new empty json_object of type json_type_boolean | |||||
| * @param b a boolean TRUE or FALSE (0 or 1) | |||||
| * @returns a json_object of type json_type_boolean | |||||
| */ | |||||
| extern struct json_object* json_object_new_boolean(boolean b); | |||||
| /** Get the boolean value of a json_object | |||||
| * | |||||
| * The type is coerced to a boolean if the passed object is not a boolean. | |||||
| * integer and double objects will return FALSE if there value is zero | |||||
| * or TRUE otherwise. If the passed object is a string it will return | |||||
| * TRUE if it has a non zero length. If any other object type is passed | |||||
| * TRUE will be returned if the object is not NULL. | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @returns a boolean | |||||
| */ | |||||
| extern boolean json_object_get_boolean(struct json_object *this); | |||||
| /* int type methods */ | |||||
| /** Create a new empty json_object of type json_type_int | |||||
| * @param i the integer | |||||
| * @returns a json_object of type json_type_int | |||||
| */ | |||||
| extern struct json_object* json_object_new_int(int i); | |||||
| /** Get the int value of a json_object | |||||
| * | |||||
| * The type is coerced to a int if the passed object is not a int. | |||||
| * double objects will return their integer conversion. Strings will be | |||||
| * parsed as an integer. If no conversion exists then 0 is returned. | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @returns an int | |||||
| */ | |||||
| extern int json_object_get_int(struct json_object *this); | |||||
| /* double type methods */ | |||||
| /** Create a new empty json_object of type json_type_double | |||||
| * @param d the double | |||||
| * @returns a json_object of type json_type_double | |||||
| */ | |||||
| extern struct json_object* json_object_new_double(double d); | |||||
| /** Get the double value of a json_object | |||||
| * | |||||
| * The type is coerced to a double if the passed object is not a double. | |||||
| * integer objects will return their dboule conversion. Strings will be | |||||
| * parsed as a double. If no conversion exists then 0.0 is returned. | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @returns an double | |||||
| */ | |||||
| extern double json_object_get_double(struct json_object *this); | |||||
| /* string type methods */ | |||||
| /** Create a new empty json_object of type json_type_string | |||||
| * | |||||
| * A copy of the string is made and the memory is managed by the json_object | |||||
| * | |||||
| * @param s the string | |||||
| * @returns a json_object of type json_type_string | |||||
| */ | |||||
| extern struct json_object* json_object_new_string(char *s); | |||||
| extern struct json_object* json_object_new_string_len(char *s, int len); | |||||
| /** Get the string value of a json_object | |||||
| * | |||||
| * If the passed object is not of type json_type_string then the JSON | |||||
| * representation of the object is returned. | |||||
| * | |||||
| * The returned string memory is managed by the json_object and will | |||||
| * be freed when the reference count of the json_object drops to zero. | |||||
| * | |||||
| * @param this the json_object instance | |||||
| * @returns a string | |||||
| */ | |||||
| extern char* json_object_get_string(struct json_object *this); | |||||
| #endif | |||||
| @@ -0,0 +1,25 @@ | |||||
| #ifndef _json_object_private_h_ | |||||
| #define _json_object_private_h_ | |||||
| typedef void (json_object_delete_fn)(struct json_object *o); | |||||
| typedef int (json_object_to_json_string_fn)(struct json_object *o, | |||||
| struct printbuf *pb); | |||||
| struct json_object | |||||
| { | |||||
| enum json_type o_type; | |||||
| json_object_delete_fn *_delete; | |||||
| json_object_to_json_string_fn *_to_json_string; | |||||
| int _ref_count; | |||||
| struct printbuf *_pb; | |||||
| union data { | |||||
| boolean c_boolean; | |||||
| double c_double; | |||||
| int c_int; | |||||
| struct lh_table *c_object; | |||||
| struct array_list *c_array; | |||||
| char *c_string; | |||||
| } o; | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,426 @@ | |||||
| /* | |||||
| * $Id: json_tokener.c,v 1.10 2004/07/27 00:42:31 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <ctype.h> | |||||
| #include <string.h> | |||||
| #include "bits.h" | |||||
| #include "debug.h" | |||||
| #include "printbuf.h" | |||||
| #include "arraylist.h" | |||||
| #include "json_object.h" | |||||
| #include "json_tokener.h" | |||||
| static struct json_object* json_tokener_do_parse(struct json_tokener *this); | |||||
| struct json_object* json_tokener_parse(char * s) | |||||
| { | |||||
| struct json_tokener tok; | |||||
| struct json_object* obj; | |||||
| tok.source = s; | |||||
| tok.pos = 0; | |||||
| tok.pb = printbuf_new(); | |||||
| obj = json_tokener_do_parse(&tok); | |||||
| printbuf_free(tok.pb); | |||||
| return obj; | |||||
| } | |||||
| static struct json_object* json_tokener_do_parse(struct json_tokener *this) | |||||
| { | |||||
| enum json_tokener_state state, saved_state; | |||||
| enum json_tokener_error err = json_tokener_success; | |||||
| struct json_object *current = NULL, *obj; | |||||
| char *obj_field_name = NULL; | |||||
| char quote_char; | |||||
| int deemed_double, start_offset; | |||||
| state = json_tokener_state_eatws; | |||||
| saved_state = json_tokener_state_start; | |||||
| char c; | |||||
| do { | |||||
| c = this->source[this->pos]; | |||||
| switch(state) { | |||||
| case json_tokener_state_eatws: | |||||
| if(isspace(c)) { | |||||
| this->pos++; | |||||
| } else if(c == '/') { | |||||
| state = json_tokener_state_comment_start; | |||||
| start_offset = this->pos++; | |||||
| } else { | |||||
| state = saved_state; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_start: | |||||
| switch(c) { | |||||
| case '{': | |||||
| state = json_tokener_state_eatws; | |||||
| saved_state = json_tokener_state_object; | |||||
| current = json_object_new_object(); | |||||
| this->pos++; | |||||
| break; | |||||
| case '[': | |||||
| state = json_tokener_state_eatws; | |||||
| saved_state = json_tokener_state_array; | |||||
| current = json_object_new_array(); | |||||
| this->pos++; | |||||
| break; | |||||
| case 'N': | |||||
| case 'n': | |||||
| state = json_tokener_state_null; | |||||
| start_offset = this->pos++; | |||||
| break; | |||||
| case '"': | |||||
| case '\'': | |||||
| quote_char = c; | |||||
| printbuf_reset(this->pb); | |||||
| state = json_tokener_state_string; | |||||
| start_offset = ++this->pos; | |||||
| break; | |||||
| case 'T': | |||||
| case 't': | |||||
| case 'F': | |||||
| case 'f': | |||||
| state = json_tokener_state_boolean; | |||||
| start_offset = this->pos++; | |||||
| break; | |||||
| case '0' ... '9': | |||||
| case '-': | |||||
| deemed_double = 0; | |||||
| state = json_tokener_state_number; | |||||
| start_offset = this->pos++; | |||||
| break; | |||||
| default: | |||||
| err = json_tokener_error_parse_unexpected; | |||||
| goto out; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_finish: | |||||
| goto out; | |||||
| case json_tokener_state_null: | |||||
| if(strncasecmp("null", this->source + start_offset, | |||||
| this->pos - start_offset)) | |||||
| return error_ptr(-json_tokener_error_parse_null); | |||||
| if(this->pos - start_offset == 4) { | |||||
| current = NULL; | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| this->pos++; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_comment_start: | |||||
| if(c == '*') { | |||||
| state = json_tokener_state_comment; | |||||
| } else if(c == '/') { | |||||
| state = json_tokener_state_comment_eol; | |||||
| } else { | |||||
| err = json_tokener_error_parse_comment; | |||||
| goto out; | |||||
| } | |||||
| this->pos++; | |||||
| break; | |||||
| case json_tokener_state_comment: | |||||
| if(c == '*') state = json_tokener_state_comment_end; | |||||
| this->pos++; | |||||
| break; | |||||
| case json_tokener_state_comment_eol: | |||||
| if(c == '\n') { | |||||
| if(mc_get_debug()) { | |||||
| char *tmp = strndup(this->source + start_offset, | |||||
| this->pos - start_offset); | |||||
| mc_debug("json_tokener_comment: %s\n", tmp); | |||||
| free(tmp); | |||||
| } | |||||
| state = json_tokener_state_eatws; | |||||
| } | |||||
| this->pos++; | |||||
| break; | |||||
| case json_tokener_state_comment_end: | |||||
| if(c == '/') { | |||||
| if(mc_get_debug()) { | |||||
| char *tmp = strndup(this->source + start_offset, | |||||
| this->pos - start_offset + 1); | |||||
| mc_debug("json_tokener_comment: %s\n", tmp); | |||||
| free(tmp); | |||||
| } | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| state = json_tokener_state_comment; | |||||
| } | |||||
| this->pos++; | |||||
| break; | |||||
| case json_tokener_state_string: | |||||
| if(c == quote_char) { | |||||
| printbuf_memappend(this->pb, this->source + start_offset, | |||||
| this->pos - start_offset); | |||||
| current = json_object_new_string(this->pb->buf); | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else if(c == '\\') { | |||||
| saved_state = json_tokener_state_string; | |||||
| state = json_tokener_state_string_escape; | |||||
| } | |||||
| this->pos++; | |||||
| break; | |||||
| case json_tokener_state_string_escape: | |||||
| switch(c) { | |||||
| case '"': | |||||
| case '\\': | |||||
| printbuf_memappend(this->pb, this->source + start_offset, | |||||
| this->pos - start_offset - 1); | |||||
| start_offset = this->pos++; | |||||
| state = saved_state; | |||||
| break; | |||||
| case 'b': | |||||
| case 'n': | |||||
| case 'r': | |||||
| case 't': | |||||
| printbuf_memappend(this->pb, this->source + start_offset, | |||||
| this->pos - start_offset - 1); | |||||
| if(c == 'b') printbuf_memappend(this->pb, "\b", 1); | |||||
| else if(c == 'n') printbuf_memappend(this->pb, "\n", 1); | |||||
| else if(c == 'r') printbuf_memappend(this->pb, "\r", 1); | |||||
| else if(c == 't') printbuf_memappend(this->pb, "\t", 1); | |||||
| start_offset = ++this->pos; | |||||
| state = saved_state; | |||||
| break; | |||||
| case 'u': | |||||
| printbuf_memappend(this->pb, this->source + start_offset, | |||||
| this->pos - start_offset - 1); | |||||
| start_offset = ++this->pos; | |||||
| state = json_tokener_state_escape_unicode; | |||||
| break; | |||||
| default: | |||||
| err = json_tokener_error_parse_string; | |||||
| goto out; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_escape_unicode: | |||||
| if(strchr(json_hex_chars, c)) { | |||||
| this->pos++; | |||||
| if(this->pos - start_offset == 4) { | |||||
| unsigned char utf_out[3]; | |||||
| unsigned int ucs_char = | |||||
| (hexdigit(*(this->source + start_offset)) << 12) + | |||||
| (hexdigit(*(this->source + start_offset + 1)) << 8) + | |||||
| (hexdigit(*(this->source + start_offset + 2)) << 4) + | |||||
| hexdigit(*(this->source + start_offset + 3)); | |||||
| if (ucs_char < 0x80) { | |||||
| utf_out[0] = ucs_char; | |||||
| printbuf_memappend(this->pb, utf_out, 1); | |||||
| } else if (ucs_char < 0x800) { | |||||
| utf_out[0] = 0xc0 | (ucs_char >> 6); | |||||
| utf_out[1] = 0x80 | (ucs_char & 0x3f); | |||||
| printbuf_memappend(this->pb, utf_out, 2); | |||||
| } else { | |||||
| utf_out[0] = 0xe0 | (ucs_char >> 12); | |||||
| utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f); | |||||
| utf_out[2] = 0x80 | (ucs_char & 0x3f); | |||||
| printbuf_memappend(this->pb, utf_out, 3); | |||||
| } | |||||
| start_offset = this->pos; | |||||
| state = saved_state; | |||||
| } | |||||
| } else { | |||||
| err = json_tokener_error_parse_string; | |||||
| goto out; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_boolean: | |||||
| if(strncasecmp("true", this->source + start_offset, | |||||
| this->pos - start_offset) == 0) { | |||||
| if(this->pos - start_offset == 4) { | |||||
| current = json_object_new_boolean(1); | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| this->pos++; | |||||
| } | |||||
| } else if(strncasecmp("false", this->source + start_offset, | |||||
| this->pos - start_offset) == 0) { | |||||
| if(this->pos - start_offset == 5) { | |||||
| current = json_object_new_boolean(0); | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| this->pos++; | |||||
| } | |||||
| } else { | |||||
| err = json_tokener_error_parse_boolean; | |||||
| goto out; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_number: | |||||
| if(!c || !strchr(json_number_chars, c)) { | |||||
| int numi; | |||||
| double numd; | |||||
| char *tmp = strndup(this->source + start_offset, | |||||
| this->pos - start_offset); | |||||
| if(!deemed_double && sscanf(tmp, "%d", &numi) == 1) { | |||||
| current = json_object_new_int(numi); | |||||
| } else if(deemed_double && sscanf(tmp, "%lf", &numd) == 1) { | |||||
| current = json_object_new_double(numd); | |||||
| } else { | |||||
| free(tmp); | |||||
| err = json_tokener_error_parse_number; | |||||
| goto out; | |||||
| } | |||||
| free(tmp); | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| if(c == '.' || c == 'e') deemed_double = 1; | |||||
| this->pos++; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_array: | |||||
| if(c == ']') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| obj = json_tokener_do_parse(this); | |||||
| if(is_error(obj)) { | |||||
| err = (enum json_tokener_error)obj; | |||||
| goto out; | |||||
| } | |||||
| json_object_array_add(current, obj); | |||||
| saved_state = json_tokener_state_array_sep; | |||||
| state = json_tokener_state_eatws; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_array_sep: | |||||
| if(c == ']') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else if(c == ',') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_array; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| json_object_put(current); | |||||
| return error_ptr(-json_tokener_error_parse_array); | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_object: | |||||
| state = json_tokener_state_object_field_start; | |||||
| start_offset = this->pos; | |||||
| break; | |||||
| case json_tokener_state_object_field_start: | |||||
| if(c == '}') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else if (c == '"' || c == '\'') { | |||||
| quote_char = c; | |||||
| printbuf_reset(this->pb); | |||||
| state = json_tokener_state_object_field; | |||||
| start_offset = ++this->pos; | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_object_field: | |||||
| if(c == quote_char) { | |||||
| printbuf_memappend(this->pb, this->source + start_offset, | |||||
| this->pos - start_offset); | |||||
| obj_field_name = strdup(this->pb->buf); | |||||
| saved_state = json_tokener_state_object_field_end; | |||||
| state = json_tokener_state_eatws; | |||||
| } else if(c == '\\') { | |||||
| saved_state = json_tokener_state_object_field; | |||||
| state = json_tokener_state_string_escape; | |||||
| } | |||||
| this->pos++; | |||||
| break; | |||||
| case json_tokener_state_object_field_end: | |||||
| if(c == ':') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_object_value; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| return error_ptr(-json_tokener_error_parse_object); | |||||
| } | |||||
| break; | |||||
| case json_tokener_state_object_value: | |||||
| obj = json_tokener_do_parse(this); | |||||
| if(is_error(obj)) { | |||||
| err = (enum json_tokener_error)obj; | |||||
| goto out; | |||||
| } | |||||
| json_object_object_add(current, obj_field_name, obj); | |||||
| free(obj_field_name); | |||||
| obj_field_name = NULL; | |||||
| saved_state = json_tokener_state_object_sep; | |||||
| state = json_tokener_state_eatws; | |||||
| break; | |||||
| case json_tokener_state_object_sep: | |||||
| if(c == '}') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_finish; | |||||
| state = json_tokener_state_eatws; | |||||
| } else if(c == ',') { | |||||
| this->pos++; | |||||
| saved_state = json_tokener_state_object; | |||||
| state = json_tokener_state_eatws; | |||||
| } else { | |||||
| err = json_tokener_error_parse_object; | |||||
| goto out; | |||||
| } | |||||
| break; | |||||
| } | |||||
| } while(c); | |||||
| if(state != json_tokener_state_finish && | |||||
| saved_state != json_tokener_state_finish) | |||||
| err = json_tokener_error_parse_eof; | |||||
| out: | |||||
| free(obj_field_name); | |||||
| if(err == json_tokener_success) return current; | |||||
| mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n", | |||||
| err, state, c); | |||||
| json_object_put(current); | |||||
| return error_ptr(-err); | |||||
| } | |||||
| @@ -0,0 +1,70 @@ | |||||
| /* | |||||
| * $Id: json_tokener.h,v 1.5 2004/07/22 01:20:05 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _json_tokener_h_ | |||||
| #define _json_tokener_h_ | |||||
| #include "json_object.h" | |||||
| enum json_tokener_error { | |||||
| json_tokener_success, | |||||
| json_tokener_error_parse_unexpected, | |||||
| json_tokener_error_parse_null, | |||||
| json_tokener_error_parse_boolean, | |||||
| json_tokener_error_parse_number, | |||||
| json_tokener_error_parse_array, | |||||
| json_tokener_error_parse_object, | |||||
| json_tokener_error_parse_string, | |||||
| json_tokener_error_parse_comment, | |||||
| json_tokener_error_parse_eof, | |||||
| }; | |||||
| enum json_tokener_state { | |||||
| json_tokener_state_eatws, | |||||
| json_tokener_state_start, | |||||
| json_tokener_state_finish, | |||||
| json_tokener_state_null, | |||||
| json_tokener_state_comment_start, | |||||
| json_tokener_state_comment, | |||||
| json_tokener_state_comment_eol, | |||||
| json_tokener_state_comment_end, | |||||
| json_tokener_state_string, | |||||
| json_tokener_state_string_escape, | |||||
| json_tokener_state_escape_unicode, | |||||
| json_tokener_state_boolean, | |||||
| json_tokener_state_number, | |||||
| json_tokener_state_array, | |||||
| json_tokener_state_array_sep, | |||||
| json_tokener_state_object, | |||||
| json_tokener_state_object_field_start, | |||||
| json_tokener_state_object_field, | |||||
| json_tokener_state_object_field_end, | |||||
| json_tokener_state_object_value, | |||||
| json_tokener_state_object_sep, | |||||
| }; | |||||
| struct json_tokener | |||||
| { | |||||
| char *source; | |||||
| int pos; | |||||
| struct printbuf *pb; | |||||
| }; | |||||
| extern struct json_object* json_tokener_parse(char *s); | |||||
| #endif | |||||
| @@ -0,0 +1,79 @@ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <errno.h> | |||||
| #include <unistd.h> | |||||
| #include <sys/types.h> | |||||
| #include <sys/stat.h> | |||||
| #include <fcntl.h> | |||||
| #include "bits.h" | |||||
| #include "debug.h" | |||||
| #include "printbuf.h" | |||||
| #include "json_object.h" | |||||
| #include "json_tokener.h" | |||||
| #include "json_util.h" | |||||
| struct json_object* json_object_from_file(char *filename) | |||||
| { | |||||
| struct printbuf *pb; | |||||
| struct json_object *obj; | |||||
| char buf[JSON_FILE_BUF_SIZE]; | |||||
| int fd, ret; | |||||
| if((fd = open(filename, O_RDONLY)) < 0) { | |||||
| mc_error("json_object_from_file: error reading file %s: %s\n", | |||||
| filename, strerror(errno)); | |||||
| return error_ptr(-1); | |||||
| } | |||||
| if(!(pb = printbuf_new())) { | |||||
| mc_error("json_object_from_file: printbuf_new failed\n"); | |||||
| return error_ptr(-1); | |||||
| } | |||||
| while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { | |||||
| printbuf_memappend(pb, buf, ret); | |||||
| } | |||||
| close(fd); | |||||
| if(ret < 0) { | |||||
| mc_abort("json_object_from_file: error reading file %s: %s\n", | |||||
| filename, strerror(errno)); | |||||
| printbuf_free(pb); | |||||
| return error_ptr(-1); | |||||
| } | |||||
| obj = json_tokener_parse(pb->buf); | |||||
| printbuf_free(pb); | |||||
| return obj; | |||||
| } | |||||
| int json_object_to_file(char *filename, struct json_object *obj) | |||||
| { | |||||
| char *json_str; | |||||
| int fd, ret, wpos, wsize; | |||||
| if(!obj) { | |||||
| mc_error("json_object_to_file: object is null\n"); | |||||
| return -1; | |||||
| } | |||||
| if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { | |||||
| mc_error("json_object_to_file: error opening file %s: %s\n", | |||||
| filename, strerror(errno)); | |||||
| return -1; | |||||
| } | |||||
| if(!(json_str = json_object_to_json_string(obj))) return -1; | |||||
| wsize = strlen(json_str); | |||||
| wpos = 0; | |||||
| while(wpos < wsize) { | |||||
| if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { | |||||
| close(fd); | |||||
| mc_error("json_object_to_file: error writing file %s: %s\n", | |||||
| filename, strerror(errno)); | |||||
| return -1; | |||||
| } | |||||
| wpos += ret; | |||||
| } | |||||
| close(fd); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,13 @@ | |||||
| #ifndef _json_util_h_ | |||||
| #define _json_util_h_ | |||||
| #include "json_object.h" | |||||
| #define JSON_FILE_BUF_SIZE 4096 | |||||
| /* utlitiy functions */ | |||||
| extern struct json_object* json_object_from_file(char *filename); | |||||
| extern int json_object_to_file(char *filename, struct json_object *obj); | |||||
| #endif | |||||
| @@ -0,0 +1,225 @@ | |||||
| /* | |||||
| * $Id: linkhash.c,v 1.2 2004/07/21 01:24:33 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <string.h> | |||||
| #include <stdlib.h> | |||||
| #include <stdarg.h> | |||||
| #include "linkhash.h" | |||||
| void lh_abort(const char *msg, ...) | |||||
| { | |||||
| va_list ap; | |||||
| va_start(ap, msg); | |||||
| vprintf(msg, ap); | |||||
| exit(1); | |||||
| } | |||||
| unsigned long lh_ptr_hash(void *k) | |||||
| { | |||||
| return ((long)k * LH_PRIME) >> 4; | |||||
| } | |||||
| int lh_ptr_equal(void *k1, void *k2) | |||||
| { | |||||
| return (k1 == k2); | |||||
| } | |||||
| unsigned long lh_char_hash(void *k) | |||||
| { | |||||
| unsigned int h = 0; | |||||
| const char* data = k; | |||||
| while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME; | |||||
| return h; | |||||
| } | |||||
| int lh_char_equal(void *k1, void *k2) | |||||
| { | |||||
| return (strcmp((char*)k1, (char*)k2) == 0); | |||||
| } | |||||
| struct lh_table* lh_table_new(int size, char *name, | |||||
| lh_entry_free_fn *free_fn, | |||||
| lh_hash_fn *hash_fn, | |||||
| lh_equal_fn *equal_fn) | |||||
| { | |||||
| int i; | |||||
| struct lh_table *t; | |||||
| t = calloc(1, sizeof(struct lh_table)); | |||||
| if(!t) lh_abort("lh_table_new: calloc failed\n"); | |||||
| t->count = 0; | |||||
| t->size = size; | |||||
| t->name = name; | |||||
| t->table = calloc(size, sizeof(struct lh_entry)); | |||||
| if(!t->table) lh_abort("lh_table_new: calloc failed\n"); | |||||
| t->free_fn = free_fn; | |||||
| t->hash_fn = hash_fn; | |||||
| t->equal_fn = equal_fn; | |||||
| for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; | |||||
| return t; | |||||
| } | |||||
| struct lh_table* lh_kchar_table_new(int size, char *name, | |||||
| lh_entry_free_fn *free_fn) | |||||
| { | |||||
| return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal); | |||||
| } | |||||
| struct lh_table* lh_kptr_table_new(int size, char *name, | |||||
| lh_entry_free_fn *free_fn) | |||||
| { | |||||
| return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal); | |||||
| } | |||||
| void lh_table_resize(struct lh_table *t, int new_size) | |||||
| { | |||||
| struct lh_table *new_t; | |||||
| struct lh_entry *ent; | |||||
| new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn); | |||||
| ent = t->head; | |||||
| while(ent) { | |||||
| lh_table_insert(new_t, ent->k, ent->v); | |||||
| ent = ent->next; | |||||
| } | |||||
| free(t->table); | |||||
| t->table = new_t->table; | |||||
| t->size = new_size; | |||||
| t->head = new_t->head; | |||||
| t->tail = new_t->tail; | |||||
| t->resizes++; | |||||
| free(new_t); | |||||
| } | |||||
| void lh_table_free(struct lh_table *t) | |||||
| { | |||||
| struct lh_entry *c; | |||||
| for(c = t->head; c != NULL; c = c->next) { | |||||
| if(t->free_fn) { | |||||
| t->free_fn(c); | |||||
| } | |||||
| } | |||||
| free(t->table); | |||||
| free(t); | |||||
| } | |||||
| int lh_table_insert(struct lh_table *t, void *k, void *v) | |||||
| { | |||||
| unsigned long h, n; | |||||
| t->inserts++; | |||||
| if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2); | |||||
| h = t->hash_fn(k); | |||||
| n = h % t->size; | |||||
| while( 1 ) { | |||||
| if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; | |||||
| t->collisions++; | |||||
| if(++n == t->size) n = 0; | |||||
| } | |||||
| t->table[n].k = k; | |||||
| t->table[n].v = v; | |||||
| t->count++; | |||||
| if(t->head == NULL) { | |||||
| t->head = t->tail = &t->table[n]; | |||||
| t->table[n].next = t->table[n].prev = NULL; | |||||
| } else { | |||||
| t->tail->next = &t->table[n]; | |||||
| t->table[n].prev = t->tail; | |||||
| t->table[n].next = NULL; | |||||
| t->tail = &t->table[n]; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k) | |||||
| { | |||||
| unsigned long h = t->hash_fn(k); | |||||
| unsigned long n = h % t->size; | |||||
| t->lookups++; | |||||
| while( 1 ) { | |||||
| if(t->table[n].k == LH_EMPTY) return NULL; | |||||
| if(t->table[n].k != LH_FREED && | |||||
| t->equal_fn(t->table[n].k, k)) return &t->table[n]; | |||||
| if(++n == t->size) n = 0; | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| void* lh_table_lookup(struct lh_table *t, void *k) | |||||
| { | |||||
| struct lh_entry *e = lh_table_lookup_entry(t, k); | |||||
| if(e) return e->v; | |||||
| return NULL; | |||||
| } | |||||
| int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) | |||||
| { | |||||
| int n = e - t->table; | |||||
| if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; | |||||
| t->count--; | |||||
| if(t->free_fn) t->free_fn(e); | |||||
| t->table[n].v = NULL; | |||||
| t->table[n].k = LH_FREED; | |||||
| if(t->tail == &t->table[n] && t->head == &t->table[n]) { | |||||
| t->head = t->tail = NULL; | |||||
| } else if (t->head == &t->table[n]) { | |||||
| t->head->next->prev = NULL; | |||||
| t->head = t->head->next; | |||||
| } else if (t->tail == &t->table[n]) { | |||||
| t->tail->prev->next = NULL; | |||||
| t->tail = t->tail->prev; | |||||
| } else { | |||||
| t->table[n].prev->next = t->table[n].next; | |||||
| t->table[n].next->prev = t->table[n].prev; | |||||
| } | |||||
| t->table[n].next = t->table[n].prev = NULL; | |||||
| return 0; | |||||
| } | |||||
| int lh_table_delete(struct lh_table *t, void *k) | |||||
| { | |||||
| struct lh_entry *e = lh_table_lookup_entry(t, k); | |||||
| if(!e) return -1; | |||||
| return lh_table_delete_entry(t, e); | |||||
| } | |||||
| @@ -0,0 +1,270 @@ | |||||
| /* | |||||
| * $Id: linkhash.h,v 1.3 2004/08/07 03:29:47 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _linkhash_h_ | |||||
| #define _linkhash_h_ | |||||
| /** | |||||
| * golden prime used in hash functions | |||||
| */ | |||||
| #define LH_PRIME 0x9e370001UL | |||||
| /** | |||||
| * sentinel pointer value for empty slots | |||||
| */ | |||||
| #define LH_EMPTY (void*)-1 | |||||
| /** | |||||
| * sentinel pointer value for freed slots | |||||
| */ | |||||
| #define LH_FREED (void*)-2 | |||||
| struct lh_entry; | |||||
| /** | |||||
| * callback function prototypes | |||||
| */ | |||||
| typedef void (lh_entry_free_fn) (struct lh_entry *e); | |||||
| /** | |||||
| * callback function prototypes | |||||
| */ | |||||
| typedef unsigned long (lh_hash_fn) (void *k); | |||||
| /** | |||||
| * callback function prototypes | |||||
| */ | |||||
| typedef int (lh_equal_fn) (void *k1, void *k2); | |||||
| /** | |||||
| * An entry in the hash table | |||||
| */ | |||||
| struct lh_entry { | |||||
| /** | |||||
| * The key. | |||||
| */ | |||||
| void *k; | |||||
| /** | |||||
| * The value. | |||||
| */ | |||||
| void *v; | |||||
| /** | |||||
| * The next entry | |||||
| */ | |||||
| struct lh_entry *next; | |||||
| /** | |||||
| * The previous entry. | |||||
| */ | |||||
| struct lh_entry *prev; | |||||
| }; | |||||
| /** | |||||
| * The hash table structure. | |||||
| */ | |||||
| struct lh_table { | |||||
| /** | |||||
| * Size of our hash. | |||||
| */ | |||||
| int size; | |||||
| /** | |||||
| * Numbers of entries. | |||||
| */ | |||||
| int count; | |||||
| /** | |||||
| * Number of collisions. | |||||
| */ | |||||
| int collisions; | |||||
| /** | |||||
| * Number of resizes. | |||||
| */ | |||||
| int resizes; | |||||
| /** | |||||
| * Number of lookups. | |||||
| */ | |||||
| int lookups; | |||||
| /** | |||||
| * Number of inserts. | |||||
| */ | |||||
| int inserts; | |||||
| /** | |||||
| * Number of deletes. | |||||
| */ | |||||
| int deletes; | |||||
| /** | |||||
| * Name of the hash table. | |||||
| */ | |||||
| char *name; | |||||
| /** | |||||
| * The first entry. | |||||
| */ | |||||
| struct lh_entry *head; | |||||
| /** | |||||
| * The last entry. | |||||
| */ | |||||
| struct lh_entry *tail; | |||||
| struct lh_entry *table; | |||||
| /** | |||||
| * A pointer onto the function responsible for freeing an entry. | |||||
| */ | |||||
| lh_entry_free_fn *free_fn; | |||||
| lh_hash_fn *hash_fn; | |||||
| lh_equal_fn *equal_fn; | |||||
| }; | |||||
| /** | |||||
| * Pre-defined hash and equality functions | |||||
| */ | |||||
| extern unsigned long lh_ptr_hash(void *k); | |||||
| extern int lh_ptr_equal(void *k1, void *k2); | |||||
| extern unsigned long lh_char_hash(void *k); | |||||
| extern int lh_char_equal(void *k1, void *k2); | |||||
| /** | |||||
| * Convenience list iterator. | |||||
| */ | |||||
| #define lh_foreach(table, entry) \ | |||||
| for(entry = table->head; entry; entry = entry->next) | |||||
| /** | |||||
| * lh_foreach_safe allows calling of deletion routine while iterating. | |||||
| */ | |||||
| #define lh_foreach_safe(table, entry, tmp) \ | |||||
| for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) | |||||
| /** | |||||
| * Create a new linkhash table. | |||||
| * @param size initial table size. The table is automatically resized | |||||
| * although this incurs a performance penalty. | |||||
| * @param name the table name. | |||||
| * @param free_fn callback function used to free memory for entries | |||||
| * when lh_table_free or lh_table_delete is called. | |||||
| * If NULL is provided, then memory for keys and values | |||||
| * must be freed by the caller. | |||||
| * @param hash_fn function used to hash keys. 2 standard ones are defined: | |||||
| * lh_ptr_hash and lh_char_hash for hashing pointer values | |||||
| * and C strings respectively. | |||||
| * @param equal_fn comparison function to compare keys. 2 standard ones defined: | |||||
| * lh_ptr_hash and lh_char_hash for comparing pointer values | |||||
| * and C strings respectively. | |||||
| * @return a pointer onto the linkhash table. | |||||
| */ | |||||
| extern struct lh_table* lh_table_new(int size, char *name, | |||||
| lh_entry_free_fn *free_fn, | |||||
| lh_hash_fn *hash_fn, | |||||
| lh_equal_fn *equal_fn); | |||||
| /** | |||||
| * Convenience function to create a new linkhash | |||||
| * table with char keys. | |||||
| * @param size initial table size. | |||||
| * @param name table name. | |||||
| * @param free_fn callback function used to free memory for entries. | |||||
| * @return a pointer onto the linkhash table. | |||||
| */ | |||||
| extern struct lh_table* lh_kchar_table_new(int size, char *name, | |||||
| lh_entry_free_fn *free_fn); | |||||
| /** | |||||
| * Convenience function to create a new linkhash | |||||
| * table with ptr keys. | |||||
| * @param size initial table size. | |||||
| * @param name table name. | |||||
| * @param free_fn callback function used to free memory for entries. | |||||
| * @return a pointer onto the linkhash table. | |||||
| */ | |||||
| extern struct lh_table* lh_kptr_table_new(int size, char *name, | |||||
| lh_entry_free_fn *free_fn); | |||||
| /** | |||||
| * Free a linkhash table. | |||||
| * If a callback free function is provided then it is called for all | |||||
| * entries in the table. | |||||
| * @param t table to free. | |||||
| */ | |||||
| extern void lh_table_free(struct lh_table *t); | |||||
| /** | |||||
| * Insert a record into the table. | |||||
| * @param t the table to insert into. | |||||
| * @param k a pointer to the key to insert. | |||||
| * @param v a pointer to the value to insert. | |||||
| */ | |||||
| extern int lh_table_insert(struct lh_table *t, void *k, void *v); | |||||
| /** | |||||
| * Lookup a record into the table. | |||||
| * @param t the table to lookup | |||||
| * @param k a pointer to the key to lookup | |||||
| * @return a pointer to the record structure of the value or NULL if it does not exist. | |||||
| */ | |||||
| extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k); | |||||
| /** | |||||
| * Lookup a record into the table | |||||
| * @param t the table to lookup | |||||
| * @param k a pointer to the key to lookup | |||||
| * @return a pointer to the found value or NULL if it does not exist. | |||||
| */ | |||||
| extern void* lh_table_lookup(struct lh_table *t, void *k); | |||||
| /** | |||||
| * Delete a record from the table. | |||||
| * If a callback free function is provided then it is called for the | |||||
| * for the item being deleted. | |||||
| * @param t the table to delete from. | |||||
| * @param e a pointer to the entry to delete. | |||||
| * @return 0 if the item was deleted. | |||||
| * @return -1 if it was not found. | |||||
| */ | |||||
| extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); | |||||
| /** | |||||
| * Delete a record from the table. | |||||
| * If a callback free function is provided then it is called for the | |||||
| * for the item being deleted. | |||||
| * @param t the table to delete from. | |||||
| * @param k a pointer to the key to delete. | |||||
| * @return 0 if the item was deleted. | |||||
| * @return -1 if it was not found. | |||||
| */ | |||||
| extern int lh_table_delete(struct lh_table *t, void *k); | |||||
| #endif | |||||
| @@ -0,0 +1,106 @@ | |||||
| /* | |||||
| * $Id: printbuf.c,v 1.3 2004/08/07 03:12:21 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <stdarg.h> | |||||
| #include <string.h> | |||||
| #include "bits.h" | |||||
| #include "debug.h" | |||||
| #include "printbuf.h" | |||||
| struct printbuf* printbuf_new() | |||||
| { | |||||
| struct printbuf *p; | |||||
| if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL; | |||||
| p->size = 32; | |||||
| p->bpos = 0; | |||||
| if(!(p->buf = malloc(p->size))) { | |||||
| free(p); | |||||
| return NULL; | |||||
| } | |||||
| return p; | |||||
| } | |||||
| int printbuf_memappend(struct printbuf *p, char *buf, int size) | |||||
| { | |||||
| char *t; | |||||
| if(p->size - p->bpos <= size) { | |||||
| int new_size = max(p->size * 2, p->bpos + size + 8); | |||||
| #if 0 | |||||
| mc_debug("printbuf_memappend: realloc " | |||||
| "bpos=%d wrsize=%d old_size=%d new_size=%d\n", | |||||
| p->bpos, size, p->size, new_size); | |||||
| #endif | |||||
| if(!(t = realloc(p->buf, new_size))) return -1; | |||||
| p->size = new_size; | |||||
| p->buf = t; | |||||
| } | |||||
| memcpy(p->buf + p->bpos, buf, size); | |||||
| p->bpos += size; | |||||
| p->buf[p->bpos]= '\0'; | |||||
| return size; | |||||
| } | |||||
| int sprintbuf(struct printbuf *p, const char *msg, ...) | |||||
| { | |||||
| va_list ap; | |||||
| char *t; | |||||
| int size; | |||||
| char buf[128]; | |||||
| /* user stack buffer first */ | |||||
| va_start(ap, msg); | |||||
| size = vsnprintf(buf, 128, msg, ap); | |||||
| va_end(ap); | |||||
| /* if string is greater than stack buffer, then use dynamic string | |||||
| with vasprintf. Note: some implementation of vsnprintf return -1 | |||||
| if output is truncated whereas some return the number of bytes that | |||||
| would have been writeen - this code handles both cases. */ | |||||
| if(size == -1 || size > 127) { | |||||
| int ret; | |||||
| va_start(ap, msg); | |||||
| if((size = vasprintf(&t, msg, ap)) == -1) return -1; | |||||
| va_end(ap); | |||||
| ret = printbuf_memappend(p, t, size); | |||||
| free(t); | |||||
| return ret; | |||||
| } else { | |||||
| return printbuf_memappend(p, buf, size); | |||||
| } | |||||
| } | |||||
| void printbuf_reset(struct printbuf *p) | |||||
| { | |||||
| p->buf[0] = '\0'; | |||||
| p->bpos = 0; | |||||
| } | |||||
| void printbuf_free(struct printbuf *p) | |||||
| { | |||||
| if(p) { | |||||
| free(p->buf); | |||||
| free(p); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,43 @@ | |||||
| /* | |||||
| * $Id: printbuf.h,v 1.2 2004/07/21 01:24:33 mclark Exp $ | |||||
| * | |||||
| * Copyright Metaparadigm Pte. Ltd. 2004. | |||||
| * Michael Clark <michael@metaparadigm.com> | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public (LGPL) | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details: http://www.gnu.org/ | |||||
| * | |||||
| */ | |||||
| #ifndef _printbuf_h_ | |||||
| #define _printbuf_h_ | |||||
| struct printbuf { | |||||
| char *buf; | |||||
| int bpos; | |||||
| int size; | |||||
| }; | |||||
| extern struct printbuf* | |||||
| printbuf_new(); | |||||
| extern int | |||||
| printbuf_memappend(struct printbuf *p, char *buf, int size); | |||||
| extern int | |||||
| sprintbuf(struct printbuf *p, const char *msg, ...); | |||||
| extern void | |||||
| printbuf_reset(struct printbuf *p); | |||||
| extern void | |||||
| printbuf_free(struct printbuf *p); | |||||
| #endif | |||||
| @@ -0,0 +1,134 @@ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include "json.h" | |||||
| int main(int argc, char **argv) | |||||
| { | |||||
| struct json_object *my_string, *my_int, *my_object, *my_array; | |||||
| struct json_object *new_obj; | |||||
| my_string = json_object_new_string("\t"); | |||||
| printf("my_string=%s\n", json_object_get_string(my_string)); | |||||
| printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); | |||||
| json_object_put(my_string); | |||||
| my_string = json_object_new_string("foo"); | |||||
| printf("my_string=%s\n", json_object_get_string(my_string)); | |||||
| printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); | |||||
| my_int = json_object_new_int(9); | |||||
| printf("my_int=%d\n", json_object_get_int(my_int)); | |||||
| printf("my_int.to_string()=%s\n", json_object_to_json_string(my_int)); | |||||
| my_array = json_object_new_array(); | |||||
| json_object_array_add(my_array, json_object_new_int(1)); | |||||
| json_object_array_add(my_array, json_object_new_int(2)); | |||||
| json_object_array_add(my_array, json_object_new_int(3)); | |||||
| json_object_array_put_idx(my_array, 4, json_object_new_int(5)); | |||||
| printf("my_array=\n"); | |||||
| for(int i=0; i < json_object_array_length(my_array); i++) { | |||||
| struct json_object *obj = json_object_array_get_idx(my_array, i); | |||||
| printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); | |||||
| } | |||||
| printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); | |||||
| my_object = json_object_new_object(); | |||||
| json_object_object_add(my_object, "abc", json_object_new_int(12)); | |||||
| json_object_object_add(my_object, "foo", json_object_new_string("bar")); | |||||
| json_object_object_add(my_object, "bool0", json_object_new_boolean(0)); | |||||
| json_object_object_add(my_object, "bool1", json_object_new_boolean(1)); | |||||
| json_object_object_add(my_object, "baz", json_object_new_string("bang")); | |||||
| json_object_object_add(my_object, "baz", json_object_new_string("fark")); | |||||
| json_object_object_del(my_object, "baz"); | |||||
| json_object_object_add(my_object, "arr", my_array); | |||||
| printf("my_object=\n"); | |||||
| json_object_object_foreach(my_object, key, val) { | |||||
| printf("\t%s: %s\n", key, json_object_to_json_string(val)); | |||||
| } | |||||
| printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); | |||||
| new_obj = json_tokener_parse("\"\003\""); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("/* hello */\"foo\""); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("// hello\n\"foo\""); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("null"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("True"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("12"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("12.3"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("[\"\\n\"]"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("[null]"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("[]"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{}"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("foo"); | |||||
| if(is_error(new_obj)) printf("got error as expected\n"); | |||||
| json_object_put(my_string); | |||||
| json_object_put(my_int); | |||||
| json_object_put(my_object); | |||||
| //json_object_put(my_array); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,19 @@ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include "json.h" | |||||
| int main(int argc, char **argv) | |||||
| { | |||||
| struct json_object *new_obj; | |||||
| mc_set_debug(1); | |||||
| new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| return 0; | |||||
| } | |||||