1262395Sbapt/* Copyright (c) 2013, Vsevolod Stakhov
2262395Sbapt * All rights reserved.
3262395Sbapt *
4262395Sbapt * Redistribution and use in source and binary forms, with or without
5262395Sbapt * modification, are permitted provided that the following conditions are met:
6262395Sbapt *       * Redistributions of source code must retain the above copyright
7262395Sbapt *         notice, this list of conditions and the following disclaimer.
8262395Sbapt *       * Redistributions in binary form must reproduce the above copyright
9262395Sbapt *         notice, this list of conditions and the following disclaimer in the
10262395Sbapt *         documentation and/or other materials provided with the distribution.
11262395Sbapt *
12262395Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13262395Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14262395Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15262395Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16262395Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17262395Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18262395Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19262395Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20262395Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21262395Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22262395Sbapt */
23262395Sbapt
24262395Sbapt#include "ucl.h"
25263648Sbapt#include "ucl_internal.h"
26298166Sbapt#include <sys/types.h>
27298166Sbapt#include <fcntl.h>
28298166Sbapt#include <unistd.h>
29262395Sbapt
30298166Sbapt
31262395Sbaptint
32262395Sbaptmain (int argc, char **argv)
33262395Sbapt{
34298166Sbapt	char *inbuf = NULL;
35262395Sbapt	struct ucl_parser *parser = NULL, *parser2 = NULL;
36298166Sbapt	ucl_object_t *obj, *comments = NULL;
37290071Sbapt	ssize_t bufsize, r;
38262395Sbapt	FILE *in, *out;
39262395Sbapt	unsigned char *emitted = NULL;
40262395Sbapt	const char *fname_in = NULL, *fname_out = NULL;
41298166Sbapt	int ret = 0, opt, json = 0, compact = 0, yaml = 0,
42298166Sbapt			save_comments = 0, skip_macro = 0,
43298166Sbapt			flags, fd_out, fd_in, use_fd = 0;
44298166Sbapt	struct ucl_emitter_functions *func;
45262395Sbapt
46298166Sbapt	while ((opt = getopt(argc, argv, "fjcyCM")) != -1) {
47262395Sbapt		switch (opt) {
48262395Sbapt		case 'j':
49262395Sbapt			json = 1;
50262395Sbapt			break;
51268831Sbapt		case 'c':
52268831Sbapt			compact = 1;
53268831Sbapt			break;
54298166Sbapt		case 'C':
55298166Sbapt			save_comments = 1;
56298166Sbapt			break;
57268831Sbapt		case 'y':
58268831Sbapt			yaml = 1;
59268831Sbapt			break;
60298166Sbapt		case 'M':
61298166Sbapt			skip_macro = true;
62298166Sbapt			break;
63298166Sbapt		case 'f':
64298166Sbapt			use_fd = true;
65298166Sbapt			break;
66262395Sbapt		default: /* '?' */
67298166Sbapt			fprintf (stderr, "Usage: %s [-jcy] [-CM] [-f] [in] [out]\n",
68262395Sbapt					argv[0]);
69262395Sbapt			exit (EXIT_FAILURE);
70262395Sbapt		}
71262395Sbapt	}
72262395Sbapt
73262395Sbapt	argc -= optind;
74262395Sbapt	argv += optind;
75262395Sbapt
76262395Sbapt	switch (argc) {
77262395Sbapt	case 1:
78262395Sbapt		fname_in = argv[0];
79262395Sbapt		break;
80262395Sbapt	case 2:
81262395Sbapt		fname_in = argv[0];
82262395Sbapt		fname_out = argv[1];
83262395Sbapt		break;
84262395Sbapt	}
85262395Sbapt
86298166Sbapt	if (!use_fd) {
87298166Sbapt		if (fname_in != NULL) {
88298166Sbapt			in = fopen (fname_in, "r");
89298166Sbapt			if (in == NULL) {
90298166Sbapt				exit (-errno);
91298166Sbapt			}
92262395Sbapt		}
93298166Sbapt		else {
94298166Sbapt			in = stdin;
95298166Sbapt		}
96262395Sbapt	}
97262395Sbapt	else {
98298166Sbapt		if (fname_in != NULL) {
99298166Sbapt			fd_in = open (fname_in, O_RDONLY);
100298166Sbapt			if (fd_in == -1) {
101298166Sbapt				exit (-errno);
102298166Sbapt			}
103298166Sbapt		}
104298166Sbapt		else {
105298166Sbapt			fd_in = STDIN_FILENO;
106298166Sbapt		}
107262395Sbapt	}
108298166Sbapt
109298166Sbapt	flags = UCL_PARSER_KEY_LOWERCASE;
110298166Sbapt
111298166Sbapt	if (save_comments) {
112298166Sbapt		flags |= UCL_PARSER_SAVE_COMMENTS;
113298166Sbapt	}
114298166Sbapt
115298166Sbapt	if (skip_macro) {
116298166Sbapt		flags |= UCL_PARSER_DISABLE_MACRO;
117298166Sbapt	}
118298166Sbapt
119298166Sbapt	parser = ucl_parser_new (flags);
120262395Sbapt	ucl_parser_register_variable (parser, "ABI", "unknown");
121262395Sbapt
122262395Sbapt	if (fname_in != NULL) {
123262395Sbapt		ucl_parser_set_filevars (parser, fname_in, true);
124262395Sbapt	}
125262395Sbapt
126298166Sbapt	if (!use_fd) {
127298166Sbapt		inbuf = malloc (BUFSIZ);
128298166Sbapt		bufsize = BUFSIZ;
129298166Sbapt		r = 0;
130290071Sbapt
131298166Sbapt		while (!feof (in) && !ferror (in)) {
132298166Sbapt			if (r == bufsize) {
133298166Sbapt				inbuf = realloc (inbuf, bufsize * 2);
134298166Sbapt				bufsize *= 2;
135298166Sbapt				if (inbuf == NULL) {
136298166Sbapt					perror ("realloc");
137298166Sbapt					exit (EXIT_FAILURE);
138298166Sbapt				}
139290071Sbapt			}
140298166Sbapt			r += fread (inbuf + r, 1, bufsize - r, in);
141264789Sbapt		}
142290071Sbapt
143298166Sbapt		if (ferror (in)) {
144298166Sbapt			fprintf (stderr, "Failed to read the input file.\n");
145298166Sbapt			exit (EXIT_FAILURE);
146298166Sbapt		}
147298166Sbapt
148298166Sbapt		ucl_parser_add_chunk (parser, (const unsigned char *)inbuf, r);
149298166Sbapt		fclose (in);
150290071Sbapt	}
151298166Sbapt	else {
152298166Sbapt		ucl_parser_add_fd (parser, fd_in);
153298166Sbapt		close (fd_in);
154298166Sbapt	}
155290071Sbapt
156298166Sbapt	if (!use_fd) {
157298166Sbapt		if (fname_out != NULL) {
158298166Sbapt			out = fopen (fname_out, "w");
159298166Sbapt			if (out == NULL) {
160298166Sbapt				exit (-errno);
161298166Sbapt			}
162262395Sbapt		}
163298166Sbapt		else {
164298166Sbapt			out = stdout;
165298166Sbapt		}
166262395Sbapt	}
167262395Sbapt	else {
168298166Sbapt		if (fname_out != NULL) {
169298166Sbapt			fd_out = open (fname_out, O_WRONLY | O_CREAT, 00644);
170298166Sbapt			if (fd_out == -1) {
171298166Sbapt				exit (-errno);
172298166Sbapt			}
173298166Sbapt		}
174298166Sbapt		else {
175298166Sbapt			fd_out = STDOUT_FILENO;
176298166Sbapt		}
177262395Sbapt	}
178290071Sbapt
179298166Sbapt
180263648Sbapt	if (ucl_parser_get_error (parser) != NULL) {
181298166Sbapt		fprintf (out, "Error occurred (phase 1): %s\n",
182298166Sbapt						ucl_parser_get_error(parser));
183262395Sbapt		ret = 1;
184262395Sbapt		goto end;
185262395Sbapt	}
186290071Sbapt
187262395Sbapt	obj = ucl_parser_get_object (parser);
188290071Sbapt
189298166Sbapt	if (save_comments) {
190298166Sbapt		comments = ucl_object_ref (ucl_parser_get_comments (parser));
191298166Sbapt	}
192298166Sbapt
193262395Sbapt	if (json) {
194268831Sbapt		if (compact) {
195268831Sbapt			emitted = ucl_object_emit (obj, UCL_EMIT_JSON_COMPACT);
196268831Sbapt		}
197268831Sbapt		else {
198268831Sbapt			emitted = ucl_object_emit (obj, UCL_EMIT_JSON);
199268831Sbapt		}
200262395Sbapt	}
201268831Sbapt	else if (yaml) {
202268831Sbapt		emitted = ucl_object_emit (obj, UCL_EMIT_YAML);
203268831Sbapt	}
204262395Sbapt	else {
205298166Sbapt		emitted = NULL;
206298166Sbapt		func = ucl_object_emit_memory_funcs ((void **)&emitted);
207298166Sbapt
208298166Sbapt		if (func != NULL) {
209298166Sbapt			ucl_object_emit_full (obj, UCL_EMIT_CONFIG, func, comments);
210298166Sbapt			ucl_object_emit_funcs_free (func);
211298166Sbapt		}
212262395Sbapt	}
213290071Sbapt
214298166Sbapt#if 0
215298166Sbapt	fprintf (out, "%s\n****\n", emitted);
216298166Sbapt#endif
217298166Sbapt
218262395Sbapt	ucl_parser_free (parser);
219262395Sbapt	ucl_object_unref (obj);
220298166Sbapt	parser2 = ucl_parser_new (flags);
221275223Sbapt	ucl_parser_add_string (parser2, (const char *)emitted, 0);
222262395Sbapt
223262395Sbapt	if (ucl_parser_get_error(parser2) != NULL) {
224298166Sbapt		fprintf (out, "Error occurred (phase 2): %s\n",
225298166Sbapt				ucl_parser_get_error(parser2));
226262395Sbapt		fprintf (out, "%s\n", emitted);
227262395Sbapt		ret = 1;
228262395Sbapt		goto end;
229262395Sbapt	}
230290071Sbapt
231262395Sbapt	if (emitted != NULL) {
232262395Sbapt		free (emitted);
233262395Sbapt	}
234298166Sbapt	if (comments) {
235298166Sbapt		ucl_object_unref (comments);
236298166Sbapt		comments = NULL;
237298166Sbapt	}
238290071Sbapt
239298166Sbapt	if (save_comments) {
240298166Sbapt		comments = ucl_object_ref (ucl_parser_get_comments (parser2));
241298166Sbapt	}
242298166Sbapt
243262395Sbapt	obj = ucl_parser_get_object (parser2);
244298166Sbapt
245298166Sbapt	if (!use_fd) {
246298166Sbapt		func = ucl_object_emit_file_funcs (out);
247298166Sbapt	}
248298166Sbapt	else {
249298166Sbapt		func = ucl_object_emit_fd_funcs (fd_out);
250298166Sbapt	}
251298166Sbapt
252298166Sbapt	if (func != NULL) {
253298166Sbapt		if (json) {
254298166Sbapt			if (compact) {
255298166Sbapt				ucl_object_emit_full (obj, UCL_EMIT_JSON_COMPACT,
256298166Sbapt						func, comments);
257298166Sbapt			}
258298166Sbapt			else {
259298166Sbapt				ucl_object_emit_full (obj, UCL_EMIT_JSON,
260298166Sbapt						func, comments);
261298166Sbapt			}
262268831Sbapt		}
263298166Sbapt		else if (yaml) {
264298166Sbapt			ucl_object_emit_full (obj, UCL_EMIT_YAML,
265298166Sbapt					func, comments);
266298166Sbapt		}
267268831Sbapt		else {
268298166Sbapt			ucl_object_emit_full (obj, UCL_EMIT_CONFIG,
269298166Sbapt					func, comments);
270268831Sbapt		}
271298166Sbapt
272298166Sbapt		ucl_object_emit_funcs_free (func);
273262395Sbapt	}
274298166Sbapt
275298166Sbapt	if (!use_fd) {
276298166Sbapt		fprintf (out, "\n");
277298166Sbapt		fclose (out);
278268831Sbapt	}
279262395Sbapt	else {
280298166Sbapt		write (fd_out, "\n", 1);
281298166Sbapt		close (fd_out);
282262395Sbapt	}
283262395Sbapt
284262395Sbapt	ucl_object_unref (obj);
285262395Sbapt
286262395Sbaptend:
287262395Sbapt	if (parser2 != NULL) {
288262395Sbapt		ucl_parser_free (parser2);
289262395Sbapt	}
290298166Sbapt	if (comments) {
291298166Sbapt		ucl_object_unref (comments);
292298166Sbapt	}
293290071Sbapt	if (inbuf != NULL) {
294290071Sbapt		free (inbuf);
295262395Sbapt	}
296262395Sbapt
297262395Sbapt	return ret;
298262395Sbapt}
299