From 3ec73ba749dfd03595437442bb04c275f7a31c59 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 4 Sep 2024 23:42:06 +0200 Subject: [PATCH] generate: generate clone operations for deep-copy Signed-off-by: Giuseppe Scrivano --- src/ocispec/headers.py | 1 + src/ocispec/json_common.c | 38 +++++++++- src/ocispec/json_common.h | 2 + src/ocispec/sources.py | 148 +++++++++++++++++++++++++++++++++++++- tests/test-1.c | 3 + tests/test-8.c | 3 +- 6 files changed, 190 insertions(+), 5 deletions(-) diff --git a/src/ocispec/headers.py b/src/ocispec/headers.py index c8af2fe9..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") diff --git a/src/ocispec/json_common.c b/src/ocispec/json_common.c index 9fde1326..a8d742a7 100644 --- a/src/ocispec/json_common.c +++ b/src/ocispec/json_common.c @@ -1505,7 +1505,7 @@ make_json_map_string_string (yajl_val src, const struct parser_context *ctx, 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"); @@ -1565,6 +1565,42 @@ make_json_map_string_string (yajl_val src, const struct parser_context *ctx, 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) { 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 c7d479df..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): """ @@ -646,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 @@ -831,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;