core-lightning/tools/gen/impl_template
Rusty Russell 38d229df3d tools/generate-wire.py: make sure TLV array fields are allocated off TLV.
Otherwise the whole thing cannot be tal_steal() onto a different parent.

Here's the difference in generated files:

   --- ./wire/onion_wiregen.c.pre	2024-10-23 12:26:09.023176933 +1030
   +++ ./wire/onion_wiregen.c	2024-10-23 12:26:52.434828303 +1030
   @@ -128,7 +128,7 @@
     	blinded_path->path = num_hops ? tal_arr(blinded_path, struct blinded_path_hop *, 0) : NULL;
    	for (size_t i = 0; i < num_hops; i++) {
    		struct blinded_path_hop * tmp;
   -		tmp = fromwire_blinded_path_hop(blinded_path, cursor, plen);
   +		tmp = fromwire_blinded_path_hop(blinded_path->path, cursor, plen);
    		tal_arr_expand(&blinded_path->path, tmp);
    	}
    
   --- ./wire/bolt12_wiregen.c.pre	2024-10-23 12:26:09.079176474 +1030
   +++ ./wire/bolt12_wiregen.c	2024-10-23 12:26:52.612826902 +1030
   @@ -316,7 +316,7 @@
    	r->offer_paths = *plen ? tal_arr(r, struct blinded_path *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_path * tmp;
   -		tmp = fromwire_blinded_path(r, cursor, plen);
   +		tmp = fromwire_blinded_path(r->offer_paths, cursor, plen);
    		tal_arr_expand(&r->offer_paths, tmp);
    	}
    }
   @@ -729,7 +729,7 @@
    	r->offer_paths = *plen ? tal_arr(r, struct blinded_path *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_path * tmp;
   -		tmp = fromwire_blinded_path(r, cursor, plen);
   +		tmp = fromwire_blinded_path(r->offer_paths, cursor, plen);
    		tal_arr_expand(&r->offer_paths, tmp);
    	}
    }
   @@ -1052,7 +1052,7 @@
    	r->invreq_paths = *plen ? tal_arr(r, struct blinded_path *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_path * tmp;
   -		tmp = fromwire_blinded_path(r, cursor, plen);
   +		tmp = fromwire_blinded_path(r->invreq_paths, cursor, plen);
    		tal_arr_expand(&r->invreq_paths, tmp);
    	}
    }
   @@ -1385,7 +1385,7 @@
    	r->offer_paths = *plen ? tal_arr(r, struct blinded_path *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_path * tmp;
   -		tmp = fromwire_blinded_path(r, cursor, plen);
   +		tmp = fromwire_blinded_path(r->offer_paths, cursor, plen);
    		tal_arr_expand(&r->offer_paths, tmp);
    	}
    }
   @@ -1708,7 +1708,7 @@
    	r->invreq_paths = *plen ? tal_arr(r, struct blinded_path *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_path * tmp;
   -		tmp = fromwire_blinded_path(r, cursor, plen);
   +		tmp = fromwire_blinded_path(r->invreq_paths, cursor, plen);
    		tal_arr_expand(&r->invreq_paths, tmp);
    	}
    }
   @@ -1781,7 +1781,7 @@
    	r->invoice_paths = *plen ? tal_arr(r, struct blinded_path *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_path * tmp;
   -		tmp = fromwire_blinded_path(r, cursor, plen);
   +		tmp = fromwire_blinded_path(r->invoice_paths, cursor, plen);
    		tal_arr_expand(&r->invoice_paths, tmp);
    	}
    }
   @@ -1808,7 +1808,7 @@
    	r->invoice_blindedpay = *plen ? tal_arr(r, struct blinded_payinfo *, 0) : NULL;
    	while (*plen != 0) {
    		struct blinded_payinfo * tmp;
   -		tmp = fromwire_blinded_payinfo(r, cursor, plen);
   +		tmp = fromwire_blinded_payinfo(r->invoice_blindedpay, cursor, plen);
    		tal_arr_expand(&r->invoice_blindedpay, tmp);
    	}
    }
   @@ -1927,7 +1927,7 @@
    	r->invoice_fallbacks = *plen ? tal_arr(r, struct fallback_address *, 0) : NULL;
    	while (*plen != 0) {
    		struct fallback_address * tmp;
   -		tmp = fromwire_fallback_address(r, cursor, plen);
   +		tmp = fromwire_fallback_address(r->invoice_fallbacks, cursor, plen);
    		tal_arr_expand(&r->invoice_fallbacks, tmp);
    	}
    }
   
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2024-11-18 11:03:26 +10:30

403 lines
12 KiB
Plaintext

/* This file was generated by generate-wire.py */
/* Do not modify this file! Modify the .csv file it was generated from. */
/* Original template can be found at tools/gen/impl_template */
#include <${header_filename}>
#include <assert.h>
#include <ccan/array_size/array_size.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/utils.h>
#include <stdio.h>
% for i in includes:
${i}
% endfor
#ifndef SUPERVERBOSE
#define SUPERVERBOSE(...)
#endif
% for comment in top_comments:
/*${comment} */
% endfor
% for enum_set in enum_sets:
const char *${enum_set['name']}_name(int e)
{
static char invalidbuf[sizeof("INVALID ") + STR_MAX_CHARS(e)];
switch ((enum ${enum_set['name']})e) {
% for msg in enum_set['set']:
case ${msg.enum_name()}: return "${msg.enum_name()}";
% endfor
}
snprintf(invalidbuf, sizeof(invalidbuf), "INVALID %i", e);
return invalidbuf;
}
bool ${enum_set['name']}_is_defined(u16 type)
{
switch ((enum ${enum_set['name']})type) {
% for msg in enum_set['set']:
case ${msg.enum_name()}:;
% endfor
return true;
}
return false;
}
% endfor
## START PARTIALS
## Subtype and TLV-msg towire_
<%def name="towire_subtype_field(fieldname, f, type_obj, is_single_ptr, ptr)">\
% if f.is_array() or f.is_varlen():
% if type_obj.has_array_helper():
towire_${type_obj.name}_array(${ptr}, ${fieldname}, ${f.size('tal_count(' + fieldname + ')')});
% else:
for (size_t i = 0; i < ${f.size('tal_count(' + fieldname + ')')}; i++)
% if type_obj.is_assignable() or type_obj.is_varsize():
towire_${type_obj.name}(${ptr}, ${fieldname}[i]);
% else:
towire_${type_obj.name}(${ptr}, ${fieldname} + i);
% endif
% endif
% elif f.len_field_of:
towire_${type_obj.name}(${ptr}, ${f.name});
% elif is_single_ptr:
towire_${type_obj.name}(${ptr}, ${'*' if type_obj.is_assignable() else ''}${fieldname});
% else:
towire_${type_obj.name}(${ptr}, ${'' if type_obj.is_assignable() or type_obj.is_varsize() else '&'}${fieldname});
% endif
</%def>
## Subtype and TLV-msg fromwire
<%def name="fromwire_subtype_field(fieldname, f, ctx, is_ptr)">\
<%
type_ = f.type_obj.name
typename = f.type_obj.type_name()
if f.type_obj.is_varsize():
typename += ' *'
%>\
% if f.is_array() or f.is_varlen():
% if f.type_obj.has_array_helper():
## We assume array helpers only deal with things literally transcribed!!
% if f.is_varlen():
${fieldname} = tal_arr(${ctx}, ${typename}, ${f.size('*plen')});
% endif
fromwire_${type_}_array(cursor, plen, ${fieldname}, ${f.size('*plen')});
% else:
% if f.is_varlen():
${fieldname} = ${f.size('*plen')} ? tal_arr(${ctx}, ${typename}, 0) : NULL;
% endif
% if f.is_implicit_len():
while (*plen != 0) {
% else:
for (size_t i = 0; i < ${f.size()}; i++) {
% endif
${typename} tmp;
% if f.type_obj.is_assignable():
tmp = fromwire_${type_}(cursor, plen);
% elif f.is_varlen() and f.type_obj.is_varsize():
tmp = fromwire_${type_}(${fieldname}, cursor, plen);
% else:
fromwire_${type_}(cursor, plen, &tmp);
% endif
tal_arr_expand(&${fieldname}, tmp);
}
% endif
% else:
% if is_ptr:
${fieldname} = tal(${ctx}, ${typename});
<% fieldname = '*' + fieldname %>
% endif
% if f.type_obj.is_assignable():
${ f.name if f.len_field_of else fieldname} = fromwire_${type_}(cursor, plen);
% elif f.type_obj.is_varsize():
${fieldname} = fromwire_${type_}(${ctx}, cursor, plen);
% else:
fromwire_${type_}(cursor, plen, &${fieldname});
% endif
%endif
</%def>
## END PARTIALS
## FIXME: extract out partials for the method declarations
## (shared between here and header_template)
% for subtype in subtypes: ## START Subtypes
/* SUBTYPE: ${subtype.name.upper()} */
% for c in subtype.type_comments:
/*${c} */
% endfor
<%
static = '' if options.expose_subtypes else 'static '
%>\
${static}void towire_${subtype.name}(u8 **p, const ${subtype.type_name()} *${subtype.name})
{
% for f in subtype.get_len_fields():
${f.type_obj.type_name()} ${f.name} = tal_count(${subtype.name}->${f.len_field_of});
% endfor
% for f in subtype.fields.values():
% for c in f.field_comments:
/*${c} */
% endfor
<%
fieldname = '{}->{}'.format(subtype.name,f.name)
%>\
${towire_subtype_field(fieldname, f, f.type_obj, False, 'p')}\
% endfor
}
% if subtype.is_varsize():
${static}${subtype.type_name()} *
fromwire_${subtype.name}(const tal_t *ctx, const u8 **cursor, size_t *plen)
% else:
${static}bool fromwire_${subtype.name}(${'const tal_t *ctx, ' if subtype.needs_context() else ''}const u8 **cursor, size_t *plen, ${subtype.type_name()} *${subtype.name})
% endif
{
% if subtype.is_varsize():
${subtype.type_name()} *${subtype.name} = tal(ctx, ${subtype.type_name()});
% endif
## Length field declarations
% for f in subtype.get_len_fields():
${f.type_obj.type_name()} ${f.name};
% endfor
% for f in subtype.fields.values():
% for c in f.field_comments:
/*${c} */
% endfor
<%
fieldname = '{}->{}'.format(subtype.name,f.name)
ctx = subtype.name
%> \
${fromwire_subtype_field(fieldname, f, ctx, False)}\
% endfor
% if subtype.is_varsize():
return ${subtype.name};
% else:
return *cursor != NULL;
% endif
}
% endfor ## END Subtypes
<%def name="fromwire_phrase(f, type_, varsized)" >\
%if f.type_obj.is_assignable():
*${f.name} = fromwire_${type_}(&cursor, &plen);
% elif varsized:
*${f.name} = fromwire_${type_}(ctx, &cursor, &plen);
% else:
fromwire_${type_}(${'ctx, ' if f.needs_context() else ''}&cursor, &plen, ${'*' if f.is_optional else ''}${f.name});
% endif
</%def>
% for tlv in tlvs.values(): ## START TLV's
${tlv.type_name()} *${tlv.struct_name()}_new(const tal_t *ctx)
{
/* Initialize everything to NULL. (Quiet, C pedants!) */
${tlv.type_name()} *inst = talz(ctx, struct ${tlv.struct_name()});
/* Initialized the fields to an empty array. */
inst->fields = tal_arr(inst, struct tlv_field, 0);
return inst;
}
% for msg in tlv.messages.values():
/* ${tlv.name.upper()} MSG: ${msg.name} */
static u8 *towire_${msg.struct_name()}(const tal_t *ctx, const void *vrecord)
{
const struct ${tlv.struct_name()} *r = vrecord;
u8 *ptr;
if (!r->${msg.name})
return NULL;
% for f in msg.get_len_fields():
${f.type_obj.type_name()} ${f.name} = tal_count(r->${msg.name}->${f.len_field_of});
% endfor
ptr = tal_arr(ctx, u8, 0);
% for f in msg.fields.values():
<%
if msg.singleton():
fieldname = 'r->{}'.format(msg.name)
type_obj = msg.singleton().type_obj
else:
fieldname = 'r->{}->{}'.format(msg.name, f.name)
type_obj = f.type_obj
%>
${towire_subtype_field(fieldname, f, type_obj, msg.singleton(), '&ptr')}\
% endfor
return ptr;
}
static void fromwire_${msg.struct_name()}(const u8 **cursor, size_t *plen, void *vrecord)
{
struct ${tlv.struct_name()} *r = vrecord;
## Length field declarations
% for f in msg.get_len_fields():
${f.type_obj.type_name()} ${f.name};
% endfor
% if not msg.singleton():
r->${msg.name} = tal(r, struct ${msg.struct_name()});
% endif
% for f in msg.fields.values():
<%
if msg.singleton():
fieldname = 'r->{}'.format(msg.name)
ctx = 'r'
else:
fieldname = 'r->{}->{}'.format(msg.name, f.name)
ctx = 'r->{}'.format(msg.name)
%>\
${fromwire_subtype_field(fieldname, f, ctx, msg.singleton() and not f.type_obj.is_varsize())}\
% endfor
}
% endfor
<% static = '' if tlv.name in options.expose_tlv_type else 'static '
%>\
${static}const struct tlv_record_type tlvs_${tlv.name}[] = {
% for msg in tlv.ordered_msgs():
{ ${msg.number}, towire_${msg.struct_name()}, fromwire_${msg.struct_name()} },
% endfor
};
void towire_${tlv.name}(u8 **pptr, const struct ${tlv.struct_name()} *record)
{
towire_tlv(pptr, tlvs_${tlv.name}, ${len(tlv.messages)}, record);
}
struct ${tlv.name} *fromwire_${tlv.name}(const tal_t *ctx, const u8 **cursor, size_t *max)
{
struct ${tlv.name} *record = ${tlv.name}_new(ctx);
if (!fromwire_tlv(cursor, max, tlvs_${tlv.name}, ${len(tlv.messages)}, record, &record->fields, NULL, NULL, NULL))
return tal_free(record);
return record;
}
% endfor ## END TLV's
% for msg in messages: ## START Wire Messages
% if msg.if_token:
#if ${msg.if_token}
% endif
/* WIRE: ${msg.name.upper()} */
% for c in msg.msg_comments:
/*${c} */
% endfor
u8 *towire_${msg.name}(const tal_t *ctx${''.join([f.arg_desc_to() for f in msg.fields.values()])})
{
## FIXME: we're ignoring TLV's rn
% for f in msg.get_len_fields():
${f.type_obj.type_name()} ${f.name} = tal_count(${f.len_field_of});
% endfor
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, ${msg.enum_name()});
% for f in msg.fields.values():
% for c in f.field_comments:
/*${c} */
% endfor
% if f.is_array() or f.is_varlen():
% if f.type_obj.has_array_helper():
towire_${f.type_obj.name}_array(&p, ${f.name}, ${f.size('tal_count(' + f.name + ')')});
% else:
for (size_t i = 0; i < ${f.size('tal_count(' + f.name + ')')}; i++)
% if f.type_obj.is_assignable() or f.type_obj.is_varsize():
towire_${f.type_obj.name}(&p, ${f.name}[i]);
% else:
towire_${f.type_obj.name}(&p, ${f.name} + i);
% endif
% endif
% elif f.type_obj.is_tlv():
towire_${f.type_obj.tlv.name}(&p, ${f.name});
% elif f.is_optional: ## is optional?
if (!${f.name})
towire_bool(&p, false);
else {
towire_bool(&p, true);
towire_${f.type_obj.name}(&p, ${'*' if f.type_obj.is_assignable() else ''}${f.name});
}
% else: ## all other cases
towire_${f.type_obj.name}(&p, ${f.name});
% endif
% endfor
return memcheck(p, tal_count(p));
}
bool fromwire_${msg.name}(${'const tal_t *ctx, ' if msg.needs_context() else ''}const void *p${''.join([f.arg_desc_from() for f in msg.fields.values()])})
{
% if msg.get_len_fields():
% for f in msg.get_len_fields():
${f.type_obj.type_name()} ${f.name};
% endfor
% endif
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != ${msg.enum_name()})
return false;
% for f in msg.fields.values():
<%
typename = f.type_obj.type_name()
if f.type_obj.is_varsize():
typename = typename + ' *'
type_ = f.type_obj.name
varsized = f.type_obj.is_varsize() or f.type_obj.is_tlv()
%> \
% for c in f.field_comments:
/*${c} */
% endfor
% if f.is_varlen():
// 2nd case ${f.name}
*${f.name} = ${f.size('plen')} ? tal_arr(ctx, ${typename}, ${f.size('plen')}) : NULL;
% endif
% if f.len_field_of:
${f.name} = fromwire_${type_}(&cursor, &plen);
% elif f.type_obj.is_tlv():
*${f.name} = fromwire_${f.type_obj.tlv.name}(ctx, &cursor, &plen);
if (!*${f.name})
return false;
% elif f.is_array() or f.is_varlen():
% if f.type_obj.has_array_helper():
fromwire_${type_}_array(&cursor, &plen, ${'*' if f.is_varlen() else ''}${f.name}, ${f.size('plen')});
% else:
% if f.is_implicit_len():
for (size_t i = 0; plen != 0; i++)
% else:
for (size_t i = 0; i < ${f.size()}; i++)
% endif
% if not varsized and not f.type_obj.is_assignable():
% if f.is_varlen():
fromwire_${type_}(&cursor, &plen, *${f.name} + i);
% else:
fromwire_${type_}(&cursor, &plen, &(${f.name}[i]));
% endif
% else:
(${'' if f.type_obj.is_assignable() and f.is_array() else '*'}${f.name})[i] = fromwire_${type_}(${'*'+f.name+', ' if varsized else ''}&cursor, &plen);
% endif
% endif
% else:
% if not f.is_optional:
${fromwire_phrase(f, type_, varsized)}\
% else: ## Start optional
if (!fromwire_bool(&cursor, &plen))
*${f.name} = NULL;
else {
% if not varsized:
*${f.name} = tal(ctx, ${typename});
% endif
${'*' if f.type_obj.is_assignable() else ''}${fromwire_phrase(f, type_, varsized)}\
}
% endif ## End optional
% endif
% endfor
return cursor != NULL;
}
% if msg.if_token:
#endif /* ${msg.if_token} */
% endif
% endfor ## END Wire Messages