*
* LGPL HEADER END
*
- * Copyright (c) 2014, 2015, Intel Corporation.
+ * Copyright (c) 2014, 2017, Intel Corporation.
*
* Author:
* Amir Shehata <amir.shehata@intel.com>
#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",
* 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 */
struct cYAML *obj;
if (tree->state != TREE_STATE_SEQ_START &&
- tree->state != TREE_STATE_BLK_STARTED)
+ tree->state != TREE_STATE_BLK_STARTED &&
+ tree->state != TREE_STATE_VALUE)
return CYAML_ERROR_UNEXPECTED_STATE;
if (tree->state == TREE_STATE_SEQ_START) {
static bool free_node(struct cYAML *node, void *user_data, void **out)
{
- if (node)
- free(node);
+ if (!node)
+ return true;
+ if (node->cy_type == CYAML_TYPE_STRING)
+ free(node->cy_valuestring);
+ if (node->cy_string)
+ free(node->cy_string);
+
+ free(node);
return true;
}
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;
- if (node->cy_string != NULL)
- fprintf(f, "%*s""%s%s:\n", (cpi->array_first_elem) ?
+ tmp = ensure(tmp, len);
+ if (!tmp)
+ return;
+
+ 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,
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;
+}