| /* |
| * Copyright (c) 2016 Eric Haszlakiewicz |
| * |
| * This is free software; you can redistribute it and/or modify |
| * it under the terms of the MIT license. See COPYING for details. |
| */ |
| |
| #include <stdio.h> |
| |
| #include "config.h" |
| #include "json_inttypes.h" |
| #include "json_object.h" |
| #include "json_visit.h" |
| #include "linkhash.h" |
| |
| static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *jso_key, |
| size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg); |
| |
| int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *userfunc, void *userarg) |
| { |
| int ret = _json_c_visit(jso, NULL, NULL, NULL, userfunc, userarg); |
| switch (ret) |
| { |
| case JSON_C_VISIT_RETURN_CONTINUE: |
| case JSON_C_VISIT_RETURN_SKIP: |
| case JSON_C_VISIT_RETURN_POP: |
| case JSON_C_VISIT_RETURN_STOP: return 0; |
| default: return JSON_C_VISIT_RETURN_ERROR; |
| } |
| } |
| static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *jso_key, |
| size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg) |
| { |
| int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg); |
| switch (userret) |
| { |
| case JSON_C_VISIT_RETURN_CONTINUE: break; |
| case JSON_C_VISIT_RETURN_SKIP: |
| case JSON_C_VISIT_RETURN_POP: |
| case JSON_C_VISIT_RETURN_STOP: |
| case JSON_C_VISIT_RETURN_ERROR: return userret; |
| default: |
| fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", |
| userret); |
| return JSON_C_VISIT_RETURN_ERROR; |
| } |
| |
| switch (json_object_get_type(jso)) |
| { |
| case json_type_null: |
| case json_type_boolean: |
| case json_type_double: |
| case json_type_int: |
| case json_type_string: |
| // we already called userfunc above, move on to the next object |
| return JSON_C_VISIT_RETURN_CONTINUE; |
| |
| case json_type_object: |
| { |
| json_object_object_foreach(jso, key, child) |
| { |
| userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg); |
| if (userret == JSON_C_VISIT_RETURN_POP) |
| break; |
| if (userret == JSON_C_VISIT_RETURN_STOP || |
| userret == JSON_C_VISIT_RETURN_ERROR) |
| return userret; |
| if (userret != JSON_C_VISIT_RETURN_CONTINUE && |
| userret != JSON_C_VISIT_RETURN_SKIP) |
| { |
| fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", |
| userret); |
| return JSON_C_VISIT_RETURN_ERROR; |
| } |
| } |
| break; |
| } |
| case json_type_array: |
| { |
| size_t array_len = json_object_array_length(jso); |
| size_t ii; |
| for (ii = 0; ii < array_len; ii++) |
| { |
| json_object *child = json_object_array_get_idx(jso, ii); |
| userret = _json_c_visit(child, jso, NULL, &ii, userfunc, userarg); |
| if (userret == JSON_C_VISIT_RETURN_POP) |
| break; |
| if (userret == JSON_C_VISIT_RETURN_STOP || |
| userret == JSON_C_VISIT_RETURN_ERROR) |
| return userret; |
| if (userret != JSON_C_VISIT_RETURN_CONTINUE && |
| userret != JSON_C_VISIT_RETURN_SKIP) |
| { |
| fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", |
| userret); |
| return JSON_C_VISIT_RETURN_ERROR; |
| } |
| } |
| break; |
| } |
| default: |
| fprintf(stderr, "INTERNAL ERROR: _json_c_visit found object of unknown type: %d\n", |
| json_object_get_type(jso)); |
| return JSON_C_VISIT_RETURN_ERROR; |
| } |
| |
| // Call userfunc for the second type on container types, after all |
| // members of the container have been visited. |
| // Non-container types will have already returned before this point. |
| |
| userret = userfunc(jso, JSON_C_VISIT_SECOND, parent_jso, jso_key, jso_index, userarg); |
| switch (userret) |
| { |
| case JSON_C_VISIT_RETURN_SKIP: |
| case JSON_C_VISIT_RETURN_POP: |
| // These are not really sensible during JSON_C_VISIT_SECOND, |
| // but map them to JSON_C_VISIT_CONTINUE anyway. |
| // FALLTHROUGH |
| case JSON_C_VISIT_RETURN_CONTINUE: return JSON_C_VISIT_RETURN_CONTINUE; |
| case JSON_C_VISIT_RETURN_STOP: |
| case JSON_C_VISIT_RETURN_ERROR: return userret; |
| default: |
| fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", |
| userret); |
| return JSON_C_VISIT_RETURN_ERROR; |
| } |
| // NOTREACHED |
| } |