xref: /freebsd/contrib/libucl/utils/ucl-tool.c (revision a0ee8cc636cd5c2374ec44ca71226564ea0bca95)
1 /* Copyright (c) 2015, Cesanta Software
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5  *       * Redistributions of source code must retain the above copyright
6  *         notice, this list of conditions and the following disclaimer.
7  *       * Redistributions in binary form must reproduce the above copyright
8  *         notice, this list of conditions and the following disclaimer in the
9  *         documentation and/or other materials provided with the distribution.
10  *
11  * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
12  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14  * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
15  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
17  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
18  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21  */
22 
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <stdlib.h>
26 
27 #include "ucl.h"
28 
29 static struct option opts[] = {
30     {"help", no_argument, NULL, 'h'},
31     {"in", required_argument, NULL, 'i' },
32     {"out", required_argument, NULL, 'o' },
33     {"schema", required_argument, NULL, 's'},
34     {"format", required_argument, NULL, 'f'},
35     {0, 0, 0, 0}
36 };
37 
38 void usage(const char *name, FILE *out) {
39   fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name);
40   fprintf(out, "    [-s|--schema file] [-f|--format format]\n\n");
41   fprintf(out, "  --help   - print this message and exit\n");
42   fprintf(out, "  --in     - specify input filename "
43           "(default: standard input)\n");
44   fprintf(out, "  --out    - specify output filename "
45           "(default: standard output)\n");
46   fprintf(out, "  --schema - specify schema file for validation\n");
47   fprintf(out, "  --format - output format. Options: ucl (default), "
48           "json, compact_json, yaml, msgpack\n");
49 }
50 
51 int main(int argc, char **argv) {
52   char ch;
53   FILE *in = stdin, *out = stdout;
54   const char *schema = NULL;
55   unsigned char *buf = NULL;
56   size_t size = 0, r = 0;
57   struct ucl_parser *parser = NULL;
58   ucl_object_t *obj = NULL;
59   ucl_emitter_t emitter = UCL_EMIT_CONFIG;
60 
61   while((ch = getopt_long(argc, argv, "hi:o:s:f:", opts, NULL)) != -1) {
62     switch (ch) {
63     case 'i':
64       in = fopen(optarg, "r");
65       if (in == NULL) {
66         perror("fopen on input file");
67         exit(EXIT_FAILURE);
68       }
69       break;
70     case 'o':
71       out = fopen(optarg, "w");
72       if (out == NULL) {
73         perror("fopen on output file");
74         exit(EXIT_FAILURE);
75       }
76       break;
77     case 's':
78       schema = optarg;
79       break;
80     case 'f':
81       if (strcmp(optarg, "ucl") == 0) {
82         emitter = UCL_EMIT_CONFIG;
83       } else if (strcmp(optarg, "json") == 0) {
84         emitter = UCL_EMIT_JSON;
85       } else if (strcmp(optarg, "yaml") == 0) {
86         emitter = UCL_EMIT_YAML;
87       } else if (strcmp(optarg, "compact_json") == 0) {
88         emitter = UCL_EMIT_JSON_COMPACT;
89       } else if (strcmp(optarg, "msgpack") == 0) {
90         emitter = UCL_EMIT_MSGPACK;
91       } else {
92         fprintf(stderr, "Unknown output format: %s\n", optarg);
93         exit(EXIT_FAILURE);
94       }
95       break;
96     case 'h':
97       usage(argv[0], stdout);
98       exit(0);
99     default:
100       usage(argv[0], stderr);
101       exit(EXIT_FAILURE);
102       break;
103     }
104   }
105 
106   parser = ucl_parser_new(0);
107   buf = malloc(BUFSIZ);
108   size = BUFSIZ;
109   while(!feof(in) && !ferror(in)) {
110     if (r == size) {
111       buf = realloc(buf, size*2);
112       size *= 2;
113       if (buf == NULL) {
114         perror("realloc");
115         exit(EXIT_FAILURE);
116       }
117     }
118     r += fread(buf + r, 1, size - r, in);
119   }
120   if (ferror(in)) {
121     fprintf(stderr, "Failed to read the input file.\n");
122     exit(EXIT_FAILURE);
123   }
124   fclose(in);
125   if (!ucl_parser_add_chunk(parser, buf, r)) {
126     fprintf(stderr, "Failed to parse input file: %s\n",
127             ucl_parser_get_error(parser));
128     exit(EXIT_FAILURE);
129   }
130   if ((obj = ucl_parser_get_object(parser)) == NULL) {
131     fprintf(stderr, "Failed to get root object: %s\n",
132             ucl_parser_get_error(parser));
133     exit(EXIT_FAILURE);
134   }
135   if (schema != NULL) {
136     struct ucl_parser *schema_parser = ucl_parser_new(0);
137     ucl_object_t *schema_obj = NULL;
138     struct ucl_schema_error error;
139 
140     if (!ucl_parser_add_file(schema_parser, schema)) {
141       fprintf(stderr, "Failed to parse schema file: %s\n",
142               ucl_parser_get_error(schema_parser));
143       exit(EXIT_FAILURE);
144     }
145     if ((schema_obj = ucl_parser_get_object(schema_parser)) == NULL) {
146       fprintf(stderr, "Failed to get root object: %s\n",
147               ucl_parser_get_error(schema_parser));
148       exit(EXIT_FAILURE);
149     }
150     if (!ucl_object_validate(schema_obj, obj, &error)) {
151       fprintf(stderr, "Validation failed: %s\n", error.msg);
152       exit(EXIT_FAILURE);
153     }
154   }
155 
156   if (emitter != UCL_EMIT_MSGPACK) {
157     fprintf(out, "%s\n", ucl_object_emit(obj, emitter));
158   }
159   else {
160     size_t len;
161     unsigned char *res;
162 
163     res = ucl_object_emit_len(obj, emitter, &len);
164     fwrite(res, 1, len, out);
165   }
166 
167   return 0;
168 }
169