Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 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 | |
| 5 | This script works with Python 2.6, 2.7, 3.3 and 3.4. |
| 6 | """ |
| 7 | |
Damien George | b24ccfc | 2017-06-09 13:42:13 +1000 | [diff] [blame] | 8 | from __future__ import print_function |
| 9 | |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 10 | import re |
Damien George | b24ccfc | 2017-06-09 13:42:13 +1000 | [diff] [blame] | 11 | import sys |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 12 | import os |
| 13 | |
| 14 | # Blacklist of qstrings that are specially handled in further |
| 15 | # processing and should be ignored |
Chris Packham | a50b26e | 2016-09-08 20:34:34 +1200 | [diff] [blame] | 16 | QSTRING_BLACK_LIST = set(['NULL', 'number_of']) |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 17 | |
| 18 | |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 19 | def write_out(fname, output): |
| 20 | if output: |
stijn | 9264d42 | 2016-04-23 18:36:07 +0200 | [diff] [blame] | 21 | for m, r in [("/", "__"), ("\\", "__"), (":", "@"), ("..", "@@")]: |
| 22 | fname = fname.replace(m, r) |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 23 | with open(args.output_dir + "/" + fname + ".qstr", "w") as f: |
| 24 | f.write("\n".join(output) + "\n") |
| 25 | |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 26 | def process_file(f): |
| 27 | output = [] |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 28 | last_fname = None |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 29 | for line in f: |
stijn | 9264d42 | 2016-04-23 18:36:07 +0200 | [diff] [blame] | 30 | # match gcc-like output (# n "file") and msvc-like output (#line n "file") |
| 31 | if line and (line[0:2] == "# " or line[0:5] == "#line"): |
| 32 | m = re.match(r"#[line]*\s\d+\s\"([^\"]+)\"", line) |
| 33 | assert m is not None |
| 34 | fname = m.group(1) |
Paul Sokolovsky | dcb9044 | 2016-06-16 01:04:42 +0300 | [diff] [blame] | 35 | if not fname.endswith(".c"): |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 36 | continue |
| 37 | if fname != last_fname: |
| 38 | write_out(last_fname, output) |
| 39 | output = [] |
| 40 | last_fname = fname |
| 41 | continue |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 42 | for match in re.findall(r'MP_QSTR_[_a-zA-Z0-9]+', line): |
| 43 | name = match.replace('MP_QSTR_', '') |
| 44 | if name not in QSTRING_BLACK_LIST: |
| 45 | output.append('Q(' + name + ')') |
| 46 | |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 47 | write_out(last_fname, output) |
| 48 | return "" |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 49 | |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 50 | |
| 51 | def cat_together(): |
| 52 | import glob |
| 53 | import hashlib |
| 54 | hasher = hashlib.md5() |
| 55 | all_lines = [] |
| 56 | outf = open(args.output_dir + "/out", "wb") |
| 57 | for fname in glob.glob(args.output_dir + "/*.qstr"): |
| 58 | with open(fname, "rb") as f: |
| 59 | lines = f.readlines() |
| 60 | all_lines += lines |
| 61 | all_lines.sort() |
| 62 | all_lines = b"\n".join(all_lines) |
| 63 | outf.write(all_lines) |
| 64 | outf.close() |
| 65 | hasher.update(all_lines) |
| 66 | new_hash = hasher.hexdigest() |
| 67 | #print(new_hash) |
| 68 | old_hash = None |
| 69 | try: |
| 70 | with open(args.output_file + ".hash") as f: |
| 71 | old_hash = f.read() |
| 72 | except IOError: |
| 73 | pass |
| 74 | if old_hash != new_hash: |
| 75 | print("QSTR updated") |
stijn | 9264d42 | 2016-04-23 18:36:07 +0200 | [diff] [blame] | 76 | try: |
| 77 | # rename below might fail if file exists |
| 78 | os.remove(args.output_file) |
| 79 | except: |
| 80 | pass |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 81 | os.rename(args.output_dir + "/out", args.output_file) |
| 82 | with open(args.output_file + ".hash", "w") as f: |
| 83 | f.write(new_hash) |
| 84 | else: |
| 85 | print("QSTR not updated") |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 86 | |
| 87 | |
| 88 | if __name__ == "__main__": |
Damien George | b24ccfc | 2017-06-09 13:42:13 +1000 | [diff] [blame] | 89 | if len(sys.argv) != 5: |
| 90 | print('usage: %s command input_filename output_dir output_file' % sys.argv[0]) |
| 91 | sys.exit(2) |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 92 | |
Damien George | b24ccfc | 2017-06-09 13:42:13 +1000 | [diff] [blame] | 93 | class Args: |
| 94 | pass |
| 95 | args = Args() |
| 96 | args.command = sys.argv[1] |
| 97 | args.input_filename = sys.argv[2] |
| 98 | args.output_dir = sys.argv[3] |
| 99 | args.output_file = sys.argv[4] |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 100 | |
Paul Sokolovsky | c618f91 | 2016-04-19 11:30:06 +0300 | [diff] [blame] | 101 | try: |
| 102 | os.makedirs(args.output_dir) |
| 103 | except OSError: |
| 104 | pass |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 105 | |
Paul Sokolovsky | 1b60a6d | 2016-04-19 14:39:08 +0300 | [diff] [blame] | 106 | if args.command == "split": |
| 107 | with open(args.input_filename) as infile: |
| 108 | process_file(infile) |
Pavel Moravec | dbbf082 | 2016-03-11 16:12:59 +0000 | [diff] [blame] | 109 | |
Paul Sokolovsky | 1b60a6d | 2016-04-19 14:39:08 +0300 | [diff] [blame] | 110 | if args.command == "cat": |
| 111 | cat_together() |