gen-rdatacode.py.in 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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 dns {\n'
  82. continue
  83. if re.match('// BEGIN_RDATA_NAMESPACE', line):
  84. content += 'namespace rdata {\n'
  85. content += 'namespace ' + class_txt + ' {\n'
  86. continue
  87. if re.match('// END_ISC_NAMESPACE', line):
  88. content += '} // end of namespace "dns"\n'
  89. content += '} // end of namespace "isc"\n'
  90. continue
  91. if re.match('// END_RDATA_NAMESPACE', line):
  92. content += '} // end of namespace "' + class_txt +'"\n'
  93. content += '} // end of namespace "rdata"\n'
  94. continue
  95. if re.match('// Local Variables:', line):
  96. break
  97. content += line
  98. if re.match('// BEGIN_COMMON_DECLARATIONS', line):
  99. content += '''
  100. class InputBuffer;
  101. class OutputBuffer;
  102. class MessageRenderer;\n\n'''
  103. if re.match('\s+// BEGIN_COMMON_MEMBERS$', line):
  104. content += '''
  105. explicit ''' + type_utxt + '''(const std::string& type_str);
  106. ''' + type_utxt + '''(InputBuffer& buffer, size_t rdata_len);
  107. ''' + type_utxt + '''(const ''' + type_utxt + '''& other);
  108. virtual std::string toText() const;
  109. virtual void toWire(OutputBuffer& buffer) const;
  110. virtual void toWire(MessageRenderer& renderer) const;
  111. virtual int compare(const Rdata& other) const;\n\n'''
  112. rdata_header.close()
  113. return content
  114. def import_definitions(classcode2txt, typecode2txt, typeandclass):
  115. global rdata_declarations
  116. global class_definitions
  117. global classdir_mtime
  118. global rdatadef_mtime
  119. global rdatahdr_mtime
  120. if classdir_mtime < getmtime('@srcdir@/rdata'):
  121. classdir_mtime = getmtime('@srcdir@/rdata')
  122. for dir in list(os.listdir('@srcdir@/rdata')):
  123. classdir = '@srcdir@/rdata' + os.sep + dir
  124. m = re_typecode.match(dir)
  125. if os.path.isdir(classdir) and (m != None or dir == 'generic'):
  126. if dir == 'generic':
  127. class_txt = 'generic'
  128. class_code = generic_code
  129. else:
  130. class_txt = m.group(1)
  131. class_code = m.group(2)
  132. if not class_code in classcode2txt:
  133. classcode2txt[class_code] = class_txt
  134. for file in list(os.listdir(classdir)):
  135. file = classdir + os.sep + file
  136. m = re_typecode.match(os.path.split(file)[1])
  137. if m != None:
  138. type_txt = m.group(1)
  139. type_code = m.group(2)
  140. if not type_code in typecode2txt:
  141. typecode2txt[type_code] = type_txt
  142. if re.search('\cc$', file):
  143. if rdatadef_mtime < getmtime(file):
  144. rdatadef_mtime = getmtime(file)
  145. class_definitions += import_classdef(class_txt, file)
  146. elif re.search('\h$', file):
  147. if rdatahdr_mtime < getmtime(file):
  148. rdatahdr_mtime = getmtime(file)
  149. rdata_declarations += import_classheader(class_txt,
  150. type_txt,
  151. type_code,
  152. file)
  153. typeandclass.append((type_txt, int(type_code),
  154. (class_txt, class_txt),
  155. int(class_code)))
  156. if class_txt == 'generic':
  157. typeandclass.append((type_txt, int(type_code),
  158. (class_txt, 'in'), 1))
  159. def need_generate(file, mtime):
  160. '''Check if we need to generate the specified file.
  161. To avoid unnecessary compilation, we skip (re)generating the file when
  162. the file already exists and newer than the base file.
  163. '''
  164. if os.path.exists(file) and getmtime(file) > mtime:
  165. return False
  166. return True
  167. def generate_rdatadef(file, basemtime):
  168. if not need_generate(file, basemtime):
  169. print('skip generating ' + file);
  170. return
  171. rdata_deffile = open(file, 'w')
  172. rdata_deffile.write(heading_txt)
  173. rdata_deffile.write(class_definitions)
  174. rdata_deffile.close()
  175. def generate_rdatahdr(file, declarations, basemtime):
  176. if not need_generate(file, basemtime):
  177. print('skip generating ' + file);
  178. return
  179. declarations += '''
  180. // Local Variables:
  181. // mode: c++
  182. // End:
  183. '''
  184. rdata_header = open(file, 'w')
  185. rdata_header.write(heading_txt)
  186. rdata_header.write(declarations)
  187. rdata_header.close()
  188. def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
  189. placeholder = '@srcdir@/' + fileprefix + '-placeholder.h'
  190. outputfile = '@builddir@/' + fileprefix + '.h'
  191. upper_key = type_or_class.upper() # TYPE or CLASS
  192. lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
  193. cap_key = type_or_class # Type or Class
  194. if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
  195. print('skip generating ' + outputfile)
  196. return
  197. declarationtxt = ''
  198. deftxt = ''
  199. for code in code2txt.keys():
  200. codetxt = code2txt[code].upper()
  201. declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
  202. deftxt += '''inline const RR''' + cap_key + '''&
  203. RR''' + cap_key + '''::''' + codetxt + '''() {
  204. static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
  205. return (''' + lower_key + ''');
  206. }\n
  207. '''
  208. header_temp = open(placeholder, 'r')
  209. header_out = open(outputfile, 'w')
  210. header_out.write(heading_txt)
  211. for line in header_temp.readlines():
  212. header_out.write(line)
  213. if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
  214. header_out.write(declarationtxt)
  215. if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
  216. header_out.write('\n' + deftxt)
  217. header_out.close()
  218. header_temp.close()
  219. def generate_rrparam(fileprefix, basemtime):
  220. placeholder = '@srcdir@/' + fileprefix + '-placeholder.cc'
  221. outputfile = '@builddir@/' + fileprefix + '.cc'
  222. if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
  223. print('skip generating ' + outputfile)
  224. return
  225. # sort by class, then by type
  226. typeandclassparams = ''
  227. typeandclass.sort(key = lambda x: (x[3], x[1]))
  228. for param in typeandclass:
  229. # for rrparamregistry.cc
  230. # each param is a tuple of (type_txt, type_code, class_tuple,
  231. # class_code)
  232. (type_txt, type_code, class_tuple, class_code) = param
  233. type_utxt = type_txt.upper()
  234. class_txt = class_tuple[0]
  235. class_utxt = class_tuple[1].upper()
  236. indent = ' ' * 8
  237. typeandclassparams += indent
  238. if class_tuple[1] != 'generic':
  239. typeandclassparams += 'add("' + type_utxt + '", '
  240. typeandclassparams += str(type_code) + ', "' + class_utxt
  241. typeandclassparams += '", ' + str(class_code)
  242. typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
  243. typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
  244. else:
  245. typeandclassparams += 'add("' + type_utxt + '", ' + str(type_code)
  246. typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
  247. typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
  248. rrparam_temp = open(placeholder, 'r')
  249. rrparam_out = open(outputfile, 'w')
  250. rrparam_out.write(heading_txt)
  251. for line in rrparam_temp.readlines():
  252. rrparam_out.write(line)
  253. if re.match('\s+// BEGIN_WELL_KNOWN_PARAMS', line):
  254. rrparam_out.write(typeandclassparams)
  255. rrparam_temp.close()
  256. rrparam_out.close()
  257. if __name__ == "__main__":
  258. try:
  259. import_definitions(classcode2txt, typecode2txt, typeandclass)
  260. generate_rdatadef('@builddir@/rdataclass.cc', rdatadef_mtime)
  261. generate_rdatahdr('@builddir@/rdataclass.h', rdata_declarations,
  262. rdatahdr_mtime)
  263. generate_typeclasscode('rrtype', rdatahdr_mtime, typecode2txt, 'Type')
  264. generate_typeclasscode('rrclass', classdir_mtime,
  265. classcode2txt, 'Class')
  266. generate_rrparam('rrparamregistry', rdatahdr_mtime)
  267. except:
  268. sys.stderr.write('Code generation failed due to exception: %s\n' %
  269. sys.exc_info()[1])
  270. exit(1)