1 /* Copyright (c) 2013, 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 #include "ucl.h"
25 #include "ucl_internal.h"
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29
30
31 int
main(int argc,char ** argv)32 main (int argc, char **argv)
33 {
34 char *inbuf = NULL;
35 struct ucl_parser *parser = NULL, *parser2 = NULL;
36 ucl_object_t *obj, *comments = NULL;
37 ssize_t bufsize, r;
38 FILE *in, *out;
39 unsigned char *emitted = NULL;
40 const char *fname_in = NULL, *fname_out = NULL;
41 int ret = 0, opt, json = 0, compact = 0, yaml = 0,
42 save_comments = 0, skip_macro = 0,
43 flags, fd_out, fd_in, use_fd = 0, msgpack_input = 0;
44 struct ucl_emitter_functions *func;
45
46 while ((opt = getopt(argc, argv, "fjcyCMm")) != -1) {
47 switch (opt) {
48 case 'j':
49 json = 1;
50 break;
51 case 'c':
52 compact = 1;
53 break;
54 case 'C':
55 save_comments = 1;
56 break;
57 case 'y':
58 yaml = 1;
59 break;
60 case 'M':
61 skip_macro = true;
62 break;
63 case 'm':
64 msgpack_input = 1;
65 break;
66 case 'f':
67 use_fd = true;
68 break;
69 default: /* '?' */
70 fprintf (stderr, "Usage: %s [-jcy] [-CM] [-f] [in] [out]\n",
71 argv[0]);
72 exit (EXIT_FAILURE);
73 }
74 }
75
76 argc -= optind;
77 argv += optind;
78
79 switch (argc) {
80 case 1:
81 fname_in = argv[0];
82 break;
83 case 2:
84 fname_in = argv[0];
85 fname_out = argv[1];
86 break;
87 }
88
89 if (!use_fd) {
90 if (fname_in != NULL) {
91 in = fopen (fname_in, "r");
92 if (in == NULL) {
93 exit (-errno);
94 }
95 }
96 else {
97 in = stdin;
98 }
99 }
100 else {
101 if (fname_in != NULL) {
102 fd_in = open (fname_in, O_RDONLY);
103 if (fd_in == -1) {
104 exit (-errno);
105 }
106 }
107 else {
108 fd_in = STDIN_FILENO;
109 }
110 }
111
112 flags = UCL_PARSER_KEY_LOWERCASE;
113
114 if (save_comments) {
115 flags |= UCL_PARSER_SAVE_COMMENTS;
116 }
117
118 if (skip_macro) {
119 flags |= UCL_PARSER_DISABLE_MACRO;
120 }
121
122 parser = ucl_parser_new (flags);
123 ucl_parser_register_variable (parser, "ABI", "unknown");
124
125 if (fname_in != NULL) {
126 ucl_parser_set_filevars (parser, fname_in, true);
127 }
128
129 if (!use_fd) {
130 inbuf = malloc (BUFSIZ);
131 bufsize = BUFSIZ;
132 r = 0;
133
134 while (!feof (in) && !ferror (in)) {
135 if (r == bufsize) {
136 inbuf = realloc (inbuf, bufsize * 2);
137 bufsize *= 2;
138 if (inbuf == NULL) {
139 perror ("realloc");
140 exit (EXIT_FAILURE);
141 }
142 }
143 r += fread (inbuf + r, 1, bufsize - r, in);
144 }
145
146 if (ferror (in)) {
147 fprintf (stderr, "Failed to read the input file.\n");
148 exit (EXIT_FAILURE);
149 }
150
151 ucl_parser_add_chunk_full (parser, (const unsigned char *)inbuf, r,
152 0, UCL_DUPLICATE_APPEND,
153 msgpack_input ? UCL_PARSE_MSGPACK : UCL_PARSE_UCL);
154 fclose (in);
155 }
156 else {
157 ucl_parser_add_fd (parser, fd_in);
158 close (fd_in);
159 }
160
161 if (!use_fd) {
162 if (fname_out != NULL) {
163 out = fopen (fname_out, "w");
164 if (out == NULL) {
165 exit (-errno);
166 }
167 }
168 else {
169 out = stdout;
170 }
171 }
172 else {
173 if (fname_out != NULL) {
174 fd_out = open (fname_out, O_WRONLY | O_CREAT, 00644);
175 if (fd_out == -1) {
176 exit (-errno);
177 }
178 }
179 else {
180 fd_out = STDOUT_FILENO;
181 }
182 }
183
184
185 if (ucl_parser_get_error (parser) != NULL) {
186 fprintf (out, "Error occurred (phase 1): %s\n",
187 ucl_parser_get_error(parser));
188 ret = 1;
189 goto end;
190 }
191
192 obj = ucl_parser_get_object (parser);
193
194 if (save_comments) {
195 comments = ucl_object_ref (ucl_parser_get_comments (parser));
196 }
197
198 if (json) {
199 if (compact) {
200 emitted = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT);
201 }
202 else {
203 emitted = ucl_object_emit (obj, UCL_EMIT_JSON);
204 }
205 }
206 else if (yaml) {
207 emitted = ucl_object_emit (obj, UCL_EMIT_YAML);
208 }
209 else {
210 emitted = NULL;
211 func = ucl_object_emit_memory_funcs ((void **)&emitted);
212
213 if (func != NULL) {
214 ucl_object_emit_full (obj, UCL_EMIT_CONFIG, func, comments);
215 ucl_object_emit_funcs_free (func);
216 }
217 }
218
219 #if 0
220 fprintf (out, "%s\n****\n", emitted);
221 #endif
222
223 ucl_parser_free (parser);
224 ucl_object_unref (obj);
225 parser2 = ucl_parser_new (flags);
226 ucl_parser_add_string (parser2, (const char *)emitted, 0);
227
228 if (ucl_parser_get_error(parser2) != NULL) {
229 fprintf (out, "Error occurred (phase 2): %s\n",
230 ucl_parser_get_error(parser2));
231 fprintf (out, "%s\n", emitted);
232 ret = 1;
233 goto end;
234 }
235
236 if (emitted != NULL) {
237 free (emitted);
238 }
239 if (comments) {
240 ucl_object_unref (comments);
241 comments = NULL;
242 }
243
244 if (save_comments) {
245 comments = ucl_object_ref (ucl_parser_get_comments (parser2));
246 }
247
248 obj = ucl_parser_get_object (parser2);
249
250 if (!use_fd) {
251 func = ucl_object_emit_file_funcs (out);
252 }
253 else {
254 func = ucl_object_emit_fd_funcs (fd_out);
255 }
256
257 if (func != NULL) {
258 if (json) {
259 if (compact) {
260 ucl_object_emit_full (obj, UCL_EMIT_JSON_COMPACT,
261 func, comments);
262 }
263 else {
264 ucl_object_emit_full (obj, UCL_EMIT_JSON,
265 func, comments);
266 }
267 }
268 else if (yaml) {
269 ucl_object_emit_full (obj, UCL_EMIT_YAML,
270 func, comments);
271 }
272 else {
273 ucl_object_emit_full (obj, UCL_EMIT_CONFIG,
274 func, comments);
275 }
276
277 ucl_object_emit_funcs_free (func);
278 }
279
280 if (!use_fd) {
281 fprintf (out, "\n");
282 fclose (out);
283 }
284 else {
285 write (fd_out, "\n", 1);
286 close (fd_out);
287 }
288
289 ucl_object_unref (obj);
290
291 end:
292 if (parser2 != NULL) {
293 ucl_parser_free (parser2);
294 }
295 if (comments) {
296 ucl_object_unref (comments);
297 }
298 if (inbuf != NULL) {
299 free (inbuf);
300 }
301
302 return ret;
303 }
304