|
Packit |
517ee8 |
#include <stdlib.h>
|
|
Packit |
517ee8 |
#include <stdbool.h>
|
|
Packit |
517ee8 |
#include <string.h>
|
|
Packit |
517ee8 |
#include <sys/queue.h>
|
|
Packit |
517ee8 |
#include <assert.h>
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#include <yaml.h>
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#include "yaml-path.h"
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#define YAML_PATH_MAX_SECTION_LEN 1024
|
|
Packit |
517ee8 |
#define YAML_PATH_MAX_SECTIONS 255
|
|
Packit |
517ee8 |
#define YAML_PATH_MAX_LEN YAML_PATH_MAX_SECTION_LEN * YAML_PATH_MAX_SECTIONS
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
typedef enum yaml_path_section_type {
|
|
Packit |
517ee8 |
YAML_PATH_SECTION_ROOT,
|
|
Packit |
517ee8 |
YAML_PATH_SECTION_ANCHOR,
|
|
Packit |
517ee8 |
YAML_PATH_SECTION_KEY,
|
|
Packit |
517ee8 |
YAML_PATH_SECTION_INDEX,
|
|
Packit |
517ee8 |
YAML_PATH_SECTION_SLICE,
|
|
Packit |
517ee8 |
} yaml_path_section_type_t;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
typedef struct yaml_path_section {
|
|
Packit |
517ee8 |
yaml_path_section_type_t type;
|
|
Packit |
517ee8 |
int level;
|
|
Packit |
517ee8 |
union {
|
|
Packit |
517ee8 |
const char *key;
|
|
Packit |
517ee8 |
const char *anchor;
|
|
Packit |
517ee8 |
int index;
|
|
Packit |
517ee8 |
struct {int start, end, stride;} slice;
|
|
Packit |
517ee8 |
} data;
|
|
Packit |
517ee8 |
TAILQ_ENTRY(yaml_path_section) entries;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
yaml_node_type_t node_type;
|
|
Packit |
517ee8 |
int counter;
|
|
Packit |
517ee8 |
bool valid;
|
|
Packit |
517ee8 |
bool next_valid;
|
|
Packit |
517ee8 |
} yaml_path_section_t;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
typedef TAILQ_HEAD(path_section_list, yaml_path_section) path_section_list_t;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
typedef struct yaml_path {
|
|
Packit |
517ee8 |
path_section_list_t sections_list;
|
|
Packit |
517ee8 |
size_t sections_count;
|
|
Packit |
517ee8 |
size_t sequence_level;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
size_t current_level;
|
|
Packit |
517ee8 |
size_t start_level;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
yaml_path_error_t error;
|
|
Packit |
517ee8 |
} yaml_path_t;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void
|
|
Packit |
517ee8 |
yaml_path_error_set (yaml_path_t *path, yaml_path_error_type_t error_type, const char *message, size_t pos)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
path->error.type = error_type;
|
|
Packit |
517ee8 |
path->error.message = message;
|
|
Packit |
517ee8 |
path->error.pos = pos;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void
|
|
Packit |
517ee8 |
yaml_path_sections_remove (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
while (!TAILQ_EMPTY(&path->sections_list)) {
|
|
Packit |
517ee8 |
yaml_path_section_t *el = TAILQ_FIRST(&path->sections_list);
|
|
Packit |
517ee8 |
TAILQ_REMOVE(&path->sections_list, el, entries);
|
|
Packit |
517ee8 |
path->sections_count--;
|
|
Packit |
517ee8 |
switch (el->type) {
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_KEY:
|
|
Packit |
517ee8 |
free((void *)el->data.key);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_ANCHOR:
|
|
Packit |
517ee8 |
free((void *)el->data.anchor);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_SLICE:
|
|
Packit |
517ee8 |
if (path->sequence_level == el->level)
|
|
Packit |
517ee8 |
path->sequence_level = 0;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
free(el);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static yaml_path_section_t*
|
|
Packit |
517ee8 |
yaml_path_section_create (yaml_path_t *path, yaml_path_section_type_t section_type)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
yaml_path_section_t *el = malloc(sizeof(*el));
|
|
Packit |
517ee8 |
assert(el != NULL);
|
|
Packit |
517ee8 |
memset(el, 0, sizeof(*el));
|
|
Packit |
517ee8 |
path->sections_count++;
|
|
Packit |
517ee8 |
el->level = path->sections_count;
|
|
Packit |
517ee8 |
el->type = section_type;
|
|
Packit |
517ee8 |
el->node_type = YAML_SCALAR_NODE;
|
|
Packit |
517ee8 |
TAILQ_INSERT_TAIL(&path->sections_list, el, entries);
|
|
Packit |
517ee8 |
if (el->type == YAML_PATH_SECTION_SLICE && !path->sequence_level) {
|
|
Packit |
517ee8 |
path->sequence_level = el->level;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return el;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static size_t
|
|
Packit |
517ee8 |
yaml_path_section_snprint (yaml_path_section_t *section, char *s, size_t max_len)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(section != NULL);
|
|
Packit |
517ee8 |
if (s == NULL)
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
size_t len = 0;
|
|
Packit |
517ee8 |
switch (section->type) {
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_ROOT:
|
|
Packit |
517ee8 |
len = snprintf(s, max_len, "$");
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_KEY:
|
|
Packit |
517ee8 |
len = snprintf(s, max_len, ".%s", section->data.key);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_ANCHOR:
|
|
Packit |
517ee8 |
len = snprintf(s, max_len, "&%s", section->data.anchor);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_INDEX:
|
|
Packit |
517ee8 |
len = snprintf(s, max_len, "[%d]", section->data.index);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_SLICE:
|
|
Packit |
517ee8 |
len = snprintf(s, max_len, "[%d:%d:%d]", section->data.slice.start, section->data.slice.end, section->data.slice.stride);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
len = snprintf(s, max_len, "");
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return len;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void
|
|
Packit |
517ee8 |
_parse (yaml_path_t *path, char *s_path) {
|
|
Packit |
517ee8 |
char *sp = s_path;
|
|
Packit |
517ee8 |
char *spe = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (s_path == NULL || !s_path[0]) {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Path is empty", 0);
|
|
Packit |
517ee8 |
return;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
while (*sp != '\0') {
|
|
Packit |
517ee8 |
switch (*sp) {
|
|
Packit |
517ee8 |
case '.':
|
|
Packit |
517ee8 |
case '[':
|
|
Packit |
517ee8 |
if (path->sections_count == 0) {
|
|
Packit |
517ee8 |
yaml_path_section_create(path, YAML_PATH_SECTION_ROOT);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (*sp == '.') {
|
|
Packit |
517ee8 |
// Key
|
|
Packit |
517ee8 |
spe = sp + 1;
|
|
Packit |
517ee8 |
while (*spe != '.' && *spe != '[' && *spe != '\0')
|
|
Packit |
517ee8 |
spe++;
|
|
Packit |
517ee8 |
if (spe == sp+1) {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is missing", sp - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY);
|
|
Packit |
517ee8 |
sec->data.key = strndup(sp + 1, spe-sp - 1);
|
|
Packit |
517ee8 |
sp = spe-1;
|
|
Packit |
517ee8 |
} else if (*sp == '[') {
|
|
Packit |
517ee8 |
spe = sp+1;
|
|
Packit |
517ee8 |
if (*spe == '\'') {
|
|
Packit |
517ee8 |
// Key
|
|
Packit |
517ee8 |
sp = spe;
|
|
Packit |
517ee8 |
spe++;
|
|
Packit |
517ee8 |
while (*spe != '\'' && *spe != '\0')
|
|
Packit |
517ee8 |
spe++;
|
|
Packit |
517ee8 |
if (spe == sp+1) {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is missing", sp - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (*spe == '\0') {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is invalid (unxepected end of string, missing ''')", sp - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
spe++;
|
|
Packit |
517ee8 |
if (*spe == '\0') {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is invalid (unxepected end of string, missing ']')", sp - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (*spe != ']') {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment key is invalid (invalid character)", spe - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY);
|
|
Packit |
517ee8 |
sec->data.key = strndup(sp + 1, spe-sp - 2);
|
|
Packit |
517ee8 |
sp = spe;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
// Index or Slice
|
|
Packit |
517ee8 |
int idx = strtol(spe, &spe, 10);
|
|
Packit |
517ee8 |
if (*spe == ']') {
|
|
Packit |
517ee8 |
// Index
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_INDEX);
|
|
Packit |
517ee8 |
sec->data.index = idx;
|
|
Packit |
517ee8 |
sp = spe;
|
|
Packit |
517ee8 |
} else if (*spe == ':') {
|
|
Packit |
517ee8 |
// Slice
|
|
Packit |
517ee8 |
int idx_start = idx;
|
|
Packit |
517ee8 |
sp = spe++;
|
|
Packit |
517ee8 |
idx = strtol(spe, &spe, 10);
|
|
Packit |
517ee8 |
if (*spe == ':') {
|
|
Packit |
517ee8 |
int idx_end = (spe == sp+1 ? __INT_MAX__ : idx);
|
|
Packit |
517ee8 |
sp = spe++;
|
|
Packit |
517ee8 |
idx = strtol(spe, &spe, 10);
|
|
Packit |
517ee8 |
if (*spe == ']' && (idx > 0 || spe == sp+1)) {
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SLICE);
|
|
Packit |
517ee8 |
sec->data.slice.start = idx_start;
|
|
Packit |
517ee8 |
sec->data.slice.end = idx_end;
|
|
Packit |
517ee8 |
sec->data.slice.stride = idx > 0 ? idx : 1;
|
|
Packit |
517ee8 |
sp = spe;
|
|
Packit |
517ee8 |
} else if (*spe == ']' && idx <= 0) {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment slice stride can not be less than 1", spe - s_path - 1);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment slice stride is invalid (invalid character)", spe - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else if (*spe == ']') {
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_SLICE);
|
|
Packit |
517ee8 |
sec->data.slice.start = idx_start;
|
|
Packit |
517ee8 |
sec->data.slice.end = (spe == sp+1 ? __INT_MAX__ : idx);
|
|
Packit |
517ee8 |
sec->data.slice.stride = 1;
|
|
Packit |
517ee8 |
sp = spe;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment slice end index is invalid (invalid character)", spe - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else if (*spe == '\0') {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment index is invalid (unxepected end of string, missing ']')", spe - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Segment index is invalid (invalid character)", spe - s_path);
|
|
Packit |
517ee8 |
goto error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
if (path->sections_count == 0) {
|
|
Packit |
517ee8 |
spe = sp + 1;
|
|
Packit |
517ee8 |
if (*sp == '$' && (*spe == '.' || *spe == '[' || *spe == '\0')) {
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT);
|
|
Packit |
517ee8 |
} else if (*sp == '&') {
|
|
Packit |
517ee8 |
// Anchor
|
|
Packit |
517ee8 |
sp++;
|
|
Packit |
517ee8 |
while (*spe != '.' && *spe != '[' && *spe != '\0')
|
|
Packit |
517ee8 |
spe++;
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ANCHOR);
|
|
Packit |
517ee8 |
sec->data.anchor = strndup(sp, spe-sp);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
// Key
|
|
Packit |
517ee8 |
while (*spe != '.' && *spe != '[' && *spe != '\0')
|
|
Packit |
517ee8 |
spe++;
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_create(path, YAML_PATH_SECTION_ROOT);
|
|
Packit |
517ee8 |
sec = yaml_path_section_create(path, YAML_PATH_SECTION_KEY);
|
|
Packit |
517ee8 |
sec->data.key = strndup(sp, spe-sp);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
sp = spe-1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
sp++;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path->sections_count == 0) {
|
|
Packit |
517ee8 |
yaml_path_error_set(path, YAML_PATH_ERROR_PARSE, "Invalid path segments", 0);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
error:
|
|
Packit |
517ee8 |
yaml_path_sections_remove(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static yaml_path_section_t*
|
|
Packit |
517ee8 |
yaml_path_section_get_at_level (yaml_path_t *path, size_t level)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
yaml_path_section_t *el;
|
|
Packit |
517ee8 |
TAILQ_FOREACH(el, &path->sections_list, entries) {
|
|
Packit |
517ee8 |
if (el->level == level)
|
|
Packit |
517ee8 |
return el;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static yaml_path_section_t*
|
|
Packit |
517ee8 |
yaml_path_section_get_first (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
return yaml_path_section_get_at_level(path, 1);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static yaml_path_section_t*
|
|
Packit |
517ee8 |
yaml_path_section_get_current (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
if (!path->start_level)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
return yaml_path_section_get_at_level(path, path->current_level - path->start_level + 1);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool
|
|
Packit |
517ee8 |
yaml_path_sections_prev_are_valid (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
int valid = true;
|
|
Packit |
517ee8 |
yaml_path_section_t *el;
|
|
Packit |
517ee8 |
TAILQ_FOREACH(el, &path->sections_list, entries) {
|
|
Packit |
517ee8 |
if (el->level < path->current_level - path->start_level + 1)
|
|
Packit |
517ee8 |
valid = el->valid && valid;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return valid;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool
|
|
Packit |
517ee8 |
yaml_path_section_current_is_last (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_get_current(path);
|
|
Packit |
517ee8 |
if (sec == NULL)
|
|
Packit |
517ee8 |
return false;
|
|
Packit |
517ee8 |
return sec->level == path->sections_count;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool
|
|
Packit |
517ee8 |
yaml_path_section_current_is_mandatory_sequence (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
yaml_path_section_t *sec = yaml_path_section_get_current(path);
|
|
Packit |
517ee8 |
if (sec == NULL)
|
|
Packit |
517ee8 |
return false;
|
|
Packit |
517ee8 |
return (sec->type == YAML_PATH_SECTION_SLICE && sec->level == path->sequence_level);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool
|
|
Packit |
517ee8 |
yaml_path_is_valid (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
assert(path != NULL);
|
|
Packit |
517ee8 |
bool valid = true;
|
|
Packit |
517ee8 |
yaml_path_section_t *el;
|
|
Packit |
517ee8 |
TAILQ_FOREACH(el, &path->sections_list, entries) {
|
|
Packit |
517ee8 |
valid = el->valid && valid;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return valid;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* Public */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
yaml_path_t*
|
|
Packit |
517ee8 |
yaml_path_create (void)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
yaml_path_t *ypath = malloc(sizeof(*ypath));
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
assert(ypath != NULL);
|
|
Packit |
517ee8 |
memset (ypath, 0, sizeof(*ypath));
|
|
Packit |
517ee8 |
TAILQ_INIT(&ypath->sections_list);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return ypath;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
int
|
|
Packit |
517ee8 |
yaml_path_parse (yaml_path_t *path, char *s_path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (path == NULL)
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
yaml_path_sections_remove(path);
|
|
Packit |
517ee8 |
memset(&path->error, 0, sizeof(path->error));
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
_parse(path, s_path);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path->sections_count == 0)
|
|
Packit |
517ee8 |
return -2;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
void
|
|
Packit |
517ee8 |
yaml_path_destroy (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (path == NULL)
|
|
Packit |
517ee8 |
return;
|
|
Packit |
517ee8 |
yaml_path_sections_remove(path);
|
|
Packit |
517ee8 |
free(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* API */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
const yaml_path_error_t*
|
|
Packit |
517ee8 |
yaml_path_error_get (yaml_path_t *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (path == NULL)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
return &path->error;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
size_t
|
|
Packit |
517ee8 |
yaml_path_snprint (yaml_path_t *path, char *s, size_t max_len)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (s == NULL)
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
if (path == NULL)
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
size_t len = 0;
|
|
Packit |
517ee8 |
yaml_path_section_t *el;
|
|
Packit |
517ee8 |
TAILQ_FOREACH(el, &path->sections_list, entries) {
|
|
Packit |
517ee8 |
len += yaml_path_section_snprint(el, s + (len < max_len ? len : max_len), max_len - (len < max_len ? len : max_len));
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return len;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
int
|
|
Packit |
517ee8 |
yaml_path_filter_event (yaml_path_t *path, yaml_parser_t *parser, yaml_event_t *event, yaml_path_filter_mode_t mode)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
int res = 0;
|
|
Packit |
517ee8 |
const char *anchor = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path == NULL || parser == NULL || event == NULL)
|
|
Packit |
517ee8 |
goto exit;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
switch(event->type) {
|
|
Packit |
517ee8 |
case YAML_MAPPING_START_EVENT:
|
|
Packit |
517ee8 |
anchor = (const char *)event->data.mapping_start.anchor;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_SEQUENCE_START_EVENT:
|
|
Packit |
517ee8 |
anchor = (const char *)event->data.sequence_start.anchor;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_SCALAR_EVENT:
|
|
Packit |
517ee8 |
anchor = (const char *)event->data.scalar.anchor;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (!path->start_level) {
|
|
Packit |
517ee8 |
switch (yaml_path_section_get_first(path)->type) {
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_ROOT:
|
|
Packit |
517ee8 |
if (event->type == YAML_DOCUMENT_START_EVENT) {
|
|
Packit |
517ee8 |
path->start_level = 1;
|
|
Packit |
517ee8 |
yaml_path_section_get_first(path)->valid = true;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_PATH_SECTION_ANCHOR:
|
|
Packit |
517ee8 |
if (anchor != NULL) {
|
|
Packit |
517ee8 |
if (!strcmp(yaml_path_section_get_first(path)->data.anchor, anchor)) {
|
|
Packit |
517ee8 |
path->start_level = path->current_level;
|
|
Packit |
517ee8 |
if (yaml_path_section_get_current(path))
|
|
Packit |
517ee8 |
yaml_path_section_get_current(path)->node_type = YAML_SCALAR_NODE;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
//TODO: This path is invalid
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
//TODO: ?
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
yaml_path_section_t *current_section = yaml_path_section_get_current(path);
|
|
Packit |
517ee8 |
if (!current_section) {
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
switch (event->type) {
|
|
Packit |
517ee8 |
case YAML_DOCUMENT_START_EVENT:
|
|
Packit |
517ee8 |
case YAML_MAPPING_START_EVENT:
|
|
Packit |
517ee8 |
case YAML_SEQUENCE_START_EVENT:
|
|
Packit |
517ee8 |
case YAML_ALIAS_EVENT:
|
|
Packit |
517ee8 |
case YAML_SCALAR_EVENT:
|
|
Packit |
517ee8 |
switch (current_section->node_type) {
|
|
Packit |
517ee8 |
case YAML_SCALAR_NODE:
|
|
Packit |
517ee8 |
current_section->valid = true;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_MAPPING_NODE:
|
|
Packit |
517ee8 |
if (current_section->type == YAML_PATH_SECTION_KEY) {
|
|
Packit |
517ee8 |
if (current_section->counter % 2) {
|
|
Packit |
517ee8 |
current_section->valid = current_section->next_valid;
|
|
Packit |
517ee8 |
current_section->next_valid = false;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
current_section->next_valid = !strcmp(current_section->data.key, (const char *)event->data.scalar.value);
|
|
Packit |
517ee8 |
current_section->valid = false;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
current_section->valid = false;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_SEQUENCE_NODE:
|
|
Packit |
517ee8 |
if (current_section->type == YAML_PATH_SECTION_INDEX) {
|
|
Packit |
517ee8 |
current_section->valid = current_section->data.index == current_section->counter;
|
|
Packit |
517ee8 |
} else if (current_section->type == YAML_PATH_SECTION_SLICE) {
|
|
Packit |
517ee8 |
current_section->valid = current_section->data.slice.start <= current_section->counter &&
|
|
Packit |
517ee8 |
current_section->data.slice.end > current_section->counter &&
|
|
Packit |
517ee8 |
(current_section->data.slice.start + current_section->counter) % current_section->data.slice.stride == 0;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
current_section->valid = false;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
current_section->counter++;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
switch (event->type) {
|
|
Packit |
517ee8 |
case YAML_STREAM_START_EVENT:
|
|
Packit |
517ee8 |
case YAML_STREAM_END_EVENT:
|
|
Packit |
517ee8 |
case YAML_NO_EVENT:
|
|
Packit |
517ee8 |
res = 1;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_DOCUMENT_START_EVENT:
|
|
Packit |
517ee8 |
if (path->start_level == 1)
|
|
Packit |
517ee8 |
path->current_level++;
|
|
Packit |
517ee8 |
res = 1;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_DOCUMENT_END_EVENT:
|
|
Packit |
517ee8 |
if (path->start_level == 1)
|
|
Packit |
517ee8 |
path->current_level--;
|
|
Packit |
517ee8 |
res = 1;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_MAPPING_START_EVENT:
|
|
Packit |
517ee8 |
case YAML_SEQUENCE_START_EVENT:
|
|
Packit |
517ee8 |
if (current_section) {
|
|
Packit |
517ee8 |
if (yaml_path_section_current_is_last(path))
|
|
Packit |
517ee8 |
res = yaml_path_is_valid(path);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
if (path->current_level > path->start_level) {
|
|
Packit |
517ee8 |
if (mode == YAML_PATH_FILTER_RETURN_ALL)
|
|
Packit |
517ee8 |
res = yaml_path_is_valid(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
path->current_level++;
|
|
Packit |
517ee8 |
current_section = yaml_path_section_get_current(path);
|
|
Packit |
517ee8 |
if (current_section && yaml_path_section_current_is_mandatory_sequence(path)) {
|
|
Packit |
517ee8 |
res = yaml_path_sections_prev_are_valid(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (current_section) {
|
|
Packit |
517ee8 |
current_section->node_type = event->type == YAML_MAPPING_START_EVENT ? YAML_MAPPING_NODE : YAML_SEQUENCE_NODE;
|
|
Packit |
517ee8 |
current_section->counter = 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_MAPPING_END_EVENT:
|
|
Packit |
517ee8 |
case YAML_SEQUENCE_END_EVENT:
|
|
Packit |
517ee8 |
if (current_section) {
|
|
Packit |
517ee8 |
if (yaml_path_section_current_is_mandatory_sequence(path))
|
|
Packit |
517ee8 |
res = yaml_path_sections_prev_are_valid(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
path->current_level--;
|
|
Packit |
517ee8 |
current_section = yaml_path_section_get_current(path);
|
|
Packit |
517ee8 |
if (current_section) {
|
|
Packit |
517ee8 |
if (yaml_path_section_current_is_last(path))
|
|
Packit |
517ee8 |
res = yaml_path_is_valid(path);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
if (path->current_level > path->start_level) {
|
|
Packit |
517ee8 |
if (mode == YAML_PATH_FILTER_RETURN_ALL)
|
|
Packit |
517ee8 |
res = yaml_path_is_valid(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case YAML_ALIAS_EVENT:
|
|
Packit |
517ee8 |
case YAML_SCALAR_EVENT:
|
|
Packit |
517ee8 |
if (!current_section) {
|
|
Packit |
517ee8 |
if ((mode == YAML_PATH_FILTER_RETURN_ALL && path->current_level > path->start_level) || path->current_level == path->start_level)
|
|
Packit |
517ee8 |
res = yaml_path_is_valid(path);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
res = yaml_path_is_valid(path) && yaml_path_section_current_is_last(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
exit:
|
|
Packit |
517ee8 |
return res;
|
|
Packit |
517ee8 |
}
|