D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
td-agent
/
embedded
/
lib
/
ruby
/
gems
/
2.1.0
/
gems
/
yajl-ruby-1.3.0
/
ext
/
yajl
/
Filename :
yajl_gen.c
back
Copy
/* * Copyright 2010, 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 "api/yajl_gen.h" #include "yajl_buf.h" #include "yajl_encode.h" #include <stdlib.h> #include <string.h> #include <stdio.h> #include <math.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_print_t print; void * ctx; /* yajl_buf */ /* memory allocation routines */ yajl_alloc_funcs alloc; unsigned int htmlSafe; }; yajl_gen yajl_gen_alloc(const yajl_gen_config * config, const yajl_alloc_funcs * afs) { return yajl_gen_alloc2(NULL, config, afs, NULL); } yajl_gen yajl_gen_alloc2(const yajl_print_t callback, const yajl_gen_config * config, const yajl_alloc_funcs * afs, void * ctx) { 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)); if (!g) return NULL; 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) { const char *indent = config->indentString; g->pretty = config->beautify; g->indentString = config->indentString; if (indent) { for (; *indent; indent++) { if (*indent != '\n' && *indent != '\v' && *indent != '\f' && *indent != '\t' && *indent != '\r' && *indent != ' ') { g->indentString = NULL; break; } } } if (!g->indentString) { g->indentString = " "; } g->htmlSafe = config->htmlSafe; } if (callback) { g->print = callback; g->ctx = ctx; } else { g->print = (yajl_print_t)&yajl_buf_append; g->ctx = yajl_buf_alloc(&(g->alloc)); } return g; } void yajl_gen_free(yajl_gen g) { if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx); YA_FREE(&(g->alloc), g); } #define INSERT_SEP \ if (g->state[g->depth] == yajl_gen_map_key || \ g->state[g->depth] == yajl_gen_in_array) { \ g->print(g->ctx, ",", 1); \ if (g->pretty) g->print(g->ctx, "\n", 1); \ } else if (g->state[g->depth] == yajl_gen_map_val) { \ g->print(g->ctx, ":", 1); \ if (g->pretty) g->print(g->ctx, " ", 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++) \ g->print(g->ctx, \ g->indentString, \ (unsigned int)strlen(g->indentString)); \ } \ } #define ENSURE_NOT_KEY \ if (g->state[g->depth] == yajl_gen_map_key || \ g->state[g->depth] == yajl_gen_map_start) { \ 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 DECREMENT_DEPTH \ if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_error; #define APPENDED_ATOM \ switch (g->state[g->depth]) { \ 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 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); g->print(g->ctx, i, (unsigned int)strlen(i)); APPENDED_ATOM; FINAL_NEWLINE; return yajl_gen_status_ok; } #ifdef WIN32 #include <float.h> #define isnan _isnan #define isinf !_finite #endif yajl_gen_status yajl_gen_double(yajl_gen g, double number) { char i[32]; ENSURE_VALID_STATE; ENSURE_NOT_KEY; if (isnan(number) || isinf(number)) return yajl_gen_invalid_number; INSERT_SEP; INSERT_WHITESPACE; sprintf(i, "%.20g", number); g->print(g->ctx, i, (unsigned int)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; g->print(g->ctx, 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; g->print(g->ctx, "\"", 1); yajl_string_encode2(g->print, g->ctx, str, len, g->htmlSafe); g->print(g->ctx, "\"", 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; g->print(g->ctx, "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; g->print(g->ctx, val, (unsigned int)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; g->print(g->ctx, "{", 1); if (g->pretty) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_map_close(yajl_gen g) { ENSURE_VALID_STATE; DECREMENT_DEPTH; if (g->pretty) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; g->print(g->ctx, "}", 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; g->print(g->ctx, "[", 1); if (g->pretty) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } yajl_gen_status yajl_gen_array_close(yajl_gen g) { ENSURE_VALID_STATE; DECREMENT_DEPTH; if (g->pretty) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; g->print(g->ctx, "]", 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) { if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; *buf = yajl_buf_data((yajl_buf)g->ctx); *len = yajl_buf_len((yajl_buf)g->ctx); return yajl_gen_status_ok; } void yajl_gen_clear(yajl_gen g) { if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx); }