| #!/usr/bin/env python3 | 
 | # -*- coding: utf-8 -*- | 
 | # | 
 | # Copyright (C) 2017-2020  The Project X-Ray Authors. | 
 | # | 
 | # Use of this source code is governed by a ISC-style | 
 | # license that can be found in the LICENSE file or at | 
 | # https://opensource.org/licenses/ISC | 
 | # | 
 | # SPDX-License-Identifier: ISC | 
 |  | 
 | import os, sys, re | 
 | from prjxray import util | 
 |  | 
 | TAG_PART_RE = re.compile(r"^[a-zA-Z][0-9a-zA-Z_]*(\[[0-9]+\])?$") | 
 |  | 
 |  | 
 | def check_tag_name(tag): | 
 |     ''' | 
 |     Checks if the tag name given by the used conforms to the valid fasm | 
 |     name rules. | 
 |  | 
 |     >>> check_tag_name("CELL.feature19.ENABLED") | 
 |     True | 
 |     >>> check_tag_name("FEATURE") | 
 |     True | 
 |     >>> check_tag_name("TAG.") | 
 |     False | 
 |     >>> check_tag_name(".TAG") | 
 |     False | 
 |     >>> check_tag_name("CELL..FEATURE") | 
 |     False | 
 |     >>> check_tag_name("CELL.3ENABLE") | 
 |     False | 
 |     >>> check_tag_name("FEATURE.12.ON") | 
 |     False | 
 |     ''' | 
 |  | 
 |     for part in tag.split("."): | 
 |         if not len(part) or TAG_PART_RE.match(part) is None: | 
 |             return False | 
 |  | 
 |     return True | 
 |  | 
 |  | 
 | def run(fn_ins, fn_out, strict=False, track_origin=False, verbose=False): | 
 |     # tag to bits | 
 |     entries = {} | 
 |     # tag to (bits, line) | 
 |     tags = dict() | 
 |     # bits to (tag, line) | 
 |     bitss = dict() | 
 |  | 
 |     for fn_in in fn_ins: | 
 |         for line, (tag, bits, mode, origin) in util.parse_db_lines(fn_in): | 
 |             line = line.strip() | 
 |             assert mode is not None or mode != "always", "strict: got ill defined line: %s" % ( | 
 |                 line, ) | 
 |  | 
 |             if not check_tag_name(tag): | 
 |                 assert not strict, "strict: Invalid tag name '{}'".format(tag) | 
 |  | 
 |             if tag in tags: | 
 |                 orig_bits, orig_line, orig_origin = tags[tag] | 
 |                 if orig_bits != bits: | 
 |                     print( | 
 |                         "WARNING: got duplicate tag %s" % (tag, ), | 
 |                         file=sys.stderr) | 
 |                     print("  Orig line: %s" % orig_line, file=sys.stderr) | 
 |                     print("  New line : %s" % line, file=sys.stderr) | 
 |                     assert not strict, "strict: got duplicate tag" | 
 |                 origin = os.path.basename(os.getcwd()) | 
 |                 if track_origin and orig_origin != origin: | 
 |                     origin = orig_origin + "," + origin | 
 |             if bits in bitss: | 
 |                 orig_tag, orig_line = bitss[bits] | 
 |                 if orig_tag != tag: | 
 |                     print( | 
 |                         "WARNING: got duplicate bits %s" % (bits, ), | 
 |                         file=sys.stderr) | 
 |                     print("  Orig line: %s" % orig_line, file=sys.stderr) | 
 |                     print("  New line : %s" % line, file=sys.stderr) | 
 |                     assert not strict, "strict: got duplicate bits" | 
 |  | 
 |             if track_origin and origin is None: | 
 |                 origin = os.path.basename(os.getcwd()) | 
 |             entries[tag] = (bits, origin) | 
 |             tags[tag] = (bits, line, origin) | 
 |             if bits != None: | 
 |                 bitss[bits] = (tag, line) | 
 |  | 
 |     util.write_db_lines(fn_out, entries, track_origin) | 
 |  | 
 |  | 
 | def main(): | 
 |     import argparse | 
 |  | 
 |     parser = argparse.ArgumentParser(description="Combine multiple .db files") | 
 |  | 
 |     util.db_root_arg(parser) | 
 |     parser.add_argument('--verbose', action='store_true', help='') | 
 |     parser.add_argument('--track_origin', action='store_true', help='') | 
 |     parser.add_argument('--out', help='') | 
 |     parser.add_argument('ins', nargs='+', help='Last takes precedence') | 
 |     args = parser.parse_args() | 
 |  | 
 |     run( | 
 |         args.ins, | 
 |         args.out, | 
 |         strict=int(os.getenv("MERGEDB_STRICT", "1")), | 
 |         track_origin=args.track_origin, | 
 |         verbose=args.verbose) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     main() |