1290067Sbapt/* Copyright (c) 2015, Cesanta Software 2290067Sbapt * 3290067Sbapt * Redistribution and use in source and binary forms, with or without 4290067Sbapt * modification, are permitted provided that the following conditions are met: 5290067Sbapt * * Redistributions of source code must retain the above copyright 6290067Sbapt * notice, this list of conditions and the following disclaimer. 7290067Sbapt * * Redistributions in binary form must reproduce the above copyright 8290067Sbapt * notice, this list of conditions and the following disclaimer in the 9290067Sbapt * documentation and/or other materials provided with the distribution. 10290067Sbapt * 11290067Sbapt * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY 12290067Sbapt * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 13290067Sbapt * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 14290067Sbapt * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY 15290067Sbapt * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 16290067Sbapt * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 17290067Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 18290067Sbapt * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 19290067Sbapt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 20290067Sbapt * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21290067Sbapt */ 22290067Sbapt 23290067Sbapt#include <stdio.h> 24290067Sbapt#include <getopt.h> 25290067Sbapt#include <stdlib.h> 26290067Sbapt 27290067Sbapt#include "ucl.h" 28290067Sbapt 29290067Sbaptstatic struct option opts[] = { 30290067Sbapt {"help", no_argument, NULL, 'h'}, 31290067Sbapt {"in", required_argument, NULL, 'i' }, 32290067Sbapt {"out", required_argument, NULL, 'o' }, 33290067Sbapt {"schema", required_argument, NULL, 's'}, 34290067Sbapt {"format", required_argument, NULL, 'f'}, 35290067Sbapt {0, 0, 0, 0} 36290067Sbapt}; 37290067Sbapt 38290067Sbaptvoid usage(const char *name, FILE *out) { 39290067Sbapt fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name); 40290067Sbapt fprintf(out, " [-s|--schema file] [-f|--format format]\n\n"); 41290067Sbapt fprintf(out, " --help - print this message and exit\n"); 42290067Sbapt fprintf(out, " --in - specify input filename " 43290067Sbapt "(default: standard input)\n"); 44290067Sbapt fprintf(out, " --out - specify output filename " 45290067Sbapt "(default: standard output)\n"); 46290067Sbapt fprintf(out, " --schema - specify schema file for validation\n"); 47290067Sbapt fprintf(out, " --format - output format. Options: ucl (default), " 48290067Sbapt "json, compact_json, yaml, msgpack\n"); 49290067Sbapt} 50290067Sbapt 51290067Sbaptint main(int argc, char **argv) { 52290067Sbapt char ch; 53290067Sbapt FILE *in = stdin, *out = stdout; 54290067Sbapt const char *schema = NULL; 55290067Sbapt unsigned char *buf = NULL; 56290067Sbapt size_t size = 0, r = 0; 57290067Sbapt struct ucl_parser *parser = NULL; 58290067Sbapt ucl_object_t *obj = NULL; 59290067Sbapt ucl_emitter_t emitter = UCL_EMIT_CONFIG; 60290067Sbapt 61290067Sbapt while((ch = getopt_long(argc, argv, "hi:o:s:f:", opts, NULL)) != -1) { 62290067Sbapt switch (ch) { 63290067Sbapt case 'i': 64290067Sbapt in = fopen(optarg, "r"); 65290067Sbapt if (in == NULL) { 66290067Sbapt perror("fopen on input file"); 67290067Sbapt exit(EXIT_FAILURE); 68290067Sbapt } 69290067Sbapt break; 70290067Sbapt case 'o': 71290067Sbapt out = fopen(optarg, "w"); 72290067Sbapt if (out == NULL) { 73290067Sbapt perror("fopen on output file"); 74290067Sbapt exit(EXIT_FAILURE); 75290067Sbapt } 76290067Sbapt break; 77290067Sbapt case 's': 78290067Sbapt schema = optarg; 79290067Sbapt break; 80290067Sbapt case 'f': 81290067Sbapt if (strcmp(optarg, "ucl") == 0) { 82290067Sbapt emitter = UCL_EMIT_CONFIG; 83290067Sbapt } else if (strcmp(optarg, "json") == 0) { 84290067Sbapt emitter = UCL_EMIT_JSON; 85290067Sbapt } else if (strcmp(optarg, "yaml") == 0) { 86290067Sbapt emitter = UCL_EMIT_YAML; 87290067Sbapt } else if (strcmp(optarg, "compact_json") == 0) { 88290067Sbapt emitter = UCL_EMIT_JSON_COMPACT; 89290067Sbapt } else if (strcmp(optarg, "msgpack") == 0) { 90290067Sbapt emitter = UCL_EMIT_MSGPACK; 91290067Sbapt } else { 92290067Sbapt fprintf(stderr, "Unknown output format: %s\n", optarg); 93290067Sbapt exit(EXIT_FAILURE); 94290067Sbapt } 95290067Sbapt break; 96290067Sbapt case 'h': 97290067Sbapt usage(argv[0], stdout); 98290067Sbapt exit(0); 99290067Sbapt default: 100290067Sbapt usage(argv[0], stderr); 101290067Sbapt exit(EXIT_FAILURE); 102290067Sbapt break; 103290067Sbapt } 104290067Sbapt } 105290067Sbapt 106290067Sbapt parser = ucl_parser_new(0); 107290067Sbapt buf = malloc(BUFSIZ); 108290067Sbapt size = BUFSIZ; 109290067Sbapt while(!feof(in) && !ferror(in)) { 110290067Sbapt if (r == size) { 111290067Sbapt buf = realloc(buf, size*2); 112290067Sbapt size *= 2; 113290067Sbapt if (buf == NULL) { 114290067Sbapt perror("realloc"); 115290067Sbapt exit(EXIT_FAILURE); 116290067Sbapt } 117290067Sbapt } 118290067Sbapt r += fread(buf + r, 1, size - r, in); 119290067Sbapt } 120290067Sbapt if (ferror(in)) { 121290067Sbapt fprintf(stderr, "Failed to read the input file.\n"); 122290067Sbapt exit(EXIT_FAILURE); 123290067Sbapt } 124290067Sbapt fclose(in); 125290067Sbapt if (!ucl_parser_add_chunk(parser, buf, r)) { 126290067Sbapt fprintf(stderr, "Failed to parse input file: %s\n", 127290067Sbapt ucl_parser_get_error(parser)); 128290067Sbapt exit(EXIT_FAILURE); 129290067Sbapt } 130290067Sbapt if ((obj = ucl_parser_get_object(parser)) == NULL) { 131290067Sbapt fprintf(stderr, "Failed to get root object: %s\n", 132290067Sbapt ucl_parser_get_error(parser)); 133290067Sbapt exit(EXIT_FAILURE); 134290067Sbapt } 135290067Sbapt if (schema != NULL) { 136290067Sbapt struct ucl_parser *schema_parser = ucl_parser_new(0); 137290067Sbapt ucl_object_t *schema_obj = NULL; 138290067Sbapt struct ucl_schema_error error; 139290067Sbapt 140290067Sbapt if (!ucl_parser_add_file(schema_parser, schema)) { 141290067Sbapt fprintf(stderr, "Failed to parse schema file: %s\n", 142290067Sbapt ucl_parser_get_error(schema_parser)); 143290067Sbapt exit(EXIT_FAILURE); 144290067Sbapt } 145290067Sbapt if ((schema_obj = ucl_parser_get_object(schema_parser)) == NULL) { 146290067Sbapt fprintf(stderr, "Failed to get root object: %s\n", 147290067Sbapt ucl_parser_get_error(schema_parser)); 148290067Sbapt exit(EXIT_FAILURE); 149290067Sbapt } 150290067Sbapt if (!ucl_object_validate(schema_obj, obj, &error)) { 151290067Sbapt fprintf(stderr, "Validation failed: %s\n", error.msg); 152290067Sbapt exit(EXIT_FAILURE); 153290067Sbapt } 154290067Sbapt } 155290067Sbapt 156290067Sbapt if (emitter != UCL_EMIT_MSGPACK) { 157290067Sbapt fprintf(out, "%s\n", ucl_object_emit(obj, emitter)); 158290067Sbapt } 159290067Sbapt else { 160290067Sbapt size_t len; 161290067Sbapt unsigned char *res; 162290067Sbapt 163290067Sbapt res = ucl_object_emit_len(obj, emitter, &len); 164290067Sbapt fwrite(res, 1, len, out); 165290067Sbapt } 166290067Sbapt 167290067Sbapt return 0; 168290067Sbapt} 169