gen-rdatacode.py.in 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #!@PYTHON@
  2. # Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  3. #
  4. # Permission to use, copy, modify, and/or distribute this software for any
  5. # purpose with or without fee is hereby granted, provided that the above
  6. # copyright notice and this permission notice appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  9. # REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. # AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. # LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13. # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. # PERFORMANCE OF THIS SOFTWARE.
  15. """\
  16. This is a supplemental script to (half) auto-generate DNS Rdata related
  17. classes and constants.
  18. """
  19. import os
  20. from os.path import getmtime
  21. import re
  22. import sys
  23. re_typecode = re.compile('([\da-z]+)_(\d+)')
  24. classcode2txt = {}
  25. typecode2txt = {}
  26. typeandclass = []
  27. generic_code = 65536 # something larger than any code value
  28. rdata_declarations = ''
  29. class_definitions = ''
  30. classdir_mtime = 0
  31. rdatadef_mtime = 0
  32. rdatahdr_mtime = 0
  33. heading_txt = '''///////////////
  34. ///////////////
  35. /////////////// THIS FILE IS AUTOMATICALLY GENERATED BY gen-rdatacode.py.
  36. /////////////// DO NOT EDIT!
  37. ///////////////
  38. ///////////////
  39. '''
  40. def import_classdef(class_txt, file):
  41. content = ''
  42. rdata_source = open(file, 'r')
  43. for line in rdata_source.readlines():
  44. if re.match('// BEGIN_ISC_NAMESPACE', line):
  45. content += 'namespace isc {\n'
  46. content += 'namespace dns {\n'
  47. continue
  48. if re.match('// BEGIN_RDATA_NAMESPACE', line):
  49. content += 'namespace rdata {\n'
  50. content += 'namespace ' + class_txt + ' {\n'
  51. continue
  52. if re.match('// END_ISC_NAMESPACE', line):
  53. content += '} // end of namespace "dns"\n'
  54. content += '} // end of namespace "isc"\n'
  55. continue
  56. if re.match('// END_RDATA_NAMESPACE', line):
  57. content += '} // end of namespace "' + class_txt +'"\n'
  58. content += '} // end of namespace "rdata"\n'
  59. continue
  60. content += line
  61. rdata_source.close()
  62. return content
  63. def import_classheader(class_txt, type_txt, type_code, file):
  64. type_utxt = type_txt.upper()
  65. class_utxt = class_txt.upper()
  66. # for each CLASS_n/TYPE_m.h
  67. rdata_header = open(file, 'r')
  68. content = ''
  69. guard_macro = class_txt.upper() + '_' + type_txt.upper()
  70. guard_macro += '_' + type_code + '_H'
  71. for line in rdata_header.readlines():
  72. if re.match('// BEGIN_HEADER_GUARD', line):
  73. content += '#ifndef ' + guard_macro + '\n'
  74. content += '#define ' + guard_macro + ' 1\n'
  75. continue
  76. if re.match('// END_HEADER_GUARD', line):
  77. content += '#endif // ' + guard_macro + '\n'
  78. continue
  79. if re.match('// BEGIN_ISC_NAMESPACE', line):
  80. content += 'namespace isc {\n'
  81. content += 'namespace util {\n'
  82. content += '''
  83. class InputBuffer;
  84. class OutputBuffer;\n'''
  85. content += '}\n\n'
  86. content += 'namespace dns {\n'
  87. continue
  88. if re.match('// BEGIN_RDATA_NAMESPACE', line):
  89. content += 'namespace rdata {\n'
  90. content += 'namespace ' + class_txt + ' {\n'
  91. continue
  92. if re.match('// END_ISC_NAMESPACE', line):
  93. content += '} // end of namespace "dns"\n'
  94. content += '} // end of namespace "isc"\n'
  95. continue
  96. if re.match('// END_RDATA_NAMESPACE', line):
  97. content += '} // end of namespace "' + class_txt +'"\n'
  98. content += '} // end of namespace "rdata"\n'
  99. continue
  100. if re.match('// Local Variables:', line):
  101. break
  102. content += line
  103. if re.match('// BEGIN_COMMON_DECLARATIONS', line):
  104. content += '''
  105. class AbstractMessageRenderer;\n\n'''
  106. if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
  107. content += '''
  108. explicit ''' + type_utxt + '''(const std::string& type_str);
  109. ''' + type_utxt + '''(isc::util::InputBuffer& buffer, size_t rdata_len);
  110. ''' + type_utxt + '''(const ''' + type_utxt + '''& other);
  111. virtual std::string toText() const;
  112. virtual void toWire(isc::util::OutputBuffer& buffer) const;
  113. virtual void toWire(AbstractMessageRenderer& renderer) const;
  114. virtual int compare(const Rdata& other) const;\n\n'''
  115. rdata_header.close()
  116. return content
  117. def import_definitions(classcode2txt, typecode2txt, typeandclass):
  118. global rdata_declarations
  119. global class_definitions
  120. global classdir_mtime
  121. global rdatadef_mtime
  122. global rdatahdr_mtime
  123. if classdir_mtime < getmtime('@srcdir@/rdata'):
  124. classdir_mtime = getmtime('@srcdir@/rdata')
  125. # Sort directories before iterating through them so that the directory
  126. # list is processed in the same order on all systems. The resulting
  127. # files should compile regardless of the order in which the components
  128. # are included but... Having a fixed order for the directories should
  129. # eliminate system-dependent problems. (Note that the drectory names
  130. # in BIND 10 are ASCII, so the order should be locale-independent.)
  131. dirlist = os.listdir('@srcdir@/rdata')
  132. dirlist.sort()
  133. for dir in dirlist:
  134. classdir = '@srcdir@/rdata' + os.sep + dir
  135. m = re_typecode.match(dir)
  136. if os.path.isdir(classdir) and (m != None or dir == 'generic'):
  137. if dir == 'generic':
  138. class_txt = 'generic'
  139. class_code = generic_code
  140. else:
  141. class_txt = m.group(1)
  142. class_code = m.group(2)
  143. if not class_code in classcode2txt:
  144. classcode2txt[class_code] = class_txt
  145. # Same considerations as directories regarding sorted order
  146. # also apply to files.
  147. filelist = os.listdir(classdir)
  148. filelist.sort()
  149. for file in filelist:
  150. file = classdir + os.sep + file
  151. m = re_typecode.match(os.path.split(file)[1])
  152. if m != None:
  153. type_txt = m.group(1)
  154. type_code = m.group(2)
  155. if not type_code in typecode2txt:
  156. typecode2txt[type_code] = type_txt
  157. if re.search('\cc$', file):
  158. if rdatadef_mtime < getmtime(file):
  159. rdatadef_mtime = getmtime(file)
  160. class_definitions += import_classdef(class_txt, file)
  161. elif re.search('\h$', file):
  162. if rdatahdr_mtime < getmtime(file):
  163. rdatahdr_mtime = getmtime(file)
  164. rdata_declarations += import_classheader(class_txt,
  165. type_txt,
  166. type_code,
  167. file)
  168. typeandclass.append((type_txt, int(type_code),
  169. (class_txt, class_txt),
  170. int(class_code)))
  171. if class_txt == 'generic':
  172. typeandclass.append((type_txt, int(type_code),
  173. (class_txt, 'in'), 1))
  174. def need_generate(file, mtime):
  175. '''Check if we need to generate the specified file.
  176. To avoid unnecessary compilation, we skip (re)generating the file when
  177. the file already exists and newer than the base file.
  178. '''
  179. if os.path.exists(file) and getmtime(file) > mtime:
  180. return False
  181. return True
  182. def generate_rdatadef(file, basemtime):
  183. if not need_generate(file, basemtime):
  184. print('skip generating ' + file);
  185. return
  186. rdata_deffile = open(file, 'w')
  187. rdata_deffile.write(heading_txt)
  188. rdata_deffile.write(class_definitions)
  189. rdata_deffile.close()
  190. def generate_rdatahdr(file, declarations, basemtime):
  191. if not need_generate(file, basemtime):
  192. print('skip generating ' + file);
  193. return
  194. declarations += '''
  195. // Local Variables:
  196. // mode: c++
  197. // End:
  198. '''
  199. rdata_header = open(file, 'w')
  200. rdata_header.write(heading_txt)
  201. rdata_header.write(declarations)
  202. rdata_header.close()
  203. def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
  204. placeholder = '@srcdir@/' + fileprefix + '-placeholder.h'
  205. outputfile = '@builddir@/' + fileprefix + '.h'
  206. upper_key = type_or_class.upper() # TYPE or CLASS
  207. lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
  208. cap_key = type_or_class # Type or Class
  209. if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
  210. print('skip generating ' + outputfile)
  211. return
  212. declarationtxt = ''
  213. deftxt = ''
  214. for code in code2txt.keys():
  215. codetxt = code2txt[code].upper()
  216. declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
  217. deftxt += '''inline const RR''' + cap_key + '''&
  218. RR''' + cap_key + '''::''' + codetxt + '''() {
  219. static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
  220. return (''' + lower_key + ''');
  221. }\n
  222. '''
  223. header_temp = open(placeholder, 'r')
  224. header_out = open(outputfile, 'w')
  225. header_out.write(heading_txt)
  226. for line in header_temp.readlines():
  227. header_out.write(line)
  228. if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
  229. header_out.write(declarationtxt)
  230. if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
  231. header_out.write('\n' + deftxt)
  232. header_out.close()
  233. header_temp.close()
  234. def generate_rrparam(fileprefix, basemtime):
  235. placeholder = '@srcdir@/' + fileprefix + '-placeholder.cc'
  236. outputfile = '@builddir@/' + fileprefix + '.cc'
  237. if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
  238. print('skip generating ' + outputfile)
  239. return
  240. # sort by class, then by type
  241. typeandclassparams = ''
  242. typeandclass.sort(key = lambda x: (x[3], x[1]))
  243. for param in typeandclass:
  244. # for rrparamregistry.cc
  245. # each param is a tuple of (type_txt, type_code, class_tuple,
  246. # class_code)
  247. (type_txt, type_code, class_tuple, class_code) = param
  248. type_utxt = type_txt.upper()
  249. class_txt = class_tuple[0]
  250. class_utxt = class_tuple[1].upper()
  251. indent = ' ' * 8
  252. typeandclassparams += indent
  253. if class_tuple[1] != 'generic':
  254. typeandclassparams += 'add("' + type_utxt + '", '
  255. typeandclassparams += str(type_code) + ', "' + class_utxt
  256. typeandclassparams += '", ' + str(class_code)
  257. typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
  258. typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
  259. else:
  260. typeandclassparams += 'add("' + type_utxt + '", ' + str(type_code)
  261. typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
  262. typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
  263. rrparam_temp = open(placeholder, 'r')
  264. rrparam_out = open(outputfile, 'w')
  265. rrparam_out.write(heading_txt)
  266. for line in rrparam_temp.readlines():
  267. rrparam_out.write(line)
  268. if re.match('\s+// BEGIN_WELL_KNOWN_PARAMS', line):
  269. rrparam_out.write(typeandclassparams)
  270. rrparam_temp.close()
  271. rrparam_out.close()
  272. if __name__ == "__main__":
  273. try:
  274. import_definitions(classcode2txt, typecode2txt, typeandclass)
  275. generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
  276. generate_rdatahdr('@builddir@/rdataclass.h', rdata_declarations,
  277. rdatahdr_mtime)
  278. generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
  279. generate_typeclasscode('rrclass', classdir_mtime,
  280. classcode2txt, 'Class')
  281. generate_rrparam('rrparamregistry', rdatahdr_mtime)
  282. except:
  283. sys.stderr.write('Code generation failed due to exception: %s\n' %
  284. sys.exc_info()[1])
  285. exit(1)