makeqstrdefs.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. """
  2. This script processes the output from the C preprocessor and extracts all
  3. qstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'.
  4. This script works with Python 2.6, 2.7, 3.3 and 3.4.
  5. """
  6. from __future__ import print_function
  7. import re
  8. import sys
  9. import os
  10. # Blacklist of qstrings that are specially handled in further
  11. # processing and should be ignored
  12. QSTRING_BLACK_LIST = set(['NULL', 'number_of'])
  13. def write_out(fname, output):
  14. if output:
  15. for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]:
  16. fname = fname.replace(m, r)
  17. with open(args.output_dir + "/" + fname + ".qstr", "w") as f:
  18. f.write("\n".join(output) + "\n")
  19. def process_file(f):
  20. re_line = re.compile(r"#[line]*\s\d+\s\"([^\"]+)\"")
  21. re_qstr = re.compile(r'MP_QSTR_[_a-zA-Z0-9]+')
  22. output = []
  23. last_fname = None
  24. for line in f:
  25. if line.isspace():
  26. continue
  27. # match gcc-like output (# n "file") and msvc-like output (#line n "file")
  28. if line.startswith(('# ', '#line')):
  29. m = re_line.match(line)
  30. assert m is not None
  31. fname = m.group(1)
  32. if not fname.endswith(".c"):
  33. continue
  34. if fname != last_fname:
  35. write_out(last_fname, output)
  36. output = []
  37. last_fname = fname
  38. continue
  39. for match in re_qstr.findall(line):
  40. name = match.replace('MP_QSTR_', '')
  41. if name not in QSTRING_BLACK_LIST:
  42. output.append('Q(' + name + ')')
  43. write_out(last_fname, output)
  44. return ""
  45. def cat_together():
  46. import glob
  47. import hashlib
  48. hasher = hashlib.md5()
  49. all_lines = []
  50. outf = open(args.output_dir + "/out", "wb")
  51. for fname in glob.glob(args.output_dir + "/*.qstr"):
  52. with open(fname, "rb") as f:
  53. lines = f.readlines()
  54. all_lines += lines
  55. all_lines.sort()
  56. all_lines = b"\n".join(all_lines)
  57. outf.write(all_lines)
  58. outf.close()
  59. hasher.update(all_lines)
  60. new_hash = hasher.hexdigest()
  61. #print(new_hash)
  62. old_hash = None
  63. try:
  64. with open(args.output_file + ".hash") as f:
  65. old_hash = f.read()
  66. except IOError:
  67. pass
  68. if old_hash != new_hash:
  69. print("QSTR updated")
  70. try:
  71. # rename below might fail if file exists
  72. os.remove(args.output_file)
  73. except:
  74. pass
  75. os.rename(args.output_dir + "/out", args.output_file)
  76. with open(args.output_file + ".hash", "w") as f:
  77. f.write(new_hash)
  78. else:
  79. print("QSTR not updated")
  80. if __name__ == "__main__":
  81. if len(sys.argv) != 5:
  82. print('usage: %s command input_filename output_dir output_file' % sys.argv[0])
  83. sys.exit(2)
  84. class Args:
  85. pass
  86. args = Args()
  87. args.command = sys.argv[1]
  88. args.input_filename = sys.argv[2]
  89. args.output_dir = sys.argv[3]
  90. args.output_file = sys.argv[4]
  91. try:
  92. os.makedirs(args.output_dir)
  93. except OSError:
  94. pass
  95. if args.command == "split":
  96. with open(args.input_filename) as infile:
  97. process_file(infile)
  98. if args.command == "cat":
  99. cat_together()