Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add RT setf fixes #67

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions frozen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1163,24 +1163,46 @@ static void json_vsetf_cb(void *userdata, const char *name, size_t name_len,
const char *path, const struct json_token *t) {
struct json_setf_data *data = (struct json_setf_data *) userdata;
int off, len = get_matched_prefix_len(path, data->json_path);
int matched = 0;
if (t->ptr == NULL) return;
off = t->ptr - data->base;
if (len > data->matched) data->matched = len;
// only check matched later on if deliminator or end are found
if (len > data->matched &&
(data->json_path[len] == '.' || data->json_path[len] == '\0')) {
matched = len;
}

/*
* If there is no exact path match, set the mutation position to tbe end
* If there is no exact path match, set the mutation position to be end
* of the object or array
*/
if (len < data->matched && data->pos == 0 &&
(t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END)) {
data->pos = data->end = data->prev;
if (matched > data->matched && data->pos == 0 &&
(t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END))
{
// only save off matched value if it is a new and larger match
data->matched = matched;
// account for a the previous item being a string
if (data->base[data->prev] == '"') {
data->pos = data->end = data->prev + 1;
}
else {
data->pos = data->end = data->prev;
}
}

/* Exact path match. Set mutation position to the value of this token */
if (strcmp(path, data->json_path) == 0 && t->type != JSON_TYPE_OBJECT_START &&
t->type != JSON_TYPE_ARRAY_START) {
data->pos = off;
data->end = off + t->len;
// need to set pos and end differently to account for '"' around string
if (t->type == JSON_TYPE_TRUE || t->type == JSON_TYPE_FALSE || t->type == JSON_TYPE_NUMBER) {
data->pos = off;
data->end = off + t->len + 1;
}
else {
data->pos = off - 1;
data->end = off + t->len + 2;
}
data->matched = matched;
}

/*
Expand Down Expand Up @@ -1223,14 +1245,30 @@ int json_vsetf(const char *s, int len, struct json_out *out,
json_printf(out, "%.*s", len - data.end, s + data.end);
} else {
/* Modification codepath */
int n, off = data.matched, depth = 0;
int n, off = data.matched+1, depth = 0;
bool empty_base = false;

// if a partial or exact match isn't found, adjust a few items
if (data.matched == 0 && data.pos == 0) {
data.pos = data.prev - 1;
data.end--;

// a completely empty base requres additional correction
if (data.base[0] == '{' && data.base[1] == '}') {
empty_base = true;
data.pos = 1;
data.prev = 1;
data.end = 1;
}
}

/* Print the unchanged beginning */
json_printf(out, "%.*s", data.pos, s);

/* Add missing keys */
while ((n = strcspn(&json_path[off], ".[")) > 0) {
if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0) {
// don't add a comma if it is a completely empty base
if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0 && !empty_base) {
json_printf(out, ",");
}
if (off > 0 && json_path[off - 1] != '.') break;
Expand Down Expand Up @@ -1468,4 +1506,4 @@ char *json_asprintf(const char *fmt, ...) {
result = json_vasprintf(fmt, ap);
va_end(ap);
return result;
}
}