2 * Copyright (c) 2012 Rogerz Zhang <rogerz.zhang@gmail.com>
4 * Jansson is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
7 * source here https://github.com/rogerz/jansson/blob/json_path/src/path.c
14 #include "jansson_path.h"
16 ////// memory.c private functions
18 /* C89 allows these to be macros */
22 /* memory function pointers */
23 static json_malloc_t do_malloc
= malloc
;
24 static json_free_t do_free
= free
;
26 static void *jsonp_malloc(size_t size
) {
30 return (*do_malloc
)(size
);
33 static void jsonp_free(void *ptr
) {
40 static char *jsonp_strndup(const char *str
, size_t len
) {
41 char *new_str
= jsonp_malloc(len
+ 1);
45 memcpy(new_str
, str
, len
);
50 static char *jsonp_strdup(const char *str
) {
51 return jsonp_strndup(str
, strlen(str
));
54 ////// error.c private functions
56 static void jsonp_error_set_source(json_error_t
*error
, const char *source
) {
59 if (!error
|| !source
)
62 length
= strlen(source
);
63 if (length
< JSON_ERROR_SOURCE_LENGTH
) {
64 strncpy(error
->source
, source
, JSON_ERROR_SOURCE_LENGTH
- 1);
66 size_t extra
= length
- JSON_ERROR_SOURCE_LENGTH
+ 4;
67 memcpy(error
->source
, "...", 3);
68 strncpy(error
->source
+ 3, source
+ extra
, length
- extra
+ 1);
72 static void jsonp_error_init(json_error_t
*error
, const char *source
) {
74 error
->text
[0] = '\0';
79 jsonp_error_set_source(error
, source
);
81 error
->source
[0] = '\0';
85 static void jsonp_error_vset(json_error_t
*error
, int line
, int column
,
86 size_t position
, enum json_error_code code
,
87 const char *msg
, va_list ap
) {
91 if (error
->text
[0] != '\0') {
92 /* error already set */
97 error
->column
= column
;
98 error
->position
= (int)position
;
100 vsnprintf(error
->text
, JSON_ERROR_TEXT_LENGTH
- 1, msg
, ap
);
101 error
->text
[JSON_ERROR_TEXT_LENGTH
- 2] = '\0';
102 error
->text
[JSON_ERROR_TEXT_LENGTH
- 1] = code
;
105 static void jsonp_error_set(json_error_t
*error
, int line
, int column
,
106 size_t position
, enum json_error_code code
,
107 const char *msg
, ...) {
110 jsonp_error_vset(error
, line
, column
, position
, code
, msg
, ap
);
115 // original path.c from jansson fork
117 json_t
*json_path_get(const json_t
*json
, const char *path
) {
118 static const char root_chr
= '$', array_open
= '[';
119 static const char *path_delims
= ".[", *array_close
= "]";
120 const json_t
*cursor
;
121 char *token
, *buf
, *peek
, *endptr
, delim
= '\0';
124 if (!json
|| !path
|| path
[0] != root_chr
)
127 buf
= jsonp_strdup(path
);
132 expect
= path_delims
;
134 while (peek
&& *peek
&& cursor
) {
135 char *last_peek
= peek
;
136 peek
= strpbrk(peek
, expect
);
138 if (!token
&& peek
!= last_peek
)
142 } else if (expect
!= path_delims
|| !token
) {
146 if (expect
== path_delims
) {
148 cursor
= json_object_get(cursor
, token
);
150 expect
= (delim
== array_open
? array_close
: path_delims
);
152 } else if (expect
== array_close
) {
153 size_t index
= strtol(token
, &endptr
, 0);
156 cursor
= json_array_get(cursor
, index
);
158 expect
= path_delims
;
165 return (json_t
*)cursor
;
171 int json_path_set_new(json_t
*json
, const char *path
, json_t
*value
, size_t flags
, json_error_t
*error
) {
172 static const char root_chr
= '$', array_open
= '[', object_delim
= '.';
173 static const char *const path_delims
= ".[", *array_close
= "]";
175 json_t
*cursor
, *parent
= NULL
;
176 char *token
, *buf
= NULL
, *peek
, delim
= '\0';
178 int index_saved
= -1;
180 jsonp_error_init(error
, "<path>");
182 if (!json
|| !path
|| flags
|| !value
) {
183 jsonp_error_set(error
, -1, -1, 0, json_error_invalid_argument
, "invalid argument");
186 buf
= jsonp_strdup(path
);
189 if (buf
[0] != root_chr
) {
190 jsonp_error_set(error
, -1, -1, 0, json_error_invalid_format
, "path should start with $");
197 expect
= path_delims
;
199 while (peek
&& *peek
&& cursor
) {
200 char *last_peek
= peek
;
201 peek
= strpbrk(last_peek
, expect
);
204 if (!token
&& peek
!= last_peek
) {
205 jsonp_error_set(error
, -1, -1, last_peek
- buf
, json_error_invalid_format
, "unexpected trailing chars");
210 } else { // end of path
211 if (expect
== path_delims
) {
214 jsonp_error_set(error
, -1, -1, last_peek
- buf
, json_error_invalid_format
, "missing ']'?");
219 if (expect
== path_delims
) {
221 if (token
[0] == '\0') {
222 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_invalid_format
, "empty token");
227 cursor
= json_object_get(parent
, token
);
230 if (!json_is_object(parent
)) {
231 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_item_not_found
, "object expected");
234 if (delim
== object_delim
) {
235 cursor
= json_object();
236 json_object_set_new(parent
, token
, cursor
);
238 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_item_not_found
, "new array is not allowed");
243 expect
= (delim
== array_open
? array_close
: path_delims
);
245 } else if (expect
== array_close
) {
250 if (!json_is_array(parent
)) {
251 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_item_not_found
, "array expected");
254 index
= strtol(token
, &endptr
, 0);
256 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_item_not_found
, "invalid array index");
259 cursor
= json_array_get(parent
, index
);
261 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_item_not_found
, "array index out of bound");
266 expect
= path_delims
;
269 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_unknown
, "unexpected error in path move");
275 if (json_is_object(cursor
)) {
276 json_object_set(cursor
, token
, value
);
278 jsonp_error_set(error
, -1, -1, peek
- buf
, json_error_item_not_found
, "object expected");
281 cursor
= json_object_get(cursor
, token
);
282 } else if (index_saved
!= -1 && json_is_array(parent
)) {
283 json_array_set(parent
, index_saved
, value
);
284 cursor
= json_array_get(parent
, index_saved
);
286 jsonp_error_set(error
, -1, -1, 0, json_error_item_not_found
, "invalid path");