Whamcloud - gitweb
LU-9680 net: Netlink improvements
[fs/lustre-release.git] / lnet / utils / lnetconfig / cyaml.c
index ae5205f..0c859a1 100644 (file)
@@ -41,6 +41,7 @@
 #include <stdio.h>
 #include <math.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <float.h>
 #include <limits.h>
 #include <ctype.h>
@@ -49,6 +50,8 @@
 
 #define INDENT         4
 #define EXTRA_IND      2
+#define LEAD_ROOM      128
+#define PRINT_BUF_LEN  2048
 
 /*
  * cYAML_print_info
@@ -72,7 +75,7 @@ struct cYAML_ll {
        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,
@@ -107,7 +110,7 @@ struct cYAML_tree_node {
 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);
@@ -136,7 +139,7 @@ static enum cYAML_handler_error yaml_entry_token(yaml_token_t *token,
 
 /* 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,
@@ -161,7 +164,7 @@ static yaml_token_handler dispatch_tbl[] = {
 };
 
 /* 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",
@@ -186,7 +189,7 @@ static char *token_type_string[] = {
        [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",
@@ -460,10 +463,11 @@ static int assign_type_value(struct cYAML *obj, const char *value)
  * 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,
@@ -545,7 +549,8 @@ static enum cYAML_handler_error yaml_scalar(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 */
@@ -792,102 +797,194 @@ void cYAML_free_tree(struct cYAML *node)
        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;
 
-       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);
+       }
 
-       fprintf(f, "%*s""%s: %" PRId64 "\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;
 
-       if (cpi->array_first_elem)
-               fprintf(f, "%*s- ", INDENT * level, "");
+       *out = ensure(*out, len);
+       if (!*out)
+               return;
+
+       tmp = ensure(tmp, len);
+       if (!tmp)
+               return;
+
+       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;
 
-       if (cpi->array_first_elem)
-               fprintf(f, "%*s- ", INDENT * level, "");
+       *out = ensure(*out, len);
+       if (!*out)
+               return;
+
+       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: %" PRId64 "\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;
@@ -897,24 +994,40 @@ static void print_object(FILE *f, struct cYAML *node,
          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 :
@@ -923,14 +1036,18 @@ static void print_array(FILE *f, struct cYAML *node,
        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);
@@ -942,19 +1059,19 @@ static void print_value(FILE *f, struct list_head *stack)
        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;
@@ -964,10 +1081,37 @@ static void print_value(FILE *f, struct list_head *stack)
                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);
 
@@ -977,13 +1121,23 @@ void cYAML_print_tree(struct cYAML *node)
        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);
 
@@ -993,7 +1147,13 @@ void cYAML_print_tree2file(FILE *f, struct cYAML *node)
        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,
@@ -1143,57 +1303,27 @@ failed:
        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 ="
@@ -1205,29 +1335,22 @@ struct cYAML *cYAML_build_tree(char *yaml_file,
                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;
@@ -1236,3 +1359,66 @@ struct cYAML *cYAML_build_tree(char *yaml_file,
 
        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;
+}