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