summaryrefslogtreecommitdiff
path: root/json_visit.c
blob: fb16fa6fa604e023851735517698138a5b9d4c70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * 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
}