diff options
| -rw-r--r-- | doc/reference/json-glib-sections.txt | 1 | ||||
| -rw-r--r-- | json-glib/json-parser.c | 80 | ||||
| -rw-r--r-- | json-glib/json-parser.h | 5 | ||||
| -rw-r--r-- | tests/test-02.c | 5 |
4 files changed, 89 insertions, 2 deletions
diff --git a/doc/reference/json-glib-sections.txt b/doc/reference/json-glib-sections.txt index 46d78ae..e781b45 100644 --- a/doc/reference/json-glib-sections.txt +++ b/doc/reference/json-glib-sections.txt @@ -99,6 +99,7 @@ json_parser_get_root <SUBSECTION> json_parser_get_current_line json_parser_get_current_pos +json_parser_has_assignment <SUBSECTION Standard> JSON_TYPE_PARSER diff --git a/json-glib/json-parser.c b/json-glib/json-parser.c index 4b89db1..5df7999 100644 --- a/json-glib/json-parser.c +++ b/json-glib/json-parser.c @@ -51,6 +51,9 @@ struct _JsonParserPrivate GScanner *scanner; GError *last_error; + + guint has_assignment : 1; + gchar *variable_name; }; static const GScannerConfig json_scanner_config = @@ -95,7 +98,8 @@ static const GScannerConfig json_scanner_config = static const gchar symbol_names[] = "true\0" "false\0" - "null\0"; + "null\0" + "var\0"; static const struct { @@ -104,7 +108,8 @@ static const struct } symbols[] = { { 0, JSON_TOKEN_TRUE }, { 5, JSON_TOKEN_FALSE }, - { 11, JSON_TOKEN_NULL } + { 11, JSON_TOKEN_NULL }, + { 16, JSON_TOKEN_VAR } }; static const guint n_symbols = G_N_ELEMENTS (symbols); @@ -152,6 +157,8 @@ json_parser_dispose (GObject *gobject) priv->last_error = NULL; } + g_free (priv->variable_name); + G_OBJECT_CLASS (json_parser_parent_class)->dispose (gobject); } @@ -326,6 +333,9 @@ json_parser_init (JsonParser *parser) priv->root = NULL; priv->current_node = NULL; + + priv->has_assignment = FALSE; + priv->variable_name = NULL; } static guint @@ -735,6 +745,38 @@ json_parse_statement (JsonParser *parser, priv->root = priv->current_node = json_node_new (JSON_NODE_ARRAY); return json_parse_array (parser, scanner, FALSE); + /* some web APIs are not only passing the data structures: they are + * also passing an assigment, which makes parsing horribly complicated + * only because web developers are lazy, and writing "var foo = " is + * evidently too much to request from them. + */ + case JSON_TOKEN_VAR: + { + guint next_token; + gchar *name; + + /* swallow the 'var' token... */ + token = g_scanner_get_next_token (scanner); + + /* ... swallow the variable name... */ + next_token = g_scanner_get_next_token (scanner); + if (next_token != G_TOKEN_IDENTIFIER) + return G_TOKEN_IDENTIFIER; + + name = g_strdup (scanner->value.v_identifier); + + /* ... and finally swallow the '=' */ + next_token = g_scanner_get_next_token (scanner); + if (next_token != '=') + return '='; + + priv->has_assignment = TRUE; + priv->variable_name = name; + + return json_parse_statement (parser, scanner); + } + break; + case JSON_TOKEN_NULL: priv->root = priv->current_node = json_node_new (JSON_NODE_NULL); return G_TOKEN_NONE; @@ -1074,3 +1116,37 @@ json_parser_get_current_pos (JsonParser *parser) return 0; } + +/** + * json_parser_has_assignment: + * @parser: a #JsonParser + * @variable_name: return location for the variable name, or %NULL + * + * A JSON data stream might sometimes contain an assignment, even though + * it would technically constitute a violation of the RFC. #JsonParser + * will ignore the left hand identifier and parse the right hand value + * of the assignment. It will record, though, the existence of the + * assignment in the data stream and the variable name used. + * + * Return value: %TRUE if there was an assignment, %FALSE otherwise. If + * @variable_name is not %NULL it will be set to the name of the variable + * used in the assignment. The string is owned by #JsonParser and should + * never be modified or freed. + * + * Since: 0.4 + */ +gboolean +json_parser_has_assignment (JsonParser *parser, + gchar **variable_name) +{ + JsonParserPrivate *priv; + + g_return_val_if_fail (JSON_IS_PARSER (parser), FALSE); + + priv = parser->priv; + + if (priv->has_assignment && variable_name) + *variable_name = priv->variable_name; + + return priv->has_assignment; +} diff --git a/json-glib/json-parser.h b/json-glib/json-parser.h index 71a17cb..37324a9 100644 --- a/json-glib/json-parser.h +++ b/json-glib/json-parser.h @@ -53,9 +53,12 @@ typedef enum { typedef enum { JSON_TOKEN_INVALID = G_TOKEN_LAST, + JSON_TOKEN_TRUE, JSON_TOKEN_FALSE, JSON_TOKEN_NULL, + JSON_TOKEN_VAR, + JSON_TOKEN_LAST } JsonTokenType; @@ -141,6 +144,8 @@ JsonNode * json_parser_get_root (JsonParser *parser); guint json_parser_get_current_line (JsonParser *parser); guint json_parser_get_current_pos (JsonParser *parser); +gboolean json_parser_has_assignment (JsonParser *parser, + gchar **variable_name); G_END_DECLS diff --git a/tests/test-02.c b/tests/test-02.c index b307a7c..b5fb7a8 100644 --- a/tests/test-02.c +++ b/tests/test-02.c @@ -13,6 +13,7 @@ static const gchar *test_arrays[] = { "[ [ false, true, 42 ], [ true, false, 3.14 ], \"test\" ]", "[ true, { } ]", "[ false, { \"test\" : 42 } ]", + "var test = [ false, false, true ]", }; static guint n_test_arrays = G_N_ELEMENTS (test_arrays); @@ -190,6 +191,7 @@ main (int argc, char *argv[]) GError *error = NULL; JsonNode *node; JsonArray *array; + gchar *var_name; if (!json_parser_load_from_data (parser, test_arrays[i], -1, &error)) { @@ -210,6 +212,9 @@ main (int argc, char *argv[]) g_assert (array != NULL); g_print ("*** Test %d: '%s' ***\n", i, test_arrays[i]); + if (json_parser_has_assignment (parser, &var_name)) + g_print ("*** Test %d: assigns '%s'\n", i, var_name); + print_array (1, array); } |
