Navigation


Changeset 1498:01efba83bf60 in freeDiameter for contrib


Ignore:
Timestamp:
Apr 3, 2020, 9:37:26 AM (4 years ago)
Author:
Luke Mewburn <luke@mewburn.net>
Branch:
default
Phase:
public
committer:
Luke Mewburn <luke@mewburn.net> 1585876473 -39600
Message:

csv_to_fd: fdc generate complete file

fdc: Generate a file with a function to create the DICT_AVP
entries, instead of a function snippet.

Processor: provide parameter() method for implementations.
Rename next_file() to filename().

File:
1 edited

Legend:

Unmodified
Added
Removed
  • contrib/tools/csv_to_fd

    r1494 r1498  
    205205
    206206    @abc.abstractmethod
    207     def next_file(self, filename):
     207    def filename(self, filename):
    208208        """Called when a file is opened."""
    209209        pass
     
    226226        pass
    227227
     228    @abc.abstractmethod
     229    def parameter(self, name, value):
     230        """Process a parameter row:
     231            @name,value.
     232        """
     233        pass
     234
    228235
    229236class DebugProcessor(Processor):
    230237    """Display the CSV parsing."""
    231238
    232     def next_file(self, filename):
     239    def filename(self, filename):
    233240        print('File: {}'.format(filename))
    234241
     
    243250        print('Generate')
    244251
     252    def parameter(self, name, value):
     253        print('Parameter: {} {}'.format(name, value))
     254
    245255
    246256class NoopProcessor(Processor):
    247257    """Validate the CSV; no other output."""
    248258
    249     def next_file(self, filename):
     259    def filename(self, filename):
    250260        pass
    251261
     
    257267
    258268    def generate(self):
     269        pass
     270
     271    def parameter(self, name, value):
    259272        pass
    260273
     
    271284    COMMENT_WIDTH = 64
    272285
     286    class AvpFunction(object):
     287        """Maintain per-function state to create DICT_AVP entries.
     288        """
     289
     290        def __init__(self, name):
     291            self.__name = name
     292            self.__lines = []
     293            self.__derived = set()
     294
     295        @property
     296        def name(self):
     297            """Return name."""
     298            return self.__name
     299
     300        @property
     301        def lines(self):
     302            """Return all lines."""
     303            return self.__lines
     304
     305        @lines.setter
     306        def lines(self, value):
     307            """Set to append a line."""
     308            self.__lines.append(value)
     309
     310        @property
     311        def derived(self):
     312            """Return list of all derived values."""
     313            return list(self.__derived)
     314
     315        @derived.setter
     316        def derived(self, value):
     317            """Set to store a derived type."""
     318            self.__derived.add(value)
     319
    273320    def __init__(self):
    274         self.filenames = []
    275         self.lines = []
    276 
    277     def next_file(self, filename):
    278         self.filenames.append(os.path.basename(filename))
     321        self._filenames = []
     322        self._functions = collections.OrderedDict()
     323
     324    def filename(self, filename):
     325        self._filenames.append(os.path.basename(filename))
    279326
    280327    def avp(self, avp):
     
    312359        elif avp.datatype in DERIVED_TO_BASE:
    313360            avp_type = '{}_type'.format(avp.datatype)
     361            self.derived(avp.datatype)
    314362        self.add('\t\tCHECK_dict_new(DICT_AVP, &data, {}, NULL);'.format(
    315363            avp_type))
     
    329377
    330378    def generate(self):
    331         self.print_header()
    332         self.print_comment('Start of generated data.')
    333         self.print_comment('')
    334         self.print_comment('The following is created automatically with:')
    335         self.print_comment('    csv_to_fd -p {} {}'.format(
    336             self.cls_name(), ' '.join(self.filenames)))
    337         self.print_comment('Changes will be lost during the next update.')
    338         self.print_comment('Do not modify;'
    339                            ' modify the source .csv file instead.')
    340         self.print_header()
    341         print('')
    342         print('\n'.join(self.lines))
    343         self.print_header()
    344         self.print_comment('End of generated data.')
    345         self.print_header()
     379        fp = sys.stdout
     380        self.write_introduction(fp)
     381        for func in self._functions:
     382            self.write_function(fp, self._functions[func])
     383
     384    def parameter(self, name, value):
     385        pass
     386
     387    # internal methods
     388
     389    def current_avpfunction(self):
     390        """Return current AvpFunction to update.
     391
     392        Note: allows for easier future enhancement to generate separate
     393        C functions per AVP groups such as: by csv file, standard, or vendor.
     394        """
     395        name = 'add_avps'
     396        if name not in self._functions:
     397            self._functions[name] = self.AvpFunction(name)
     398        return self._functions[name]
     399
     400    def add(self, line):
     401        self.current_avpfunction().lines = line
     402
     403    def derived(self, value):
     404        self.current_avpfunction().derived = value
     405
     406    def build_c_token(self, value):
     407        """Convert a string into a valid C token."""
     408        return re.sub(r'[^\w]', '_', value)
    346409
    347410    def build_flags(self, flags):
     
    353416        return ' |'.join(result)
    354417
    355     def add(self, line):
    356         self.lines.append(line)
    357 
    358418    def add_comment(self, comment):
    359         self.lines.append(self.format_comment(comment))
     419        self.add(self.format_comment(comment))
    360420
    361421    def add_header(self):
    362         self.lines.append(self.format_header())
     422        self.add(self.format_header())
    363423
    364424    def format_comment(self, comment):
     
    368428        return '\t/*={:=<{width}}=*/'.format('', width=self.COMMENT_WIDTH)
    369429
    370     def print_comment(self, comment):
    371         print(self.format_comment(comment))
    372 
    373     def print_header(self):
    374         print(self.format_header())
     430    def write_introduction(self, fp):
     431        """Write the introduction to the generated file."""
     432        fp.write('''\
     433/*
     434Generated by:
     435\tcsv_to_fd -p {processor} {files}
     436
     437Do not modify; modify the source .csv files instead.
     438*/
     439
     440#include <freeDiameter/extension.h>
     441
     442#define CHECK_dict_new( _type, _data, _parent, _ref ) \\
     443\tCHECK_FCT(  fd_dict_new( fd_g_config->cnf_dict, \
     444(_type), (_data), (_parent), (_ref))  );
     445
     446#define CHECK_dict_search( _type, _criteria, _what, _result ) \\
     447\tCHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, \
     448(_type), (_criteria), (_what), (_result), ENOENT) );
     449'''.format(
     450            processor=self.cls_name(),
     451            files=' '.join(self._filenames)))
     452
     453    def write_function(self, fp, avpfunction):
     454        """Generate a function from AvpFunction."""
     455        function = self.build_c_token(avpfunction.name)
     456        # Function start
     457        fp.write('''\
     458
     459int {}()
     460{{
     461'''.format(function))
     462
     463        # Create variables used by derived type validation
     464        for derived in avpfunction.derived:
     465            fp.write('''\
     466\tstruct dict_object * {name}_type = NULL;
     467\tCHECK_dict_search(DICT_TYPE, TYPE_BY_NAME, "{name}", &{name}_type);
     468
     469'''.format(name=derived))
     470
     471        # Write generated DICT_AVP creation
     472        fp.write('\n'.join(avpfunction.lines))
     473
     474        # Write function end
     475        fp.write('''\
     476
     477\treturn 0;
     478}} /* {}() */
     479'''.format(function))
    375480
    376481
     
    382487        self.avps = []
    383488
    384     def next_file(self, filename):
     489    def filename(self, filename):
    385490        pass
    386491
     
    405510        doc = {"AVPs": self.avps}
    406511        print(json.dumps(doc, indent=2))
     512
     513    def parameter(self, name, value):
     514        pass
    407515
    408516    def build_flags(self, flags):
     
    467575into various formats using the specified processor PROCESSOR.
    468576""")
    469 
    470577    parser.add_option(
    471578        '-p', '--processor',
     
    491598    # Process files
    492599    for filename in args:
    493         avpproc.next_file(filename)
     600        avpproc.filename(filename)
    494601        with open(filename, 'r') as csvfile:
    495602            csvdata = csv.DictReader(csvfile, CSV_COLUMN_NAMES,
     
    517624                            raise ValueError('Unknown parameter "{}"'.format(
    518625                                parameter))
     626                        avpproc.parameter(parameter, value)
    519627                    else:
    520628                        avp = Avp(filename=filename, line_num=csvdata.line_num,
Note: See TracChangeset for help on using the changeset viewer.