json: New function json_serialized_length().
[sliver-openvswitch.git] / tests / test-json.c
1 /*
2  * Copyright (c) 2009, 2010, 2013 Nicira, Inc.
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         ovs_assert(pretty || json_serialized_length(json) == strlen(s));
46         puts(s);
47         free(s);
48         ok = true;
49     }
50     json_destroy(json);
51     return ok;
52 }
53
54 static bool
55 refill(FILE *file, void *buffer, size_t buffer_size, size_t *n, size_t *used)
56 {
57     *used = 0;
58     if (feof(file)) {
59         *n = 0;
60         return false;
61     } else {
62         *n = fread(buffer, 1, buffer_size, file);
63         if (ferror(file)) {
64             ovs_fatal(errno, "Error reading input file");
65         }
66         return *n > 0;
67     }
68 }
69
70 static bool
71 parse_multiple(FILE *stream)
72 {
73     struct json_parser *parser;
74     char buffer[BUFSIZ];
75     size_t n, used;
76     bool ok;
77
78     parser = NULL;
79     n = used = 0;
80     ok = true;
81     while (used < n || refill(stream, buffer, sizeof buffer, &n, &used)) {
82         if (!parser && isspace((unsigned char) buffer[used])) {
83             /* Skip white space. */
84             used++;
85         } else {
86             if (!parser) {
87                 parser = json_parser_create(0);
88             }
89
90             used += json_parser_feed(parser, &buffer[used], n - used);
91             if (used < n) {
92                 if (!print_and_free_json(json_parser_finish(parser))) {
93                     ok = false;
94                 }
95                 parser = NULL;
96             }
97         }
98     }
99     if (parser) {
100         if (!print_and_free_json(json_parser_finish(parser))) {
101             ok = false;
102         }
103     }
104     return ok;
105 }
106
107 int
108 main(int argc, char *argv[])
109 {
110     const char *input_file;
111     FILE *stream;
112     bool ok;
113
114     set_program_name(argv[0]);
115
116     for (;;) {
117         static const struct option options[] = {
118             {"pretty", no_argument, &pretty, 1},
119             {"multiple", no_argument, &multiple, 1},
120         };
121         int option_index = 0;
122         int c = getopt_long (argc, argv, "", options, &option_index);
123
124         if (c == -1) {
125             break;
126         }
127         switch (c) {
128         case 0:
129             break;
130
131         case '?':
132             exit(1);
133
134         default:
135             abort();
136         }
137     }
138
139     if (argc - optind != 1) {
140         ovs_fatal(0, "usage: %s [--pretty] [--multiple] INPUT.json",
141                   program_name);
142     }
143
144     input_file = argv[optind];
145     stream = !strcmp(input_file, "-") ? stdin : fopen(input_file, "r");
146     if (!stream) {
147         ovs_fatal(errno, "Cannot open \"%s\"", input_file);
148     }
149
150     if (multiple) {
151         ok = parse_multiple(stream);
152     } else {
153         ok = print_and_free_json(json_from_stream(stream));
154     }
155
156     fclose(stream);
157
158     return !ok;
159 }