| #!/usr/bin/env python |
| # -*- coding: utf-8 -*- |
| import re |
| import os |
| import json |
| import chardet |
| import logging |
| import argparse |
| from tempfile import mkstemp |
| from shutil import move, copy |
| class ParserState(): |
| EXPECT_BEGIN='(BEGIN_TRACE_MAP_WITH_RANGE|BEGIN_TRACE_MAP)\(\s*(\w+)\s*(,*\s*(\d+)\s*)?\s*(,*\s*(\d+)\s*)?\)' |
| TRC_MSG= r'TRC_MSG\s*\(\s*([_a-zA-Z][_a-zA-Z0-9]+)\s*,\s*\"((\\.|[^"\\])*)\"(\w+\"(\\.|[^"\\]*)\")*\s*\)' |
| END_TRACE_MAP='(END_TRACE_MAP_WITH_RANGE|END_TRACE_MAP)\(\s*(\w+)\s*(,*\s*(\d+)\s*)?\s*(,*\s*(\d+)\s*)?\)' |
| args = None |
| module = 'DUMMY' |
| legacyParams = {} |
| msgs = [] |
| moduleList = [] |
| classes = [ |
| { 'TRACE_INFO': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_WARNING': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_ERROR': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_FUNC': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_STATE': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP1': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP2': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP3': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP4': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP5': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP6': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP7': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP8': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP9': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| { 'TRACE_GROUP10': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } } |
| ] |
| |
| def init_logger(log_filename): |
| logging.basicConfig(level=logging.DEBUG, |
| format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', |
| datefmt='%m-%d %H:%M:%S', |
| filename=log_filename) |
| console = logging.StreamHandler() |
| console.setLevel(logging.DEBUG) |
| formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') |
| console.setFormatter(formatter) |
| logging.getLogger('').addHandler(console) |
| def parsePsTrcPreprocessed(pstrc_file, inc_path): |
| global moduleList |
| tmp_h, tmp_pstrc_file = mkstemp() |
| with os.fdopen(tmp_h, 'w') as new_file: |
| prep_pstrc_file = pstrc_file+'.tmp' |
| logging.info('PreProcessing {}'.format(prep_pstrc_file)) |
| os.system(r'gcc -fdirectives-only -P -E -I{} -Iinterface/service/kal/ -Iinterface/service/config/ -Iinterface/sap -I interface/service/dhl/v2 -I interface/service/dhl -I interface/service/config/kal_config/ -I interface/driver/regbase -I interface/service/event_info -D __VGTCM__ -D __LPP_CP_SUPPORT__ -D __MD97__ -D MT6297 -D __TST_MODULE__ -D GEN_FOR_PC {} | gcc -fpreprocessed -dD -E -P - > {}'.format(inc_path, pstrc_file, prep_pstrc_file)) |
| parsePsTrc(prep_pstrc_file, new_file) |
| logging.info('Processing {}'.format(pstrc_file)) |
| parserState = ParserState.EXPECT_BEGIN |
| tmp_h, tmp_pstrc_file = mkstemp() |
| with os.fdopen(tmp_h, 'w') as new_file: |
| file = open(pstrc_file) |
| line = file.readline() |
| while line: |
| stripped= line.rstrip().lstrip() |
| if stripped == '': |
| line = file.readline() |
| continue |
| logging.debug('[IO] State {}: line: {}'.format(parserState, stripped)) |
| if parserState == ParserState.EXPECT_BEGIN: |
| if re.match(ParserState.EXPECT_BEGIN, stripped, re.IGNORECASE): |
| match = re.search(ParserState.EXPECT_BEGIN, stripped) |
| if match: |
| parserState = ParserState.TRC_MSG |
| else: |
| new_file.write(line) |
| else: |
| new_file.write(line) |
| elif parserState == ParserState.TRC_MSG: |
| if re.match(ParserState.END_TRACE_MAP, stripped, re.IGNORECASE): |
| _m = moduleList.pop(0) |
| j = json.dumps(_m, |
| sort_keys=True, |
| # escape utf-8 to ascii |
| ensure_ascii=True, |
| indent=2 |
| ) |
| filename = os.path.splitext(pstrc_file)[0] +'_'+ _m['module'].lower() + '_utmd.json' |
| new_file.write('// The trace map of {} is converted to UTMD file.\n'.format(module)) |
| new_file.write('// If you wished to modify your trace, please refer to {}\n'.format(os.path.basename(filename))) |
| new_file.write('#include"{}_precodegen.h"\n'.format(os.path.splitext(os.path.basename(filename))[0])) |
| parserState = ParserState.EXPECT_BEGIN |
| else: |
| new_file.write(line) |
| line = file.readline() |
| #force output for lpp_trc.h (no END_TRACE_MAP in file...) |
| for _m in moduleList: |
| filename = os.path.splitext(pstrc_file)[0] +'_'+ _m['module'].lower() + '_utmd.json' |
| new_file.write('// The trace map of {} is converted to UTMD file.\n'.format(module)) |
| new_file.write('// If you wished to modify your trace, please refer to {}\n'.format(os.path.basename(filename))) |
| new_file.write('#include"{}_precodegen.h"\n'.format(os.path.splitext(os.path.basename(filename))[0])) |
| if pstrc_file.endswith('lpp_trc.h'): |
| new_file.write('#endif /* _LPP_TRC_H */\n') |
| move(tmp_pstrc_file, pstrc_file) |
| def parsePsTrc(pstrc_file, new_file): |
| global module |
| global legacyParams |
| global classes |
| global msgs |
| global moduleList |
| logging.info('Processing {}'.format(pstrc_file)) |
| os.system(r"sed -i -E ':a;N;$!ba;s/(TRC_MSG)\s*\(\s*(\w+)\s*,\n/\1\(\2, /g;:a:N;$!ba;s/\\\n//g' {}".format(pstrc_file)) |
| parserState = ParserState.EXPECT_BEGIN |
| with open(pstrc_file) as file: |
| line = file.readline() |
| while line: |
| stripped= line.rstrip().lstrip() |
| if stripped == '': |
| line = file.readline() |
| continue |
| logging.debug('[IO] State {}: line: {}'.format(parserState, stripped)) |
| if parserState == ParserState.EXPECT_BEGIN: |
| if re.match(ParserState.EXPECT_BEGIN, stripped, re.IGNORECASE): |
| match = re.search(ParserState.EXPECT_BEGIN, stripped) |
| if match: |
| global module |
| module = match.group(2) |
| if match.group(4) and match.group(6): |
| legacyParams.update( {'predefinedMessageRange': { 'min': int(match.group(4)), 'max': int(match.group(6)) } } ) |
| else: |
| logging.warning("4th group / 6th group not found") |
| parserState = ParserState.TRC_MSG |
| else: |
| new_file.write(line) |
| else: |
| new_file.write(line) |
| elif parserState == ParserState.TRC_MSG: |
| if stripped.startswith('/*'): |
| while not stripped.endswith('*/'): |
| c = file.read(1) |
| stripped = stripped + c |
| line = file.readline() |
| continue |
| if stripped.startswith('TRC_MSG'): |
| while not re.match(ParserState.TRC_MSG, stripped, re.IGNORECASE) and line: |
| if stripped.endswith('\\'): |
| stripped = stripped[:-1:] |
| line = file.readline().lstrip().rstrip() |
| stripped = stripped + line |
| logging.error('strip anti-slash {}'.format(stripped)) |
| else: |
| line = file.readline().lstrip().rstrip() |
| stripped = stripped + line |
| logging.error('strip anti-slash {}'.format(stripped)) |
| # detect character encoding and transform to utf8 |
| if chardet.detect(stripped)['confidence'] > 0.75: |
| logging.debug('decode by {}'.format(chardet.detect(stripped)['encoding'])) |
| stripped = stripped.decode(chardet.detect(stripped)['encoding']).encode('utf8') |
| match = re.search(ParserState.TRC_MSG, stripped) |
| trc = {} |
| trc['traceClass'] = 'TRACE_INFO' |
| if match.group(4): |
| trc['format'] = match.group(2) + re.sub('"', '', match.group(4)) |
| else: |
| trc['format'] = match.group(2) |
| if not filter( lambda x: match.group(1) in x, msgs): |
| msgs.append( { match.group(1): trc } ) |
| else: |
| logging.error('Msg redefined {}'.format(match.group(1))) |
| logging.debug(match) |
| elif re.match(ParserState.END_TRACE_MAP, stripped, re.IGNORECASE): |
| moduleList.append({'module':module, |
| 'legacyParameters': legacyParams, |
| 'traceClassDefs': classes, |
| 'traceDefs': msgs, |
| 'traceFamily': 'PS' |
| }) |
| j = json.dumps({'module':module, |
| 'legacyParameters': legacyParams, |
| 'traceClassDefs': classes, |
| 'traceDefs': msgs, |
| 'traceFamily': 'PS' |
| }, |
| sort_keys=True, |
| # escape utf-8 to ascii |
| ensure_ascii=True, |
| indent=2 |
| ) |
| filename = os.path.splitext(os.path.splitext(pstrc_file)[0])[0] +'_'+ module.lower() + '_utmd.json' |
| logging.warning('write to {}'.format(filename)) |
| utmd_file = open(filename, 'w') |
| utmd_file.write(j) |
| new_file.write('// The trace map of {} is converted to UTMD file.\n'.format(module)) |
| new_file.write('// If you wished to modify your trace, please refer to {}\n'.format(os.path.basename(filename))) |
| new_file.write('#include"{}_precodegen.h"\n'.format(os.path.splitext(os.path.basename(filename))[0])) |
| parserState = ParserState.EXPECT_BEGIN |
| module = 'DUMMY' |
| legacyParams = {} |
| msgs = [] |
| else: |
| new_file.write(line) |
| line = file.readline() |
| def main(): |
| global args |
| parser = argparse.ArgumentParser(description='PSTRC-UTMD: UTMD file will be automatically generated aside pstrc_file\n\ |
| xxx_trc.h -> xxx_trc_utmd.json for single trace_map header\n\ |
| xxx_trc.h -> xxx_trc_mod_ooo_utmd.json, xxx_trc_mod_abc_utmd.json for multiple trace_map header\n\ |
| in this case the there are trace_map for MOD_OOO and MOD_ABC', |
| #formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| formatter_class=argparse.RawDescriptionHelpFormatter) |
| parser.add_argument("-v", action="version", version='1.0.0') |
| parser.add_argument("pstrc_file", |
| help="input PS TRC file") |
| parser.add_argument("-l", dest="log_file", |
| help="log file", |
| default='legacy-ps-utmd.log', |
| action="store") |
| args = parser.parse_args() |
| if args.pstrc_file is None: |
| parser.print_help() |
| quit() |
| init_logger(args.log_file) |
| copy(args.pstrc_file, args.pstrc_file+'.bak') |
| expand_file_mapping = {'lpp_trc': 'protocol/agps/lpp/include/', |
| 'mod_dast_trc': 'protocol/ddm/mod_dast/include/', |
| 'vgsm_trc': 'protocol/interface/vgnas/trace/', |
| 'ltecsr_trc': 'protocol/lte_csr/csr/inc/', |
| 'SST_trc': 'service/sst/include/', |
| 'tcm_trc': 'protocol/layer4/l4/tcm/common/' |
| } |
| if(args.pstrc_file.endswith('lpp_trc.h') or |
| args.pstrc_file.endswith('mod_dast_trc.h') or |
| args.pstrc_file.endswith('vgsm_trc.h') or |
| args.pstrc_file.endswith('ltecsr_trc.h') or |
| args.pstrc_file.endswith('SST_trc.h') or |
| os.path.basename(args.pstrc_file) == 'tcm_trc.h' |
| ): |
| logging.info('Inc path: {}'.format(expand_file_mapping[ os.path.splitext(os.path.basename(args.pstrc_file))[0] ]) ) |
| parsePsTrcPreprocessed(args.pstrc_file, expand_file_mapping[ os.path.splitext(os.path.basename(args.pstrc_file))[0] ]) |
| else: |
| tmp_h, tmp_pstrc_file = mkstemp() |
| with os.fdopen(tmp_h, 'w') as new_file: |
| parsePsTrc(args.pstrc_file, new_file) |
| move(tmp_pstrc_file, args.pstrc_file) |
| if __name__ == '__main__': |
| main() |
| |