123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- #!@PYTHON@
- # Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- #
- # Permission to use, copy, modify, and/or distribute this software for any
- # purpose with or without fee is hereby granted, provided that the above
- # copyright notice and this permission notice appear in all copies.
- #
- # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- # PERFORMANCE OF THIS SOFTWARE.
- """\
- This is a supplemental script to (half) auto-generate DNS Rdata related
- classes and constants.
- """
- import os
- from os.path import getmtime
- import re
- import sys
- # new_rdata_factory_users[] is a list of tuples of the form (rrtype,
- # rrclass). Items in the list use the (new) RdataFactory class, and
- # items which are not in the list use OldRdataFactory class.
- # Note: rrtype and rrclass must be specified in lowercase in
- # new_rdata_factory_users.
- #
- # Example:
- # new_rdata_factory_users = [('a', 'in'), ('a', 'ch'), ('soa', 'generic')]
- new_rdata_factory_users = [('soa', 'generic'), ('txt', 'generic'),
- ('aaaa', 'in'), ('spf', 'generic')]
- re_typecode = re.compile('([\da-z]+)_(\d+)')
- classcode2txt = {}
- typecode2txt = {}
- typeandclass = []
- generic_code = 65536 # something larger than any code value
- rdata_declarations = ''
- class_definitions = ''
- classdir_mtime = 0
- rdatadef_mtime = 0
- rdatahdr_mtime = 0
- heading_txt = '''///////////////
- ///////////////
- /////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
- /////////////// DO NOT EDIT!
- ///////////////
- ///////////////
- '''
- def import_classdef(class_txt, file):
- content = ''
- rdata_source = open(file, 'r')
- for line in rdata_source.readlines():
- if re.match('// BEGIN_ISC_NAMESPACE', line):
- content += 'namespace isc {\n'
- content += 'namespace dns {\n'
- continue
- if re.match('// BEGIN_RDATA_NAMESPACE', line):
- content += 'namespace rdata {\n'
- content += 'namespace ' + class_txt + ' {\n'
- continue
- if re.match('// END_ISC_NAMESPACE', line):
- content += '} // end of namespace "dns"\n'
- content += '} // end of namespace "isc"\n'
- continue
- if re.match('// END_RDATA_NAMESPACE', line):
- content += '} // end of namespace "' + class_txt +'"\n'
- content += '} // end of namespace "rdata"\n'
- continue
- content += line
- rdata_source.close()
- return content
- def import_classheader(class_txt, type_txt, type_code, file):
- type_utxt = type_txt.upper()
- class_utxt = class_txt.upper()
- # for each CLASS_n/TYPE_m.h
- rdata_header = open(file, 'r')
- content = ''
- guard_macro = class_txt.upper() + '_' + type_txt.upper()
- guard_macro += '_' + type_code + '_H'
- for line in rdata_header.readlines():
- if re.match('// BEGIN_HEADER_GUARD', line):
- content += '#ifndef ' + guard_macro + '\n'
- content += '#define ' + guard_macro + ' 1\n'
- continue
- if re.match('// END_HEADER_GUARD', line):
- content += '#endif // ' + guard_macro + '\n'
- continue
- if re.match('// BEGIN_ISC_NAMESPACE', line):
- content += 'namespace isc {\n'
- content += 'namespace util {\n'
- content += '''
- class InputBuffer;
- class OutputBuffer;\n'''
- content += '}\n\n'
- content += 'namespace dns {\n'
- continue
- if re.match('// BEGIN_RDATA_NAMESPACE', line):
- content += 'namespace rdata {\n'
- content += 'namespace ' + class_txt + ' {\n'
- continue
- if re.match('// END_ISC_NAMESPACE', line):
- content += '} // end of namespace "dns"\n'
- content += '} // end of namespace "isc"\n'
- continue
- if re.match('// END_RDATA_NAMESPACE', line):
- content += '} // end of namespace "' + class_txt +'"\n'
- content += '} // end of namespace "rdata"\n'
- continue
- if re.match('// Local Variables:', line):
- break
- content += line
- if re.match('// BEGIN_COMMON_DECLARATIONS', line):
- content += '''
- class AbstractMessageRenderer;\n\n'''
- if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
- content += '''
- explicit ''' + type_utxt + '''(const std::string& type_str);
- ''' + type_utxt + '''(isc::util::InputBuffer& buffer, size_t rdata_len);
- ''' + type_utxt + '''(const ''' + type_utxt + '''& other);
- ''' + type_utxt + '''(
- MasterLexer& lexer, const Name* name,
- MasterLoader::Options options, MasterLoaderCallbacks& callbacks);
- virtual std::string toText() const;
- virtual void toWire(isc::util::OutputBuffer& buffer) const;
- virtual void toWire(AbstractMessageRenderer& renderer) const;
- virtual int compare(const Rdata& other) const;\n\n'''
- rdata_header.close()
- return content
- def import_definitions(classcode2txt, typecode2txt, typeandclass):
- global rdata_declarations
- global class_definitions
- global classdir_mtime
- global rdatadef_mtime
- global rdatahdr_mtime
- if classdir_mtime < getmtime('@srcdir@/rdata'):
- classdir_mtime = getmtime('@srcdir@/rdata')
- # Sort directories before iterating through them so that the directory
- # list is processed in the same order on all systems. The resulting
- # files should compile regardless of the order in which the components
- # are included but... Having a fixed order for the directories should
- # eliminate system-dependent problems. (Note that the drectory names
- # in BIND 10 are ASCII, so the order should be locale-independent.)
- dirlist = os.listdir('@srcdir@/rdata')
- dirlist.sort()
- for dir in dirlist:
- classdir = '@srcdir@/rdata' + os.sep + dir
- m = re_typecode.match(dir)
- if os.path.isdir(classdir) and (m != None or dir == 'generic'):
- if dir == 'generic':
- class_txt = 'generic'
- class_code = generic_code
- else:
- class_txt = m.group(1)
- class_code = m.group(2)
- if not class_code in classcode2txt:
- classcode2txt[class_code] = class_txt
- # Same considerations as directories regarding sorted order
- # also apply to files.
- filelist = os.listdir(classdir)
- filelist.sort()
- for file in filelist:
- file = classdir + os.sep + file
- m = re_typecode.match(os.path.split(file)[1])
- if m != None:
- type_txt = m.group(1)
- type_code = m.group(2)
- if not type_code in typecode2txt:
- typecode2txt[type_code] = type_txt
- if re.search('\cc$', file):
- if rdatadef_mtime < getmtime(file):
- rdatadef_mtime = getmtime(file)
- class_definitions += import_classdef(class_txt, file)
- elif re.search('\h$', file):
- if rdatahdr_mtime < getmtime(file):
- rdatahdr_mtime = getmtime(file)
- rdata_declarations += import_classheader(class_txt,
- type_txt,
- type_code,
- file)
- typeandclass.append((type_txt, int(type_code),
- (class_txt, class_txt),
- int(class_code)))
- if class_txt == 'generic':
- typeandclass.append((type_txt, int(type_code),
- (class_txt, 'in'), 1))
- def need_generate(file, mtime):
- '''Check if we need to generate the specified file.
- To avoid unnecessary compilation, we skip (re)generating the file when
- the file already exists and newer than the base file.
- '''
- if os.path.exists(file) and getmtime(file) > mtime:
- return False
- return True
- def generate_rdatadef(file, basemtime):
- if not need_generate(file, basemtime):
- print('skip generating ' + file);
- return
- rdata_deffile = open(file, 'w')
- rdata_deffile.write(heading_txt)
- rdata_deffile.write(class_definitions)
- rdata_deffile.close()
- def generate_rdatahdr(file, heading, declarations, basemtime):
- if not need_generate(file, basemtime):
- print('skip generating ' + file);
- return
- heading += '''
- #ifndef DNS_RDATACLASS_H
- #define DNS_RDATACLASS_H 1
- #include <dns/master_loader.h>
- namespace isc {
- namespace dns {
- class Name;
- class MasterLexer;
- class MasterLoaderCallbacks;
- }
- }
- '''
- declarations += '''
- #endif // DNS_RDATACLASS_H
- // Local Variables:
- // mode: c++
- // End:
- '''
- rdata_header = open(file, 'w')
- rdata_header.write(heading)
- rdata_header.write(declarations)
- rdata_header.close()
- def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
- placeholder = '@srcdir@/' + fileprefix + '-placeholder.h'
- outputfile = '@builddir@/' + fileprefix + '.h'
- upper_key = type_or_class.upper() # TYPE or CLASS
- lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
- cap_key = type_or_class # Type or Class
- if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
- print('skip generating ' + outputfile)
- return
- declarationtxt = ''
- deftxt = ''
- for code in code2txt.keys():
- codetxt = code2txt[code].upper()
- declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
- deftxt += '''inline const RR''' + cap_key + '''&
- RR''' + cap_key + '''::''' + codetxt + '''() {
- static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
- return (''' + lower_key + ''');
- }\n
- '''
- header_temp = open(placeholder, 'r')
- header_out = open(outputfile, 'w')
- header_out.write(heading_txt)
- for line in header_temp.readlines():
- header_out.write(line)
- if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
- header_out.write(declarationtxt)
- if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
- header_out.write('\n' + deftxt)
- header_out.close()
- header_temp.close()
- def generate_rrparam(fileprefix, basemtime):
- placeholder = '@srcdir@/' + fileprefix + '-placeholder.cc'
- outputfile = '@builddir@/' + fileprefix + '.cc'
- if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
- print('skip generating ' + outputfile)
- return
- # sort by class, then by type
- typeandclassparams = ''
- typeandclass.sort(key = lambda x: (x[3], x[1]))
- for param in typeandclass:
- # for rrparamregistry.cc
- # each param is a tuple of (type_txt, type_code, class_tuple,
- # class_code)
- (type_txt, type_code, class_tuple, class_code) = param
- type_utxt = type_txt.upper()
- class_txt = class_tuple[0]
- class_utxt = class_tuple[1].upper()
- indent = ' ' * 8
- typeandclassparams += indent
- # By default, we use OldRdataFactory (see bug #2497). If you
- # want to pick RdataFactory for a particular type, add it to
- # new_rdata_factory_users. Note that we explicitly generate (for
- # optimization) class-independent ("generic") factories for class IN
- # for optimization.
- if (((type_txt.lower(), class_txt.lower()) in
- new_rdata_factory_users) or
- ((class_txt.lower() == 'in') and
- ((type_txt.lower(), 'generic') in new_rdata_factory_users))):
- rdf_class = 'RdataFactory'
- else:
- rdf_class = 'OldRdataFactory'
- if class_tuple[1] != 'generic':
- typeandclassparams += 'add("' + type_utxt + '", '
- typeandclassparams += str(type_code) + ', "' + class_utxt
- typeandclassparams += '", ' + str(class_code)
- typeandclassparams += ', RdataFactoryPtr(new ' + rdf_class + '<'
- typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
- else:
- typeandclassparams += 'add("' + type_utxt + '", ' + str(type_code)
- typeandclassparams += ', RdataFactoryPtr(new ' + rdf_class + '<'
- typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
- rrparam_temp = open(placeholder, 'r')
- rrparam_out = open(outputfile, 'w')
- rrparam_out.write(heading_txt)
- for line in rrparam_temp.readlines():
- rrparam_out.write(line)
- if re.match('\s+// BEGIN_WELL_KNOWN_PARAMS', line):
- rrparam_out.write(typeandclassparams)
- rrparam_temp.close()
- rrparam_out.close()
- if __name__ == "__main__":
- try:
- import_definitions(classcode2txt, typecode2txt, typeandclass)
- generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
- generate_rdatahdr('@builddir@/rdataclass.h', heading_txt,
- rdata_declarations, rdatahdr_mtime)
- generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
- generate_typeclasscode('rrclass', classdir_mtime,
- classcode2txt, 'Class')
- generate_rrparam('rrparamregistry', rdatahdr_mtime)
- except:
- sys.stderr.write('Code generation failed due to exception: %s\n' %
- sys.exc_info()[1])
- exit(1)
|