]>
Commit | Line | Data |
---|---|---|
d18e52e3 | 1 | /* Copyright (c) 2009, 2011, 2013, 2015 Nicira, Inc. |
f85f8ebb BP |
2 | * |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at: | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | */ | |
15 | ||
16 | #include <config.h> | |
17 | ||
18 | #include "ovsdb-parser.h" | |
19 | ||
20 | #include <ctype.h> | |
21 | #include <stdarg.h> | |
22 | ||
23 | #include "ovsdb-error.h" | |
24 | ||
25 | void | |
26 | ovsdb_parser_init(struct ovsdb_parser *parser, const struct json *json, | |
27 | const char *name, ...) | |
28 | { | |
29 | va_list args; | |
30 | ||
31 | va_start(args, name); | |
32 | parser->name = xvasprintf(name, args); | |
33 | va_end(args); | |
34 | ||
53d04661 | 35 | sset_init(&parser->used); |
f85f8ebb BP |
36 | parser->error = NULL; |
37 | ||
38 | parser->json = (json && json->type == JSON_OBJECT ? json : NULL); | |
39 | if (!parser->json) { | |
40 | ovsdb_parser_raise_error(parser, "Object expected."); | |
41 | } | |
42 | } | |
43 | ||
b966380b BP |
44 | bool |
45 | ovsdb_parser_is_id(const char *string) | |
f85f8ebb BP |
46 | { |
47 | unsigned char c; | |
48 | ||
49 | c = *string; | |
50 | if (!isalpha(c) && c != '_') { | |
51 | return false; | |
52 | } | |
53 | ||
54 | for (;;) { | |
55 | c = *++string; | |
56 | if (c == '\0') { | |
57 | return true; | |
58 | } else if (!isalpha(c) && !isdigit(c) && c != '_') { | |
59 | return false; | |
60 | } | |
61 | } | |
62 | } | |
63 | ||
64 | const struct json * | |
65 | ovsdb_parser_member(struct ovsdb_parser *parser, const char *name, | |
66 | enum ovsdb_parser_types types) | |
67 | { | |
68 | struct json *value; | |
69 | ||
70 | if (!parser->json) { | |
71 | return NULL; | |
72 | } | |
73 | ||
74 | value = shash_find_data(json_object(parser->json), name); | |
75 | if (!value) { | |
76 | if (!(types & OP_OPTIONAL)) { | |
77 | ovsdb_parser_raise_error(parser, | |
78 | "Required '%s' member is missing.", name); | |
79 | } | |
80 | return NULL; | |
81 | } | |
82 | ||
a6d214f0 | 83 | if (((int) value->type >= 0 && value->type < JSON_N_TYPES |
4d0101a0 BP |
84 | && types & (1u << value->type)) |
85 | || (types & OP_ID && value->type == JSON_STRING | |
b966380b | 86 | && ovsdb_parser_is_id(value->u.string))) |
f85f8ebb | 87 | { |
53d04661 | 88 | sset_add(&parser->used, name); |
f85f8ebb BP |
89 | return value; |
90 | } else { | |
91 | ovsdb_parser_raise_error(parser, "Type mismatch for member '%s'.", | |
92 | name); | |
93 | return NULL; | |
94 | } | |
95 | } | |
96 | ||
97 | void | |
98 | ovsdb_parser_raise_error(struct ovsdb_parser *parser, const char *format, ...) | |
99 | { | |
100 | if (!parser->error) { | |
101 | struct ovsdb_error *error; | |
102 | va_list args; | |
103 | char *message; | |
104 | ||
105 | va_start(args, format); | |
106 | message = xvasprintf(format, args); | |
107 | va_end(args); | |
108 | ||
109 | error = ovsdb_syntax_error(parser->json, NULL, "Parsing %s failed: %s", | |
110 | parser->name, message); | |
111 | free(message); | |
112 | ||
113 | parser->error = error; | |
114 | } | |
115 | } | |
116 | ||
117 | struct ovsdb_error * | |
118 | ovsdb_parser_get_error(const struct ovsdb_parser *parser) | |
119 | { | |
120 | return parser->error ? ovsdb_error_clone(parser->error) : NULL; | |
121 | } | |
122 | ||
123 | bool | |
124 | ovsdb_parser_has_error(const struct ovsdb_parser *parser) | |
125 | { | |
126 | return parser->error != NULL; | |
127 | } | |
128 | ||
d18e52e3 BP |
129 | struct ovsdb_error * |
130 | ovsdb_parser_destroy(struct ovsdb_parser *parser) | |
131 | { | |
132 | free(parser->name); | |
133 | sset_destroy(&parser->used); | |
134 | ||
135 | return parser->error; | |
136 | } | |
137 | ||
f85f8ebb BP |
138 | struct ovsdb_error * |
139 | ovsdb_parser_finish(struct ovsdb_parser *parser) | |
140 | { | |
141 | if (!parser->error) { | |
142 | const struct shash *object = json_object(parser->json); | |
143 | size_t n_unused; | |
144 | ||
53d04661 | 145 | n_unused = shash_count(object) - sset_count(&parser->used); |
f85f8ebb BP |
146 | if (n_unused) { |
147 | struct shash_node *node; | |
148 | ||
149 | SHASH_FOR_EACH (node, object) { | |
53d04661 | 150 | if (!sset_contains(&parser->used, node->name)) { |
f85f8ebb BP |
151 | if (n_unused > 1) { |
152 | ovsdb_parser_raise_error( | |
153 | parser, | |
34582733 | 154 | "Member '%s' and %"PRIuSIZE" other member%s " |
f85f8ebb BP |
155 | "are present but not allowed here.", |
156 | node->name, n_unused - 1, n_unused > 2 ? "s" : ""); | |
157 | } else { | |
158 | ovsdb_parser_raise_error( | |
159 | parser, | |
160 | "Member '%s' is present but not allowed here.", | |
161 | node->name); | |
162 | } | |
163 | break; | |
164 | } | |
165 | } | |
166 | } | |
167 | } | |
168 | ||
d18e52e3 | 169 | return ovsdb_parser_destroy(parser); |
f85f8ebb | 170 | } |