xref: /freebsd/contrib/libucl/src/ucl_emitter_streamline.c (revision a831d7d1c538b93ffec095657d9a6e6e778db195)
1 /* Copyright (c) 2014, Vsevolod Stakhov
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *       * Redistributions of source code must retain the above copyright
7  *         notice, this list of conditions and the following disclaimer.
8  *       * Redistributions in binary form must reproduce the above copyright
9  *         notice, this list of conditions and the following disclaimer in the
10  *         documentation and/or other materials provided with the distribution.
11  *
12  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "ucl.h"
29 #include "ucl_internal.h"
30 #include "ucl_chartable.h"
31 
32 struct ucl_emitter_streamline_stack {
33 	bool is_array;
34 	bool empty;
35 	const ucl_object_t *obj;
36 	struct ucl_emitter_streamline_stack *next;
37 };
38 
39 struct ucl_emitter_context_streamline {
40 	/* Inherited from the main context */
41 	const char *name;
42 	int id;
43 	const struct ucl_emitter_functions *func;
44 	const struct ucl_emitter_operations *ops;
45 	unsigned int ident;
46 	const ucl_object_t *top;
47 
48 	/* Streamline specific fields */
49 	struct ucl_emitter_streamline_stack *containers;
50 };
51 
52 #define TO_STREAMLINE(ctx) (struct ucl_emitter_context_streamline *)(ctx)
53 
54 struct ucl_emitter_context*
55 ucl_object_emit_streamline_new (const ucl_object_t *obj,
56 		enum ucl_emitter emit_type,
57 		struct ucl_emitter_functions *emitter)
58 {
59 	const struct ucl_emitter_context *ctx;
60 	struct ucl_emitter_context_streamline *sctx;
61 
62 	ctx = ucl_emit_get_standard_context (emit_type);
63 	if (ctx == NULL) {
64 		return NULL;
65 	}
66 
67 	sctx = calloc (1, sizeof (*sctx));
68 	if (sctx == NULL) {
69 		return NULL;
70 	}
71 
72 	memcpy (sctx, ctx, sizeof (*ctx));
73 	sctx->func = emitter;
74 	sctx->top = obj;
75 
76 	ucl_object_emit_streamline_start_container ((struct ucl_emitter_context *)sctx,
77 			obj);
78 
79 	return (struct ucl_emitter_context *)sctx;
80 }
81 
82 void
83 ucl_object_emit_streamline_start_container (struct ucl_emitter_context *ctx,
84 		const ucl_object_t *obj)
85 {
86 	struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
87 	struct ucl_emitter_streamline_stack *st, *top;
88 	bool print_key = false;
89 
90 	/* Check top object presence */
91 	if (sctx->top == NULL) {
92 		sctx->top = obj;
93 	}
94 
95 	top = sctx->containers;
96 	st = malloc (sizeof (*st));
97 	if (st != NULL) {
98 		if (top != NULL && !top->is_array) {
99 			print_key = true;
100 		}
101 		st->empty = true;
102 		st->obj = obj;
103 		if (obj != NULL && obj->type == UCL_ARRAY) {
104 			st->is_array = true;
105 			sctx->ops->ucl_emitter_start_array (ctx, obj, print_key);
106 		}
107 		else {
108 			st->is_array = false;
109 			sctx->ops->ucl_emitter_start_object (ctx, obj, print_key);
110 		}
111 		LL_PREPEND (sctx->containers, st);
112 	}
113 }
114 
115 void
116 ucl_object_emit_streamline_add_object (
117 		struct ucl_emitter_context *ctx, const ucl_object_t *obj)
118 {
119 	struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
120 	bool is_array = false, is_first = false;
121 
122 	if (sctx->containers != NULL) {
123 		if (sctx->containers->is_array) {
124 			is_array = true;
125 		}
126 		if (sctx->containers->empty) {
127 			is_first = true;
128 			sctx->containers->empty = false;
129 		}
130 	}
131 
132 	sctx->ops->ucl_emitter_write_elt (ctx, obj, is_first, !is_array);
133 }
134 
135 void
136 ucl_object_emit_streamline_end_container (struct ucl_emitter_context *ctx)
137 {
138 	struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
139 	struct ucl_emitter_streamline_stack *st;
140 
141 	if (sctx->containers != NULL) {
142 		st = sctx->containers;
143 
144 		if (st->is_array) {
145 			sctx->ops->ucl_emitter_end_array (ctx, st->obj);
146 		}
147 		else {
148 			sctx->ops->ucl_emitter_end_object (ctx, st->obj);
149 		}
150 		sctx->containers = st->next;
151 		free (st);
152 	}
153 }
154 
155 void
156 ucl_object_emit_streamline_finish (struct ucl_emitter_context *ctx)
157 {
158 	struct ucl_emitter_context_streamline *sctx = TO_STREAMLINE(ctx);
159 
160 	while (sctx->containers != NULL) {
161 		ucl_object_emit_streamline_end_container (ctx);
162 	}
163 
164 	free (sctx);
165 }
166