rtnetlink: Fix typo in comments referencing rtnetlink_notifier_register()
[openvswitch] / lib / json.c
index dfd6b84531dde279f9a23c3d0e7fe2326f689513..3acaa1964d3d5b2fe66291819dc423bb36d0a210 100644 (file)
@@ -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;
     }
 }