/* * 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 #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 }