2 * Copyright 2007-2009, Lloyd Hilaiel.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * 3. Neither the name of Lloyd Hilaiel nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include "yajl/yajl_gen.h"
35 #include "yajl_encode.h"
56 const char * indentString
;
57 yajl_gen_state state
[YAJL_MAX_DEPTH
];
59 /* memory allocation routines */
60 yajl_alloc_funcs alloc
;
64 yajl_gen_alloc(const yajl_gen_config
* config
,
65 const yajl_alloc_funcs
* afs
)
68 yajl_alloc_funcs afsBuffer
;
70 /* first order of business is to set up memory allocation routines */
72 if (afs
->malloc
== NULL
|| afs
->realloc
== NULL
|| afs
->free
== NULL
)
77 yajl_set_default_alloc_funcs(&afsBuffer
);
81 g
= (yajl_gen
) YA_MALLOC(afs
, sizeof(struct yajl_gen_t
));
82 memset((void *) g
, 0, sizeof(struct yajl_gen_t
));
83 /* copy in pointers to allocation routines */
84 memcpy((void *) &(g
->alloc
), (void *) afs
, sizeof(yajl_alloc_funcs
));
87 g
->pretty
= config
->beautify
;
88 g
->indentString
= config
->indentString
? config
->indentString
: " ";
90 g
->buf
= yajl_buf_alloc(&(g
->alloc
));
96 yajl_gen_free(yajl_gen g
)
98 yajl_buf_free(g
->buf
);
99 YA_FREE(&(g
->alloc
), g
);
103 if (g->state[g->depth] == yajl_gen_map_key || \
104 g->state[g->depth] == yajl_gen_in_array) { \
105 yajl_buf_append(g->buf, ",", 1); \
106 if (g->pretty) yajl_buf_append(g->buf, "\n", 1); \
107 } else if (g->state[g->depth] == yajl_gen_map_val) { \
108 yajl_buf_append(g->buf, ":", 1); \
109 if (g->pretty) yajl_buf_append(g->buf, " ", 1); \
112 #define INSERT_WHITESPACE \
114 if (g->state[g->depth] != yajl_gen_map_val) { \
116 for (_i=0;_i<g->depth;_i++) \
117 yajl_buf_append(g->buf, g->indentString, \
118 strlen(g->indentString)); \
122 #define ENSURE_NOT_KEY \
123 if (g->state[g->depth] == yajl_gen_map_key) { \
124 return yajl_gen_keys_must_be_strings; \
127 /* check that we're not complete, or in error state. in a valid state
128 * to be generating */
129 #define ENSURE_VALID_STATE \
130 if (g->state[g->depth] == yajl_gen_error) { \
131 return yajl_gen_in_error_state;\
132 } else if (g->state[g->depth] == yajl_gen_complete) { \
133 return yajl_gen_generation_complete; \
136 #define INCREMENT_DEPTH \
137 if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
139 #define APPENDED_ATOM \
140 switch (g->state[g->depth]) { \
141 case yajl_gen_start: \
142 g->state[g->depth] = yajl_gen_complete; \
144 case yajl_gen_map_start: \
145 case yajl_gen_map_key: \
146 g->state[g->depth] = yajl_gen_map_val; \
148 case yajl_gen_array_start: \
149 g->state[g->depth] = yajl_gen_in_array; \
151 case yajl_gen_map_val: \
152 g->state[g->depth] = yajl_gen_map_key; \
158 #define FINAL_NEWLINE \
159 if (g->pretty && g->state[g->depth] == yajl_gen_complete) \
160 yajl_buf_append(g->buf, "\n", 1);
163 yajl_gen_integer(yajl_gen g
, long int number
)
166 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
167 sprintf(i
, "%ld", number
);
168 yajl_buf_append(g
->buf
, i
, strlen(i
));
171 return yajl_gen_status_ok
;
175 yajl_gen_double(yajl_gen g
, double number
)
178 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
179 sprintf(i
, "%g", number
);
180 yajl_buf_append(g
->buf
, i
, strlen(i
));
183 return yajl_gen_status_ok
;
187 yajl_gen_number(yajl_gen g
, const char * s
, unsigned int l
)
189 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
190 yajl_buf_append(g
->buf
, s
, l
);
193 return yajl_gen_status_ok
;
197 yajl_gen_string(yajl_gen g
, const unsigned char * str
,
200 ENSURE_VALID_STATE
; INSERT_SEP
; INSERT_WHITESPACE
;
201 yajl_buf_append(g
->buf
, "\"", 1);
202 yajl_string_encode(g
->buf
, str
, len
);
203 yajl_buf_append(g
->buf
, "\"", 1);
206 return yajl_gen_status_ok
;
210 yajl_gen_null(yajl_gen g
)
212 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
213 yajl_buf_append(g
->buf
, "null", strlen("null"));
216 return yajl_gen_status_ok
;
220 yajl_gen_bool(yajl_gen g
, int boolean
)
222 const char * val
= boolean
? "true" : "false";
224 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
225 yajl_buf_append(g
->buf
, val
, strlen(val
));
228 return yajl_gen_status_ok
;
232 yajl_gen_map_open(yajl_gen g
)
234 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
237 g
->state
[g
->depth
] = yajl_gen_map_start
;
238 yajl_buf_append(g
->buf
, "{", 1);
239 if (g
->pretty
) yajl_buf_append(g
->buf
, "\n", 1);
241 return yajl_gen_status_ok
;
245 yajl_gen_map_close(yajl_gen g
)
249 if (g
->pretty
) yajl_buf_append(g
->buf
, "\n", 1);
252 yajl_buf_append(g
->buf
, "}", 1);
254 return yajl_gen_status_ok
;
258 yajl_gen_array_open(yajl_gen g
)
260 ENSURE_VALID_STATE
; ENSURE_NOT_KEY
; INSERT_SEP
; INSERT_WHITESPACE
;
262 g
->state
[g
->depth
] = yajl_gen_array_start
;
263 yajl_buf_append(g
->buf
, "[", 1);
264 if (g
->pretty
) yajl_buf_append(g
->buf
, "\n", 1);
266 return yajl_gen_status_ok
;
270 yajl_gen_array_close(yajl_gen g
)
273 if (g
->pretty
) yajl_buf_append(g
->buf
, "\n", 1);
277 yajl_buf_append(g
->buf
, "]", 1);
279 return yajl_gen_status_ok
;
283 yajl_gen_get_buf(yajl_gen g
, const unsigned char ** buf
,
286 *buf
= yajl_buf_data(g
->buf
);
287 *len
= yajl_buf_len(g
->buf
);
288 return yajl_gen_status_ok
;
292 yajl_gen_clear(yajl_gen g
)
294 yajl_buf_clear(g
->buf
);