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 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