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; | |||
| } | |||