Skip to content

Commit

Permalink
generate: generate clone operations for deep-copy
Browse files Browse the repository at this point in the history
Signed-off-by: Giuseppe Scrivano <[email protected]>
  • Loading branch information
giuseppe committed Sep 5, 2024
1 parent d371222 commit 3ec73ba
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/ocispec/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
38 changes: 37 additions & 1 deletion src/ocispec/json_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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)
{
Expand Down
2 changes: 2 additions & 0 deletions src/ocispec/json_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
148 changes: 146 additions & 2 deletions src/ocispec/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions tests/test-1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions tests/test-8.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ along with libocispec. If not, see <http://www.gnu.org/licenses/>.
#include <string.h>
#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;
Expand Down

0 comments on commit 3ec73ba

Please sign in to comment.