Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generate: generate clone operations for deep-copy #135

Merged
merged 2 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 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 Expand Up @@ -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)
Expand Down
62 changes: 53 additions & 9 deletions src/ocispec/json_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 };
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
163 changes: 153 additions & 10 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 @@ -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)
{
Expand All @@ -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;
}
""")

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
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
Loading