Implement JSON parsing and serialization.
[cascardo/ovs.git] / tests / test-json.c
1 /*
2  * Copyright (c) 2009 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "json.h"
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <getopt.h>
24 #include <stdio.h>
25
26 #include "util.h"
27
28 /* --pretty: If set, the JSON output is pretty-printed, instead of printed as
29  * compactly as possible.  */
30 static int pretty = 0;
31
32 /* --multiple: If set, the input is a sequence of JSON objects or arrays,
33  * instead of exactly one object or array. */
34 static int multiple = 0;
35
36 static bool
37 print_and_free_json(struct json *json)
38 {
39     bool ok;
40     if (json->type == JSON_STRING) {
41         printf("error: %s\n", json->u.string);
42         ok = false;
43     } else {
44         char *s = json_to_string(json, JSSF_SORT | (pretty ? JSSF_PRETTY : 0));
45         puts(s);
46         free(s);
47         ok = true;
48     }
49     json_destroy(json);
50     return ok;
51 }
52
53 static bool
54 refill(FILE *file, void *buffer, size_t buffer_size, size_t *n, size_t *used)
55 {
56     *used = 0;
57     if (feof(file)) {
58         *n = 0;
59         return false;
60     } else {
61         *n = fread(buffer, 1, buffer_size, file);
62         if (ferror(file)) {
63             ovs_fatal(errno, "Error reading input file");
64         }
65         return *n > 0;
66     }
67 }
68
69 static bool
70 parse_multiple(const char *input_file)
71 {
72     struct json_parser *parser;
73     char buffer[BUFSIZ];
74     size_t n, used;
75     FILE *file;
76     bool ok;
77
78     file = fopen(input_file, "r");
79     if (!file) {
80         ovs_fatal(errno, "Cannot open \"%s\"", input_file);
81     }
82
83     parser = NULL;
84     n = used = 0;
85     ok = true;
86     while (used < n || refill(file, buffer, sizeof buffer, &n, &used)) {
87         if (!parser && isspace((unsigned char) buffer[used])) {
88             /* Skip white space. */
89             used++;
90         } else {
91             if (!parser) {
92                 parser = json_parser_create(0);
93             }
94
95             used = n - json_parser_feed(parser, &buffer[used], n - used);
96             if (used < n) {
97                 if (!print_and_free_json(json_parser_finish(parser))) {
98                     ok = false;
99                 }
100                 parser = NULL;
101             }
102         }
103     }
104     if (parser) {
105         if (!print_and_free_json(json_parser_finish(parser))) {
106             ok = false;
107         }
108     }
109     return ok;
110 }
111
112 int
113 main(int argc, char *argv[])
114 {
115     const char *input_file;
116     bool ok;
117
118     set_program_name(argv[0]);
119
120     for (;;) {
121         static const struct option options[] = {
122             {"pretty", no_argument, &pretty, 1},
123             {"multiple", no_argument, &multiple, 1},
124         };
125         int option_index = 0;
126         int c = getopt_long (argc, argv, "", options, &option_index);
127
128         if (c == -1) {
129             break;
130         }
131         switch (c) {
132         case 0:
133             break;
134
135         case '?':
136             exit(1);
137
138         default:
139             abort();
140         }
141     }
142
143     if (argc - optind != 1) {
144         ovs_fatal(0, "usage: %s [--pretty] [--multiple] INPUT.json",
145                   program_name);
146     }
147
148     input_file = argv[optind];
149     if (!strcmp(input_file, "-")) {
150         input_file = "/dev/stdin";
151     }
152
153     if (multiple) {
154         ok = parse_multiple(input_file);
155     } else {
156         ok = print_and_free_json(json_from_file(input_file));
157     }
158
159     return !ok;
160 }