diff --git a/src/ocispec/headers.py b/src/ocispec/headers.py index cbf00de2..4d1ff88c 100755 --- a/src/ocispec/headers.py +++ b/src/ocispec/headers.py @@ -172,6 +172,7 @@ def append_type_c_header(obj, header, prefix): typename = helpers.get_prefixed_name(obj.name, prefix) header.append(f"}}\n{typename};\n\n") header.append(f"void free_{typename} ({typename} *ptr);\n\n") + header.append(f"{typename} *clone_{typename} ({typename} *src);\n") header.append(f"{typename} *make_{typename} (yajl_val tree, const struct parser_context *ctx, parser_error *err);\n\n") header.append(f"yajl_gen_status gen_{typename} (yajl_gen g, const {typename} *ptr, const struct parser_context *ctx, parser_error *err);\n\n") @@ -232,13 +233,13 @@ def header_reflect(structs, schema_info, header): length = len(structs) toptype = structs[length - 1].typ if length != 0 else "" if toptype == 'object': - header.append(f"{prefix} *{prefix}_parse_file(const char *filename, const struct parser_context *ctx, "\ + header.append(f"{prefix} *{prefix}_parse_file (const char *filename, const struct parser_context *ctx, "\ "parser_error *err);\n\n") - header.append(f"{prefix} *{prefix}_parse_file_stream(FILE *stream, const struct parser_context *ctx, "\ + header.append(f"{prefix} *{prefix}_parse_file_stream (FILE *stream, const struct parser_context *ctx, "\ "parser_error *err);\n\n") - header.append(f"{prefix} *{prefix}_parse_data(const char *jsondata, const struct parser_context *ctx, "\ + header.append(f"{prefix} *{prefix}_parse_data (const char *jsondata, const struct parser_context *ctx, "\ "parser_error *err);\n\n") - header.append(f"char *{prefix}_generate_json(const {prefix} *ptr, const struct parser_context *ctx, "\ + header.append(f"char *{prefix}_generate_json (const {prefix} *ptr, const struct parser_context *ctx, "\ "parser_error *err);\n\n") elif toptype == 'array': header_reflect_top_array(structs[length - 1], prefix, header) diff --git a/src/ocispec/json_common.c b/src/ocispec/json_common.c index 9722b955..a8d742a7 100644 --- a/src/ocispec/json_common.c +++ b/src/ocispec/json_common.c @@ -509,7 +509,8 @@ free_json_map_int_int (json_map_int_int *map) define_cleaner_function (json_map_int_int *, free_json_map_int_int) - json_map_int_int *make_json_map_int_int (yajl_val src, const struct parser_context *ctx, parser_error *err) +json_map_int_int * +make_json_map_int_int (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_int_int) json_map_int_int *ret = NULL; size_t i; @@ -689,7 +690,8 @@ free_json_map_int_bool (json_map_int_bool *map) define_cleaner_function (json_map_int_bool *, free_json_map_int_bool) - json_map_int_bool *make_json_map_int_bool (yajl_val src, const struct parser_context *ctx, parser_error *err) +json_map_int_bool * +make_json_map_int_bool (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_int_bool) json_map_int_bool *ret = NULL; size_t i; @@ -861,7 +863,8 @@ free_json_map_int_string (json_map_int_string *map) define_cleaner_function (json_map_int_string *, free_json_map_int_string) - json_map_int_string *make_json_map_int_string (yajl_val src, const struct parser_context *ctx, parser_error *err) +json_map_int_string * +make_json_map_int_string (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_int_string) json_map_int_string *ret = NULL; size_t i; @@ -1020,7 +1023,8 @@ free_json_map_string_int (json_map_string_int *map) define_cleaner_function (json_map_string_int *, free_json_map_string_int) - json_map_string_int *make_json_map_string_int (yajl_val src, const struct parser_context *ctx, parser_error *err) +json_map_string_int * +make_json_map_string_int (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_string_int) json_map_string_int *ret = NULL; size_t i; @@ -1181,7 +1185,8 @@ free_json_map_string_int64 (json_map_string_int64 *map) define_cleaner_function (json_map_string_int64 *, free_json_map_string_int64) - json_map_string_int64 *make_json_map_string_int64 (yajl_val src, const struct parser_context *ctx, +json_map_string_int64 * +make_json_map_string_int64 (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_string_int64) json_map_string_int64 *ret = NULL; @@ -1316,7 +1321,8 @@ free_json_map_string_bool (json_map_string_bool *map) define_cleaner_function (json_map_string_bool *, free_json_map_string_bool) - json_map_string_bool *make_json_map_string_bool (yajl_val src, const struct parser_context *ctx, parser_error *err) +json_map_string_bool * +make_json_map_string_bool (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_string_bool) json_map_string_bool *ret = NULL; size_t i; @@ -1485,7 +1491,8 @@ free_json_map_string_string (json_map_string_string *map) define_cleaner_function (json_map_string_string *, free_json_map_string_string) - json_map_string_string *make_json_map_string_string (yajl_val src, const struct parser_context *ctx, +json_map_string_string * +make_json_map_string_string (yajl_val src, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (free_json_map_string_string) json_map_string_string *ret = NULL; @@ -1498,7 +1505,7 @@ define_cleaner_function (json_map_string_string *, free_json_map_string_string) len = YAJL_GET_OBJECT_NO_CHECK (src)->len; - ret = malloc (sizeof (*ret)); + ret = calloc (sizeof (*ret), 1); if (ret == NULL) { *(err) = strdup ("error allocating memory"); @@ -1558,6 +1565,42 @@ define_cleaner_function (json_map_string_string *, free_json_map_string_string) return move_ptr (ret); } +json_map_string_string * +clone_map_string_string (json_map_string_string *src) +{ + __auto_cleanup (free_json_map_string_string) json_map_string_string *ret = NULL; + size_t i; + + if (src == NULL) + return NULL; + + ret = calloc (sizeof (*ret), 1); + if (ret == NULL) + return NULL; + + ret->len = src->len; + + ret->keys = calloc (src->len + 1, sizeof (char *)); + if (ret->keys == NULL) + return NULL; + + ret->values = calloc (src->len + 1, sizeof (char *)); + if (ret->values == NULL) + return NULL; + + for (i = 0; i < src->len; i++) + { + ret->keys[i] = strdup (src->keys[i]); + if (ret->keys[i] == NULL) + return NULL; + + ret->values[i] = strdup (src->values[i]); + if (ret->values[i] == NULL) + return NULL; + } + return move_ptr (ret); +} + int append_json_map_string_string (json_map_string_string *map, const char *key, const char *val) { @@ -1628,7 +1671,8 @@ cleanup_yajl_gen (yajl_gen g) define_cleaner_function (yajl_gen, cleanup_yajl_gen) - char *json_marshal_string (const char *str, size_t length, const struct parser_context *ctx, parser_error *err) +char * +json_marshal_string (const char *str, size_t length, const struct parser_context *ctx, parser_error *err) { __auto_cleanup (cleanup_yajl_gen) yajl_gen g = NULL; struct parser_context tmp_ctx = { 0 }; diff --git a/src/ocispec/json_common.h b/src/ocispec/json_common.h index 11f4a76b..41c73f59 100644 --- a/src/ocispec/json_common.h +++ b/src/ocispec/json_common.h @@ -220,6 +220,8 @@ typedef struct void free_json_map_string_string (json_map_string_string *map); +json_map_string_string *clone_map_string_string (json_map_string_string *src); + json_map_string_string *make_json_map_string_string (yajl_val src, const struct parser_context *ctx, parser_error *err); yajl_gen_status gen_json_map_string_string (void *ctx, const json_map_string_string *map, diff --git a/src/ocispec/sources.py b/src/ocispec/sources.py index f1c499d2..ebdd752c 100755 --- a/src/ocispec/sources.py +++ b/src/ocispec/sources.py @@ -37,9 +37,9 @@ def append_c_code(obj, c_file, prefix): History: 2019-06-17 """ parse_json_to_c(obj, c_file, prefix) - make_c_free (obj, c_file, prefix) + make_c_free(obj, c_file, prefix) get_c_json(obj, c_file, prefix) - + make_clone(obj, c_file, prefix) def parse_map_string_obj(obj, c_file, prefix, obj_typename): """ @@ -325,8 +325,8 @@ def parse_obj_arr_obj(obj, c_file, prefix, obj_typename): } for (i = 0; i < tree->u.object.len; i++) - {""" \ - f"if ({condition})" \ + {\n""" \ + f" if ({condition})" \ """{ if (ctx->options & OPT_PARSE_FULLKEY) { @@ -339,13 +339,12 @@ def parse_obj_arr_obj(obj, c_file, prefix, obj_typename): j++; } } - if (ctx->options & OPT_PARSE_STRICT) - { - if (j > 0 && ctx->errfile != NULL) - (void) fprintf (ctx->errfile, "WARNING: unknown key found\\n"); - } + + if ((ctx->options & OPT_PARSE_STRICT) && j > 0 && ctx->errfile != NULL) + (void) fprintf (ctx->errfile, "WARNING: unknown key found\\n"); + if (ctx->options & OPT_PARSE_FULLKEY) - ret->_residual = resi; + ret->_residual = resi; } """) @@ -647,6 +646,7 @@ def get_obj_arr_obj(obj, c_file, prefix): c_file.append(" GEN_SET_ERROR_AND_RETURN (stat, err);\n") c_file.append(" }\n") + def get_c_json(obj, c_file, prefix): """ Description: c language generate json file @@ -832,6 +832,149 @@ def read_val_generator(c_file, level, src, dest, typ, keyname, obj_typename): c_file.append(f'{" " * (level)}}}\n') +def make_clone(obj, c_file, prefix): + """ + Description: generate a clone operation for the specified object + Interface: None + History: 2024-09-03 + """ + + if not helpers.judge_complex(obj.typ) or obj.subtypname: + return + typename = helpers.get_prefixed_name(obj.name, prefix) + case = obj.typ + result = {'mapStringObject': lambda x: [], 'object': lambda x: x.children, + 'array': lambda x: x.subtypobj}[case](obj) + objs = result + if obj.typ == 'array': + if objs is None: + return + else: + typename = helpers.get_name_substr(obj.name, prefix) + + c_file.append(f"{typename} *\nclone_{typename} ({typename} *src)\n") + c_file.append("{\n") + c_file.append(f" __auto_cleanup(free_{typename}) {typename} *ret = NULL;\n") + + c_file.append(" ret = calloc (1, sizeof (*ret));\n") + c_file.append(" if (ret == NULL)\n") + c_file.append(" return NULL;\n") + + nodes = obj.children if obj.typ == 'object' else obj.subtypobj + for i in nodes or []: + if helpers.judge_data_type(i.typ) or i.typ == 'boolean': + c_file.append(f" ret->{i.fixname} = src->{i.fixname};\n") + c_file.append(f" ret->{i.fixname}_present = src->{i.fixname}_present;\n") + elif i.typ == 'object': + node_name = i.subtypname or helpers.get_prefixed_name(i.name, prefix) + c_file.append(f" if (src->{i.fixname})\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname} = clone_{node_name} (src->{i.fixname});\n") + c_file.append(f" if (ret->{i.fixname} == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" }}\n") + elif i.typ == 'string': + c_file.append(f" if (src->{i.fixname})\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname} = strdup (src->{i.fixname});\n") + c_file.append(f" if (ret->{i.fixname} == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" }}\n") + elif i.typ == 'array': + c_file.append(f" if (src->{i.fixname})\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname}_len = src->{i.fixname}_len;\n") + c_file.append(f" ret->{i.fixname} = calloc (src->{i.fixname}_len + 1, sizeof (*ret->{i.fixname}));\n") + c_file.append(f" if (ret->{i.fixname} == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" for (size_t i = 0; i < src->{i.fixname}_len; i++)\n") + c_file.append(f" {{\n") + if helpers.judge_data_type(i.subtyp) or i.subtyp == 'boolean': + c_file.append(f" ret->{i.fixname}[i] = src->{i.fixname}[i];\n") + elif i.subtyp == 'object': + subnode_name = i.subtypname or helpers.get_prefixed_name(i.name, prefix) + if False: # i.subtypname is not None: + typename = i.subtypname + c_file.append(f" ret->{i.fixname}[i] = clone_{typename} (src->{i.fixname}[i]);\n") + c_file.append(f" if (ret->{i.fixname}[i] == NULL)\n") + c_file.append(f" return NULL;\n") + else: + typename = helpers.get_prefixed_name(i.name, prefix) + if i.subtypname is not None: + typename = i.subtypname + maybe_element = "_element" if i.subtypname is None else "" + if i.doublearray: + c_file.append(f" ret->{i.fixname}_item_lens[i] = src->{i.fixname}_item_lens[i];\n") + c_file.append(f" ret->{i.fixname}[i] = calloc (ret->{i.fixname}_item_lens[i] + 1, sizeof (**ret->{i.fixname}[i]));\n") + c_file.append(f" if (ret->{i.fixname}[i] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" for (size_t j = 0; j < src->{i.fixname}_item_lens[i]; j++)\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname}[i][j] = clone_{typename}{maybe_element} (src->{i.fixname}[i][j]);\n") + c_file.append(f" if (ret->{i.fixname}[i][j] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" }}\n") + else: + c_file.append(f" ret->{i.fixname}[i] = clone_{typename}{maybe_element} (src->{i.fixname}[i]);\n") + c_file.append(f" if (ret->{i.fixname}[i] == NULL)\n") + c_file.append(f" return NULL;\n") + + elif i.subtyp == 'string': + if i.doublearray: + c_file.append(f" ret->{i.fixname}[i] = calloc (ret->{i.fixname}_item_lens[i] + 1, sizeof (**ret->{i.fixname}[i]));\n") + c_file.append(f" if (ret->{i.fixname}[i] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" for (size_t j = 0; j < src->{i.fixname}_item_lens[i]; j++)\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname}[i][j] = strdup (src->{i.fixname}[i][j]);\n") + c_file.append(f" if (ret->{i.fixname}[i][j] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" }}\n") + else: + c_file.append(f" if (src->{i.fixname}[i])\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname}[i] = strdup (src->{i.fixname}[i]);\n") + c_file.append(f" if (ret->{i.fixname}[i] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" }}\n") + else: + raise Exception("Unimplemented type for array clone: %s (%s)" % (i.subtyp, i.subtypname)) + c_file.append(f" }}\n") + c_file.append(f" }}\n") + elif i.typ == 'mapStringString': + c_file.append(f" ret->{i.fixname} = clone_map_string_string (src->{i.fixname});\n") + c_file.append(f" if (ret->{i.fixname} == NULL)\n") + c_file.append(f" return NULL;\n") + elif i.typ == 'mapStringObject': + c_file.append(f" if (src->{i.fixname})\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname} = calloc (1, sizeof ({i.subtypname}));\n") + c_file.append(f" if (ret->{i.fixname} == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" ret->{i.fixname}->len = src->{i.fixname}->len;\n") + c_file.append(f" ret->{i.fixname}->keys = calloc (src->{i.fixname}->len + 1, sizeof (char *));\n") + c_file.append(f" if (ret->{i.fixname}->keys == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" ret->{i.fixname}->values = calloc (src->{i.fixname}->len + 1, sizeof (*ret->{i.fixname}->values));\n") + c_file.append(f" if (ret->{i.fixname}->values == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" for (size_t i = 0; i < ret->{i.fixname}->len; i++)\n") + c_file.append(f" {{\n") + c_file.append(f" ret->{i.fixname}->keys[i] = strdup (src->{i.fixname}->keys[i]);\n") + c_file.append(f" if (ret->{i.fixname}->keys[i] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" ret->{i.fixname}->values[i] = clone_{i.subtypname}_element (src->{i.fixname}->values[i]);\n") + c_file.append(f" if (ret->{i.fixname}->values[i] == NULL)\n") + c_file.append(f" return NULL;\n") + c_file.append(f" }}\n") + c_file.append(f" }}\n") + else: + raise Exception("Unimplemented type for clone: %s" % i.typ) + + c_file.append(f" return move_ptr (ret);\n") + c_file.append("}\n\n") + + def json_value_generator(c_file, level, src, dst, ptx, typ): """ Description: json value generateor diff --git a/tests/test-1.c b/tests/test-1.c index 705c021f..6e35b424 100644 --- a/tests/test-1.c +++ b/tests/test-1.c @@ -86,6 +86,9 @@ main () if (container->linux->seccomp == NULL || container->linux->seccomp->flags == NULL || container->linux->seccomp->flags_len != 0) exit (5); + free_runtime_spec_schema_config_schema (clone_runtime_spec_schema_config_schema (container)); + free_runtime_spec_schema_config_schema_process (clone_runtime_spec_schema_config_schema_process (container->process)); + free(json_buf); free_runtime_spec_schema_config_schema (container); free_runtime_spec_schema_config_schema (container_gen); diff --git a/tests/test-8.c b/tests/test-8.c index ecea86a4..f066660a 100644 --- a/tests/test-8.c +++ b/tests/test-8.c @@ -22,12 +22,11 @@ along with libocispec. If not, see . #include #include "ocispec/image_manifest_items_image_manifest_items_schema.h" - int main () { parser_error err = NULL; - image_manifest_items_image_manifest_items_schema_container *image_items = + image_manifest_items_image_manifest_items_schema_container *image_items = image_manifest_items_image_manifest_items_schema_container_parse_file ("tests/data/image_manifest_item.json", 0, &err); image_manifest_items_image_manifest_items_schema_container *image_items_gen = NULL; char *json_buf = NULL;