#include <stdio.h>
#include <math.h>
#include <stdlib.h>
+#include <errno.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#define INDENT 4
#define EXTRA_IND 2
+#define LEAD_ROOM 128
+#define PRINT_BUF_LEN 2048
/*
* cYAML_print_info
struct cYAML_print_info *print_info;
};
-static void print_value(FILE *f, struct list_head *stack);
+static void print_value(char **out, struct list_head *stack);
enum cYAML_handler_error {
CYAML_ERROR_NONE = 0,
typedef enum cYAML_handler_error (*yaml_token_handler)(yaml_token_t *token,
struct cYAML_tree_node *);
-static enum cYAML_handler_error yaml_parse_error(yaml_token_t *token,
+static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
struct cYAML_tree_node *tree);
static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
struct cYAML_tree_node *tree);
/* dispatch table */
static yaml_token_handler dispatch_tbl[] = {
- [YAML_NO_TOKEN] = yaml_parse_error,
+ [YAML_NO_TOKEN] = yaml_no_token,
[YAML_STREAM_START_TOKEN] = yaml_stream_start,
[YAML_STREAM_END_TOKEN] = yaml_stream_end,
[YAML_VERSION_DIRECTIVE_TOKEN] = yaml_not_supported,
};
/* dispatch table */
-static char *token_type_string[] = {
+static const char * const token_type_string[] = {
[YAML_NO_TOKEN] = "YAML_NO_TOKEN",
[YAML_STREAM_START_TOKEN] = "YAML_STREAM_START_TOKEN",
[YAML_STREAM_END_TOKEN] = "YAML_STREAM_END_TOKEN",
[YAML_SCALAR_TOKEN] = "YAML_SCALAR_TOKEN",
};
-static char *state_string[] = {
+static const char * const state_string[] = {
[TREE_STATE_COMPLETE] = "COMPLETE",
[TREE_STATE_INITED] = "INITED",
[TREE_STATE_TREE_STARTED] = "TREE_STARTED",
struct cYAML *obj = NULL;
if (!list_empty(list)) {
- pop = list_entry(list->next, struct cYAML_ll, list);
+ pop = list_first_entry(list, struct cYAML_ll, list);
obj = pop->obj;
if (print_info != NULL)
int subscale = 0, signsubscale = 1;
const char *num = input;
+ if (!strncmp(input, "0x", 2)) {
+ int64_t hex; /* hex input is always an integer */
+ char *invalid = NULL;
+
+ errno = 0;
+ hex = strtoll(input, &invalid, 16);
+ if (errno)
+ return false;
+ if (*invalid)
+ return false;
+
+ item->cy_valuedouble = (double) hex;
+ item->cy_valueint = hex;
+ item->cy_type = CYAML_TYPE_NUMBER;
+ return true;
+ }
+
if (*num == '-') {
sign = -1;
num++;
n = sign * n * pow(10.0, (scale + subscale * signsubscale));
item->cy_valuedouble = n;
- item->cy_valueint = (int)n;
+ item->cy_valueint = (int64_t)n;
item->cy_type = CYAML_TYPE_NUMBER;
return true;
* else state = VALUE
*
*/
-static enum cYAML_handler_error yaml_parse_error(yaml_token_t *token,
- struct cYAML_tree_node *tree)
+
+static enum cYAML_handler_error yaml_no_token(yaml_token_t *token,
+ struct cYAML_tree_node *tree)
{
- return CYAML_ERROR_PARSE;
+ return CYAML_ERROR_NONE;
}
static enum cYAML_handler_error yaml_stream_start(yaml_token_t *token,
strdup((const char *)token->data.scalar.value);
tree->state = TREE_STATE_KEY_FILLED;
- } else if (tree->state == TREE_STATE_VALUE) {
+ } else if (tree->state == TREE_STATE_VALUE ||
+ tree->state == TREE_STATE_SEQ_START) {
if (assign_type_value(tree->cur,
(char *)token->data.scalar.value))
/* failed to assign a value */
static bool free_node(struct cYAML *node, void *user_data, void **out)
{
+ if (!node)
+ return true;
+
if (node->cy_type == CYAML_TYPE_STRING)
free(node->cy_valuestring);
if (node->cy_string)
free(node->cy_string);
- if (node)
- free(node);
+ free(node);
return true;
}
return (node != NULL ? node->cy_type == CYAML_TYPE_ARRAY : 0);
}
-void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
+static void cYAML_tree_recursive_walk(struct cYAML *node, cYAML_walk_cb cb,
bool cb_first,
void *usr_data,
void **out)
cYAML_tree_recursive_walk(node, free_node, false, NULL, NULL);
}
-static inline void print_simple(FILE *f, struct cYAML *node,
+static char *ensure(char *in, int len)
+{
+ int curlen;
+ char *new = in;
+
+ if (!in)
+ return (char*)calloc(len, 1);
+
+ curlen = strlen(in) + 1;
+
+ if (curlen <= curlen + len) {
+ new = calloc(curlen + len, 1);
+ if (!new) {
+ free(in);
+ return NULL;
+ }
+ strcpy(new, in);
+ free(in);
+ }
+
+ return new;
+}
+
+static inline void print_simple(char **out, struct cYAML *node,
struct cYAML_print_info *cpi)
{
int level = cpi->level;
int ind = cpi->extra_ind;
+ char *tmp = NULL;
+ int len = (INDENT * level + ind) * 2 +
+ ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
+
+ *out = ensure(*out, len);
+ if (!*out)
+ return;
+
+ tmp = ensure(tmp, len);
+ if (!tmp)
+ return;
- if (cpi->array_first_elem)
- fprintf(f, "%*s- ", INDENT * level, "");
+ if (cpi->array_first_elem) {
+ sprintf(tmp, "%*s- ", INDENT * level, "");
+ strcat(*out, tmp);
+ }
- fprintf(f, "%*s""%s: %d\n", (cpi->array_first_elem) ? 0 :
+ sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
INDENT * level + ind, "", node->cy_string,
node->cy_valueint);
+ strcat(*out, tmp);
+ free(tmp);
}
-static void print_string(FILE *f, struct cYAML *node,
+static void print_string(char **out, struct cYAML *node,
struct cYAML_print_info *cpi)
{
char *new_line;
int level = cpi->level;
int ind = cpi->extra_ind;
+ char *tmp = NULL;
+ int len = INDENT * level + ind +
+ ((node->cy_valuestring) ? strlen(node->cy_valuestring) : 0) +
+ ((node->cy_string) ? strlen(node->cy_string) : 0) + LEAD_ROOM;
+
+ *out = ensure(*out, len);
+ if (!*out)
+ return;
+
+ tmp = ensure(tmp, len);
+ if (!tmp)
+ return;
- if (cpi->array_first_elem)
- fprintf(f, "%*s- ", INDENT * level, "");
+ if (cpi->array_first_elem) {
+ sprintf(tmp, "%*s- ", INDENT * level, "");
+ strcat(*out, tmp);
+ }
new_line = strchr(node->cy_valuestring, '\n');
- if (new_line == NULL)
- fprintf(f, "%*s""%s: %s\n", (cpi->array_first_elem) ?
+ if (new_line == NULL) {
+ sprintf(tmp, "%*s""%s: %s\n", (cpi->array_first_elem) ?
0 : INDENT * level + ind, "",
node->cy_string, node->cy_valuestring);
- else {
+ strcat(*out, tmp);
+ } else {
int indent = 0;
- fprintf(f, "%*s""%s: ", (cpi->array_first_elem) ?
+ sprintf(tmp, "%*s""%s: ", (cpi->array_first_elem) ?
0 : INDENT * level + ind, "",
node->cy_string);
+ strcat(*out, tmp);
char *l = node->cy_valuestring;
while (new_line) {
*new_line = '\0';
- fprintf(f, "%*s""%s\n", indent, "", l);
+ sprintf(tmp, "%*s""%s\n", indent, "", l);
+ strcat(*out, tmp);
indent = INDENT * level + ind +
strlen(node->cy_string) + 2;
*new_line = '\n';
l = new_line+1;
new_line = strchr(l, '\n');
}
- fprintf(f, "%*s""%s\n", indent, "", l);
+ sprintf(tmp, "%*s""%s\n", indent, "", l);
+ strcat(*out, tmp);
}
+
+ free(tmp);
}
-static void print_number(FILE *f, struct cYAML *node,
+static void print_number(char **out, struct cYAML *node,
struct cYAML_print_info *cpi)
{
double d = node->cy_valuedouble;
int level = cpi->level;
int ind = cpi->extra_ind;
+ char *tmp = NULL;
+ int len = INDENT * level + ind + LEAD_ROOM;
+
+ *out = ensure(*out, len);
+ if (!*out)
+ return;
- if (cpi->array_first_elem)
- fprintf(f, "%*s- ", INDENT * level, "");
+ tmp = ensure(tmp, len);
+ if (!tmp)
+ return;
+
+ if (cpi->array_first_elem) {
+ sprintf(tmp, "%*s- ", INDENT * level, "");
+ strcat(*out, tmp);
+ }
if ((fabs(((double)node->cy_valueint) - d) <= DBL_EPSILON) &&
- (d <= INT_MAX) && (d >= INT_MIN))
- fprintf(f, "%*s""%s: %d\n", (cpi->array_first_elem) ? 0 :
+ (d <= INT_MAX) && (d >= INT_MIN)) {
+ sprintf(tmp, "%*s""%s: %" PRId64 "\n", (cpi->array_first_elem) ? 0 :
INDENT * level + ind, "",
node->cy_string, node->cy_valueint);
- else {
+ strcat(*out, tmp);
+ } else {
if ((fabs(floor(d) - d) <= DBL_EPSILON) &&
- (fabs(d) < 1.0e60))
- fprintf(f, "%*s""%s: %.0f\n",
+ (fabs(d) < 1.0e60)) {
+ sprintf(tmp, "%*s""%s: %.0f\n",
(cpi->array_first_elem) ? 0 :
INDENT * level + ind, "",
node->cy_string, d);
- else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
- fprintf(f, "%*s""%s: %e\n",
+ strcat(*out, tmp);
+ } else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) {
+ sprintf(tmp, "%*s""%s: %e\n",
(cpi->array_first_elem) ? 0 :
INDENT * level + ind, "",
node->cy_string, d);
- else
- fprintf(f, "%*s""%s: %f\n",
+ strcat(*out, tmp);
+ } else {
+ sprintf(tmp, "%*s""%s: %f\n",
(cpi->array_first_elem) ? 0 :
INDENT * level + ind, "",
node->cy_string, d);
+ strcat(*out, tmp);
+ }
}
+
+ free(tmp);
}
-static void print_object(FILE *f, struct cYAML *node,
+static void print_object(char **out, struct cYAML *node,
struct list_head *stack,
struct cYAML_print_info *cpi)
{
struct cYAML_print_info print_info;
struct cYAML *child = node->cy_child;
+ char *tmp = NULL;
+ int len = ((cpi->array_first_elem) ? INDENT * cpi->level :
+ INDENT * cpi->level + cpi->extra_ind) +
+ ((node->cy_string) ? strlen(node->cy_string) : 0) +
+ LEAD_ROOM;
+
+ *out = ensure(*out, len);
+ if (!*out)
+ return;
+
+ tmp = ensure(tmp, len);
+ if (!tmp)
+ return;
- if (node->cy_string != NULL)
- fprintf(f, "%*s""%s%s:\n", (cpi->array_first_elem) ?
+ if (node->cy_string != NULL) {
+ sprintf(tmp, "%*s""%s%s:\n", (cpi->array_first_elem) ?
INDENT * cpi->level :
INDENT * cpi->level + cpi->extra_ind,
"", (cpi->array_first_elem) ? "- " : "",
node->cy_string);
+ strcat(*out, tmp);
+ }
print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
cpi->level;
cpi->extra_ind;
while (child) {
- if (cYAML_ll_push(child, &print_info, stack) != 0)
+ if (cYAML_ll_push(child, &print_info, stack) != 0) {
+ free(tmp);
return;
- print_value(f, stack);
+ }
+ print_value(out, stack);
print_info.array_first_elem = 0;
child = child->cy_next;
}
+
+ free(tmp);
}
-static void print_array(FILE *f, struct cYAML *node,
+static void print_array(char **out, struct cYAML *node,
struct list_head *stack,
struct cYAML_print_info *cpi)
{
struct cYAML_print_info print_info;
struct cYAML *child = node->cy_child;
+ char *tmp = NULL;
+ int len = ((node->cy_string) ? strlen(node->cy_string) : 0) +
+ INDENT * cpi->level + cpi->extra_ind + LEAD_ROOM;
+
+ *out = ensure(*out, len);
+ if (!*out)
+ return;
+
+ tmp = ensure(tmp, len);
+ if (!tmp)
+ return;
if (node->cy_string != NULL) {
- fprintf(f, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
+ sprintf(tmp, "%*s""%s:\n", INDENT * cpi->level + cpi->extra_ind,
"", node->cy_string);
+ strcat(*out, tmp);
}
print_info.level = (node->cy_string != NULL) ? cpi->level + 1 :
print_info.extra_ind = EXTRA_IND;
while (child) {
- if (cYAML_ll_push(child, &print_info, stack) != 0)
+ if (cYAML_ll_push(child, &print_info, stack) != 0) {
+ free(tmp);
return;
- print_value(f, stack);
+ }
+ print_value(out, stack);
child = child->cy_next;
}
+
+ free(tmp);
}
-static void print_value(FILE *f, struct list_head *stack)
+static void print_value(char **out, struct list_head *stack)
{
struct cYAML_print_info *cpi = NULL;
struct cYAML *node = cYAML_ll_pop(stack, &cpi);
case CYAML_TYPE_FALSE:
case CYAML_TYPE_TRUE:
case CYAML_TYPE_NULL:
- print_simple(f, node, cpi);
+ print_simple(out, node, cpi);
break;
case CYAML_TYPE_STRING:
- print_string(f, node, cpi);
+ print_string(out, node, cpi);
break;
case CYAML_TYPE_NUMBER:
- print_number(f, node, cpi);
+ print_number(out, node, cpi);
break;
case CYAML_TYPE_ARRAY:
- print_array(f, node, stack, cpi);
+ print_array(out, node, stack, cpi);
break;
case CYAML_TYPE_OBJECT:
- print_object(f, node, stack, cpi);
+ print_object(out, node, stack, cpi);
break;
default:
break;
free(cpi);
}
+void cYAML_dump(struct cYAML *node, char **buf)
+{
+ struct cYAML_print_info print_info;
+ struct list_head list;
+
+ *buf = ensure(NULL, PRINT_BUF_LEN);
+
+ if (!*buf)
+ return;
+
+ INIT_LIST_HEAD(&list);
+
+ if (node == NULL) {
+ *buf = NULL;
+ return;
+ }
+
+ memset(&print_info, 0, sizeof(struct cYAML_print_info));
+
+ if (cYAML_ll_push(node, &print_info, &list) == 0)
+ print_value(buf, &list);
+}
+
void cYAML_print_tree(struct cYAML *node)
{
struct cYAML_print_info print_info;
struct list_head list;
+ char *buf = ensure(NULL, PRINT_BUF_LEN);
+
+ if (!buf)
+ return;
INIT_LIST_HEAD(&list);
memset(&print_info, 0, sizeof(struct cYAML_print_info));
if (cYAML_ll_push(node, &print_info, &list) == 0)
- print_value(stdout, &list);
+ print_value(&buf, &list);
+
+ /* buf could've been freed if we ran out of memory */
+ if (buf) {
+ printf("%s", buf);
+ free(buf);
+ }
}
void cYAML_print_tree2file(FILE *f, struct cYAML *node)
{
struct cYAML_print_info print_info;
struct list_head list;
+ char *buf = ensure(NULL, PRINT_BUF_LEN);
+
+ if (!buf)
+ return;
INIT_LIST_HEAD(&list);
memset(&print_info, 0, sizeof(struct cYAML_print_info));
if (cYAML_ll_push(node, &print_info, &list) == 0)
- print_value(f, &list);
+ print_value(&buf, &list);
+
+ /* buf could've been freed if we ran out of memory */
+ if (buf) {
+ fprintf(f, "%s", buf);
+ free(buf);
+ }
}
static struct cYAML *insert_item(struct cYAML *parent, char *key,
char *entity, char *err_str,
struct cYAML **root)
{
- struct cYAML *r = NULL, *err, *s, *itm, *cmd_obj;
+ struct cYAML *r = NULL, *err, *s, *itm = NULL, *cmd_obj;
if (root == NULL)
return;
else if (cmd_obj == NULL) {
s = cYAML_create_seq(r, cmd);
itm = cYAML_create_seq_item(s);
- } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY)
+ } else if (cmd_obj != NULL && cmd_obj->cy_type != CYAML_TYPE_ARRAY) {
goto failed;
+ }
err = cYAML_create_object(itm, entity);
if (err == NULL)
fprintf(stderr, "error:\n\tfatal: out of memory\n");
}
-struct cYAML *cYAML_build_tree(char *yaml_file,
- const char *yaml_blk,
- size_t yaml_blk_size,
- struct cYAML **err_rc,
- bool debug)
+static struct cYAML *
+cYAML_parser_to_tree(yaml_parser_t *parser, struct cYAML **err_rc, bool debug)
{
- yaml_parser_t parser;
yaml_token_t token;
struct cYAML_tree_node tree;
enum cYAML_handler_error rc;
yaml_token_type_t token_type;
char err_str[256];
- FILE *input = NULL;
int done = 0;
memset(&tree, 0, sizeof(struct cYAML_tree_node));
INIT_LIST_HEAD(&tree.ll);
- /* Create the Parser object. */
- yaml_parser_initialize(&parser);
-
- /* file always takes precedence */
- if (yaml_file != NULL) {
- /* Set a file input. */
- input = fopen(yaml_file, "rb");
- if (input == NULL) {
- snprintf(err_str, sizeof(err_str),
- "Failed to open file: %s", yaml_file);
- cYAML_build_error(-1, -1, "yaml", "builder",
- err_str,
- err_rc);
- return NULL;
- }
-
- yaml_parser_set_input_file(&parser, input);
- } else if (yaml_blk != NULL) {
- yaml_parser_set_input_string(&parser,
- (const unsigned char *) yaml_blk,
- yaml_blk_size);
- } else
- /* assume that we're getting our input froms stdin */
- yaml_parser_set_input_file(&parser, stdin);
-
/* Read the event sequence. */
while (!done) {
/*
* Go through the parser and build a cYAML representation
* of the passed in YAML text
*/
- yaml_parser_scan(&parser, &token);
+ yaml_parser_scan(parser, &token);
if (debug)
fprintf(stderr, "tree.state(%p:%d) = %s, token.type ="
rc = dispatch_tbl[token.type](&token, &tree);
if (rc != CYAML_ERROR_NONE) {
snprintf(err_str, sizeof(err_str),
- "Failed to handle token:%d "
- "[state=%d, rc=%d]",
- token.type, tree.state, rc);
+ "Failed to handle token:%d %s [state=%d, rc=%d]",
+ token.type, token_type_string[token.type],
+ tree.state, rc);
cYAML_build_error(-1, -1, "yaml", "builder",
err_str,
err_rc);
}
/* Are we finished? */
done = (rc != CYAML_ERROR_NONE ||
- token.type == YAML_STREAM_END_TOKEN ||
- token.type == YAML_NO_TOKEN);
+ token.type == YAML_STREAM_END_TOKEN);
token_type = token.type;
yaml_token_delete(&token);
}
- /* Destroy the Parser object. */
- yaml_parser_delete(&parser);
-
- if (input != NULL)
- fclose(input);
-
if (token_type == YAML_STREAM_END_TOKEN &&
rc == CYAML_ERROR_NONE)
return tree.root;
return NULL;
}
+
+struct cYAML *cYAML_load(FILE *file, struct cYAML **err_rc, bool debug)
+{
+ yaml_parser_t parser;
+ struct cYAML *yaml;
+
+ yaml_parser_initialize(&parser);
+ yaml_parser_set_input_file(&parser, file);
+
+ yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
+
+ yaml_parser_delete(&parser);
+
+ return yaml;
+}
+
+struct cYAML *cYAML_build_tree(char *path,
+ const char *yaml_blk,
+ size_t yaml_blk_size,
+ struct cYAML **err_rc,
+ bool debug)
+{
+ yaml_parser_t parser;
+ struct cYAML *yaml;
+ char err_str[256];
+ FILE *input = NULL;
+
+ /* Create the Parser object. */
+ yaml_parser_initialize(&parser);
+
+ /* file always takes precedence */
+ if (path != NULL) {
+ /* Set a file input. */
+ input = fopen(path, "rb");
+ if (input == NULL) {
+ snprintf(err_str, sizeof(err_str),
+ "cannot open '%s': %s", path, strerror(errno));
+ cYAML_build_error(-1, -1, "yaml", "builder",
+ err_str,
+ err_rc);
+ return NULL;
+ }
+
+ yaml_parser_set_input_file(&parser, input);
+ } else if (yaml_blk != NULL) {
+ yaml_parser_set_input_string(&parser,
+ (const unsigned char *) yaml_blk,
+ yaml_blk_size);
+ } else {
+ /* assume that we're getting our input froms stdin */
+ yaml_parser_set_input_file(&parser, stdin);
+ }
+
+ yaml = cYAML_parser_to_tree(&parser, err_rc, debug);
+
+ /* Destroy the Parser object. */
+ yaml_parser_delete(&parser);
+
+ if (input != NULL)
+ fclose(input);
+
+ return yaml;
+}