core-lightning/tools/gen/impl_template
Rusty Russell 83ee68ab06 common/tlvstream: put TLV checking back in the generic function.
Callers were supposed to call "tlv_fields_valid" after fromwire_tlv,
but few did.  Make this the default, and call the underlying function
directly where we want to be more flexible (one place).

This loses the ability to allow misordered fields, or to pass through
*any* even fields.  We restore that for special cases in the next
patch.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2022-03-25 13:55:44 +10:30

400 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():
for (size_t i = 0; *plen != 0; i++) {
% 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_}(${ctx}, 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}void 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};
% 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