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