From 5320cab2de86d12a373d9c06d3e123696ac997d3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 3 Nov 2017 10:40:57 +1030 Subject: [PATCH] generate-wire.py: create structures for optional fields. If a structure foo has a optional fields opt1 and opt2, this creates towire_foo, towire_foo_opt1 and towire_foo_opt2 (since opt2 implies opt1), similarly for fromwire_*. This requires the callers to be updated to call the correct routines (eg. try fromwire_foo_opt2, then fromwire_foo_opt1, then finally fromwire_foo), but this is a minimal change to the generation code. Signed-off-by: Rusty Russell --- tools/generate-wire.py | 63 ++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/tools/generate-wire.py b/tools/generate-wire.py index c203f6dee..9a66768f9 100755 --- a/tools/generate-wire.py +++ b/tools/generate-wire.py @@ -2,6 +2,7 @@ # Read from stdin, spit out C header or body. import argparse +import copy from collections import namedtuple import fileinput import re @@ -387,6 +388,28 @@ class Message(object): subcalls='\n'.join(subcalls), ) +def find_message(messages, name): + for m in messages: + if m.name == name: + return m + + return None + +def find_message_with_option(messages, optional_messages, name, option): + fullname = name + "_" + option; + + base = find_message(messages, name) + if not base: + raise ValueError('Unknown message {}'.format(name)) + + m = find_message(optional_messages, name) + if not m: + # Add a new option. + m = copy.deepcopy(base) + m.name = fullname + optional_messages.append(m) + return m + parser = argparse.ArgumentParser(description='Generate C from from CSV') parser.add_argument('--header', action='store_true', help="Create wire header") parser.add_argument('--bolt', action='store_true', help="Generate wire-format for BOLT") @@ -397,6 +420,7 @@ options = parser.parse_args() # Maps message names to messages messages = [] +messages_with_option = [] comments = [] includes = [] prevfield = None @@ -423,22 +447,27 @@ for line in fileinput.input(options.files): messages.append(Message(parts[0],Enumtype("WIRE_" + parts[0].upper(), parts[1]), comments)) comments=[] prevfield = None - elif len(parts) == 4: - # eg commit_sig,0,channel-id,8 OR - # commit_sig,0,channel-id,u64 - for m in messages: - if m.name == parts[0]: - f = Field(parts[0], parts[2], parts[3], comments, prevfield) - m.addField(f) - # If it used prevfield as lenvar, keep that for next - # time (multiple fields can use the same lenvar). - if not f.lenvar: - prevfield = parts[2] - break - comments=[] else: - raise ValueError('Line {} malformed'.format(line.rstrip())) - + if len(parts) == 4: + # eg commit_sig,0,channel-id,8 OR + # commit_sig,0,channel-id,u64 + m = find_message(messages, parts[0]) + if m is None: + raise ValueError('Unknown message {}'.format(name)) + elif len(parts) == 5: + # eg. + # channel_reestablish,48,your_last_per_commitment_secret,32,option209 + m = find_message_with_option(messages, messages_with_option, parts[0], parts[4]) + else: + raise ValueError('Line {} malformed'.format(line.rstrip())) + + f = Field(m.name, parts[2], parts[3], comments, prevfield) + m.addField(f) + # If it used prevfield as lenvar, keep that for next + # time (multiple fields can use the same lenvar). + if not f.lenvar: + prevfield = parts[2] + comments=[] header_template = """#ifndef LIGHTNING_{idem} #define LIGHTNING_{idem} @@ -485,8 +514,8 @@ for m in messages: includes = '\n'.join(includes) cases = ['case {enum.name}: return "{enum.name}";'.format(enum=m.enum) for m in messages] -fromwire_decls = [m.print_fromwire(options.header) for m in messages] -towire_decls = [m.print_towire(options.header) for m in messages] +fromwire_decls = [m.print_fromwire(options.header) for m in messages + messages_with_option] +towire_decls = [m.print_towire(options.header) for m in messages + messages_with_option] print(template.format( headerfilename=options.headerfilename,