X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fjson.c;h=3acaa1964d3d5b2fe66291819dc423bb36d0a210;hb=56244b81016f4d60082976845f296f98111d16a3;hp=dfd6b84531dde279f9a23c3d0e7fe2326f689513;hpb=f38b84ea2b6b61d309c604faedd41ab3b0fcf16b;p=openvswitch diff --git a/lib/json.c b/lib/json.c index dfd6b845..3acaa196 100644 --- a/lib/json.c +++ b/lib/json.c @@ -99,6 +99,9 @@ struct json_parser { /* Lexical analysis. */ enum json_lex_state lex_state; struct ds buffer; /* Buffer for accumulating token text. */ + int line_number; + int column_number; + int byte_number; /* Parsing. */ enum json_parse_state parse_state; @@ -219,6 +222,14 @@ json_array_create(struct json **elements, size_t n) return json; } +struct json * +json_array_create_1(struct json *elem0) +{ + struct json **elems = xmalloc(sizeof *elems); + elems[0] = elem0; + return json_array_create(elems, 1); +} + struct json * json_array_create_2(struct json *elem0, struct json *elem1) { @@ -500,14 +511,15 @@ json_hash(const struct json *json, size_t basis) static bool json_equal_object(const struct shash *a, const struct shash *b) { - struct shash_node *node; + struct shash_node *a_node; if (shash_count(a) != shash_count(b)) { return false; } - SHASH_FOR_EACH (node, a) { - if (!shash_find(b, node->name)) { + SHASH_FOR_EACH (a_node, a) { + struct shash_node *b_node = shash_find(b, a_node->name); + if (!b_node || !json_equal(a_node->data, b_node->data)) { return false; } } @@ -594,6 +606,7 @@ json_lex_number(struct json_parser *p) { const char *cp = ds_cstr(&p->buffer); unsigned long long int significand = 0; + struct json_token token; int sig_digits = 0; bool imprecise = false; bool negative = false; @@ -718,7 +731,6 @@ json_lex_number(struct json_parser *p) && significand <= (negative ? (unsigned long long int) LLONG_MAX + 1 : LLONG_MAX)) { - struct json_token token; token.type = T_INTEGER; token.u.integer = negative ? -significand : significand; json_parser_input(p, &token); @@ -726,19 +738,16 @@ json_lex_number(struct json_parser *p) } } - if (pow10 + sig_digits <= DBL_MAX_10_EXP) { - struct json_token token; - token.type = T_REAL; - token.u.real = significand * pow(10.0, pow10); - if (token.u.real <= DBL_MAX) { - if (negative && token.u.real) { - token.u.real = -token.u.real; - } - json_parser_input(p, &token); - return; - } + token.type = T_REAL; + if (!str_to_double(ds_cstr(&p->buffer), &token.u.real)) { + json_error(p, "number outside valid range"); + return; + } + /* Suppress negative zero. */ + if (token.u.real == 0) { + token.u.real = 0; } - json_error(p, "number outside valid range"); + json_parser_input(p, &token); } static bool @@ -868,10 +877,18 @@ exit: } static bool -json_lex_input(struct json_parser *p, int c) +json_lex_input(struct json_parser *p, unsigned char c) { struct json_token token; + p->byte_number++; + if (c == '\n') { + p->column_number = 0; + p->line_number++; + } else { + p->column_number++; + } + switch (p->lex_state) { case JSON_LEX_START: switch (c) { @@ -985,18 +1002,34 @@ json_from_string(const char *string) struct json * json_from_file(const char *file_name) { - struct json_parser *p; struct json *json; FILE *stream; - /* Open file. */ stream = fopen(file_name, "r"); if (!stream) { return json_string_create_nocopy( xasprintf("error opening \"%s\": %s", file_name, strerror(errno))); } + json = json_from_stream(stream); + fclose(stream); + + return json; +} + +/* Parses the contents of 'stream' as a JSON object or array, and returns a + * newly allocated 'struct json'. The caller must free the returned structure + * with json_destroy() when it is no longer needed. + * + * The file must be encoded in UTF-8. + * + * See json_from_string() for return value semantics. + */ +struct json * +json_from_stream(FILE *stream) +{ + struct json_parser *p; + struct json *json; - /* Read and parse file. */ p = json_parser_create(JSPF_TRAILER); for (;;) { char buffer[BUFSIZ]; @@ -1009,13 +1042,11 @@ json_from_file(const char *file_name) } json = json_parser_finish(p); - /* Close file and check for I/O errors. */ if (ferror(stream)) { json_destroy(json); json = json_string_create_nocopy( - xasprintf("error reading \"%s\": %s", file_name, strerror(errno))); + xasprintf("error reading JSON stream: %s", strerror(errno))); } - fclose(stream); return json; } @@ -1339,12 +1370,18 @@ static void json_error(struct json_parser *p, const char *format, ...) { if (!p->error) { + struct ds msg; va_list args; + ds_init(&msg); + ds_put_format(&msg, "line %d, column %d, byte %d: ", + p->line_number, p->column_number, p->byte_number); va_start(args, format); - p->error = xvasprintf(format, args); + ds_put_format_valist(&msg, format, args); va_end(args); + p->error = ds_steal_cstr(&msg); + p->done = true; } }