summaryrefslogtreecommitdiff
path: root/jcnf/yajl/yajl_gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'jcnf/yajl/yajl_gen.c')
-rw-r--r--jcnf/yajl/yajl_gen.c381
1 files changed, 381 insertions, 0 deletions
diff --git a/jcnf/yajl/yajl_gen.c b/jcnf/yajl/yajl_gen.c
new file mode 100644
index 0000000..a400176
--- /dev/null
+++ b/jcnf/yajl/yajl_gen.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_gen.h"
+#include "yajl_buf.h"
+#include "yajl_encode.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+typedef enum {
+ yajl_gen_start,
+ yajl_gen_map_start,
+ yajl_gen_map_key,
+ yajl_gen_map_val,
+ yajl_gen_array_start,
+ yajl_gen_in_array,
+ yajl_gen_complete,
+ yajl_gen_error
+} yajl_gen_state;
+
+struct yajl_gen_t
+{
+ unsigned int depth;
+ unsigned int pretty;
+ const char * indentString;
+ yajl_gen_state state[YAJL_MAX_DEPTH];
+ yajl_buf buf;
+ unsigned char *pendingComment;
+ unsigned int pendingLen; /* Length of pending comment */
+ int pendingCpp; /* NZ if comment is C++ style, Z if C */
+ /* memory allocation routines */
+ yajl_alloc_funcs alloc;
+};
+
+yajl_gen
+yajl_gen_alloc(const yajl_gen_config * config,
+ const yajl_alloc_funcs * afs)
+{
+ yajl_gen g = NULL;
+ yajl_alloc_funcs afsBuffer;
+
+ /* first order of business is to set up memory allocation routines */
+ if (afs != NULL) {
+ if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
+ {
+ return NULL;
+ }
+ } else {
+ yajl_set_default_alloc_funcs(&afsBuffer);
+ afs = &afsBuffer;
+ }
+
+ g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t));
+ memset((void *) g, 0, sizeof(struct yajl_gen_t));
+ /* copy in pointers to allocation routines */
+ memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
+
+ if (config) {
+ g->pretty = config->beautify;
+ g->indentString = config->indentString ? config->indentString : " ";
+ }
+ g->buf = yajl_buf_alloc(&(g->alloc));
+
+ return g;
+}
+
+void
+yajl_gen_free(yajl_gen g)
+{
+ yajl_buf_free(g->buf);
+ YA_FREE(&(g->alloc), g);
+}
+
+#define INSERT_EOL \
+ if (g->pretty || g->pendingComment != NULL) \
+ yajl_insert_eol(g);
+
+#define INSERT_SEP \
+ if (g->state[g->depth] == yajl_gen_map_key || \
+ g->state[g->depth] == yajl_gen_in_array) { \
+ yajl_buf_append(g->buf, ",", 1); \
+ INSERT_EOL; \
+ } else if (g->state[g->depth] == yajl_gen_map_val) { \
+ yajl_buf_append(g->buf, ":", 1); \
+ if (g->pretty) yajl_buf_append(g->buf, " ", 1); \
+ }
+
+#define INSERT_WHITESPACE \
+ if (g->pretty) { \
+ if (g->state[g->depth] != yajl_gen_map_val) { \
+ unsigned int _i; \
+ for (_i=0;_i<g->depth;_i++) \
+ yajl_buf_append(g->buf, g->indentString, \
+ strlen(g->indentString)); \
+ } \
+ }
+
+#define INSERT_SOME_WHITESPACE \
+ if (g->pretty) { \
+ if (g->state[g->depth] != yajl_gen_map_val) { \
+ yajl_buf_append(g->buf, g->indentString, \
+ strlen(g->indentString)); \
+ } \
+ }
+
+#define ENSURE_NOT_KEY \
+ if (g->state[g->depth] == yajl_gen_map_key) { \
+ return yajl_gen_keys_must_be_strings; \
+ } \
+
+/* check that we're not complete, or in error state. in a valid state
+ * to be generating */
+#define ENSURE_VALID_STATE \
+ if (g->state[g->depth] == yajl_gen_error) { \
+ return yajl_gen_in_error_state;\
+ } else if (g->state[g->depth] == yajl_gen_complete) { \
+ return yajl_gen_generation_complete; \
+ }
+
+#define INCREMENT_DEPTH \
+ if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
+
+#define APPENDED_ATOM \
+ switch (g->state[g->depth]) { \
+ case yajl_gen_start: \
+ g->state[g->depth] = yajl_gen_complete; \
+ break; \
+ case yajl_gen_map_start: \
+ case yajl_gen_map_key: \
+ g->state[g->depth] = yajl_gen_map_val; \
+ break; \
+ case yajl_gen_array_start: \
+ g->state[g->depth] = yajl_gen_in_array; \
+ break; \
+ case yajl_gen_map_val: \
+ g->state[g->depth] = yajl_gen_map_key; \
+ break; \
+ default: \
+ break; \
+ } \
+
+#define FINAL_NEWLINE \
+ if (g->pretty && g->state[g->depth] == yajl_gen_complete) \
+ INSERT_EOL
+
+/* Insert an end of line, and take care of any */
+/* pending comments */
+static void yajl_insert_eol(yajl_gen g) {
+ if (g->pendingComment != NULL) {
+ INSERT_SOME_WHITESPACE;
+ if (g->pendingCpp)
+ yajl_buf_append(g->buf, "//", 2);
+ else
+ yajl_buf_append(g->buf, "/*", 2);
+ yajl_string_encode(g->buf, g->pendingComment, g->pendingLen);
+ if (!g->pendingCpp)
+ yajl_buf_append(g->buf, "*/", 2);
+ free(g->pendingComment);
+ g->pendingComment = NULL;
+ g->pendingLen = 0;
+ g->pendingCpp = 0;
+ }
+ yajl_buf_append(g->buf, "\n", 1);
+}
+
+/* Insert a comment at the end of the line. Append if there is already */
+/* one pending. */
+static void yajl_insert_pending_comment(
+yajl_gen g, const unsigned char * str, unsigned int len, int cpp) {
+ if (g->pendingComment != NULL) {
+ unsigned int tlen = g->pendingLen + 0 + len;
+ unsigned char *pendingComment;
+ pendingComment = (unsigned char *) realloc(g->pendingComment, sizeof(char) * tlen);
+ memcpy(pendingComment + g->pendingLen + 0, str, len);
+ g->pendingComment = pendingComment;
+ g->pendingLen = tlen;
+ } else {
+ g->pendingComment = (unsigned char *) malloc(sizeof(char) * len);
+ memcpy(g->pendingComment, str, len);
+ g->pendingLen = len;
+ }
+ g->pendingCpp = cpp;
+}
+
+yajl_gen_status
+yajl_gen_integer(yajl_gen g, long int number)
+{
+ char i[32];
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ sprintf(i, "%ld", number);
+ yajl_buf_append(g->buf, i, strlen(i));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_double(yajl_gen g, double number)
+{
+ char i[32];
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ sprintf(i, "%g", number);
+ yajl_buf_append(g->buf, i, strlen(i));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_number(yajl_gen g, const char * s, unsigned int l)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, s, l);
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_string(yajl_gen g, const unsigned char * str,
+ unsigned int len)
+{
+ ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "\"", 1);
+ yajl_string_encode(g->buf, str, len);
+ yajl_buf_append(g->buf, "\"", 1);
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_null(yajl_gen g)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "null", strlen("null"));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_bool(yajl_gen g, int boolean)
+{
+ const char * val = boolean ? "true" : "false";
+
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, val, strlen(val));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_map_open(yajl_gen g)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ INCREMENT_DEPTH;
+
+ g->state[g->depth] = yajl_gen_map_start;
+ yajl_buf_append(g->buf, "{", 1);
+ INSERT_EOL;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_map_close(yajl_gen g)
+{
+ ENSURE_VALID_STATE;
+ (g->depth)--;
+ INSERT_EOL;
+ APPENDED_ATOM;
+ INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "}", 1);
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_array_open(yajl_gen g)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ INCREMENT_DEPTH;
+ g->state[g->depth] = yajl_gen_array_start;
+ yajl_buf_append(g->buf, "[", 1);
+ INSERT_EOL;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_array_close(yajl_gen g)
+{
+ ENSURE_VALID_STATE;
+ INSERT_EOL;
+ (g->depth)--;
+ APPENDED_ATOM;
+ INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "]", 1);
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_c_comment(yajl_gen g, const unsigned char * str,
+ unsigned int len, int dlytoeol)
+{
+ ENSURE_VALID_STATE;
+ if (dlytoeol) {
+ yajl_insert_pending_comment(g, str, len, 0);
+ } else {
+ if (g->pretty)
+ yajl_buf_append(g->buf, " /*", 3);
+ else
+ yajl_buf_append(g->buf, "/*", 2);
+ yajl_string_encode(g->buf, str, len);
+ if (g->pretty)
+ yajl_buf_append(g->buf, "*/ ", 3);
+ else
+ yajl_buf_append(g->buf, "*/", 2);
+ }
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_cpp_comment(yajl_gen g, const unsigned char * str,
+ unsigned int len)
+{
+ ENSURE_VALID_STATE;
+ yajl_insert_pending_comment(g, str, len, 1);
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf,
+ unsigned int * len)
+{
+ *buf = yajl_buf_data(g->buf);
+ *len = yajl_buf_len(g->buf);
+ return yajl_gen_status_ok;
+}
+
+void
+yajl_gen_clear(yajl_gen g)
+{
+ yajl_buf_clear(g->buf);
+}