rjw | 6c1fd8f | 2022-11-30 14:33:01 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- |
| 3 | import re |
| 4 | import os |
| 5 | import json |
| 6 | import chardet |
| 7 | import logging |
| 8 | import argparse |
| 9 | from tempfile import mkstemp |
| 10 | from shutil import move, copy |
| 11 | class ParserState(): |
| 12 | EXPECT_BEGIN='(BEGIN_TRACE_MAP_WITH_RANGE|BEGIN_TRACE_MAP)\(\s*(\w+)\s*(,*\s*(\d+)\s*)?\s*(,*\s*(\d+)\s*)?\)' |
| 13 | TRC_MSG= r'TRC_MSG\s*\(\s*([_a-zA-Z][_a-zA-Z0-9]+)\s*,\s*\"((\\.|[^"\\])*)\"(\w+\"(\\.|[^"\\]*)\")*\s*\)' |
| 14 | END_TRACE_MAP='(END_TRACE_MAP_WITH_RANGE|END_TRACE_MAP)\(\s*(\w+)\s*(,*\s*(\d+)\s*)?\s*(,*\s*(\d+)\s*)?\)' |
| 15 | args = None |
| 16 | module = 'DUMMY' |
| 17 | legacyParams = {} |
| 18 | msgs = [] |
| 19 | moduleList = [] |
| 20 | classes = [ |
| 21 | { 'TRACE_INFO': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 22 | { 'TRACE_WARNING': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 23 | { 'TRACE_ERROR': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 24 | { 'TRACE_FUNC': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 25 | { 'TRACE_STATE': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 26 | { 'TRACE_GROUP1': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 27 | { 'TRACE_GROUP2': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 28 | { 'TRACE_GROUP3': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 29 | { 'TRACE_GROUP4': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 30 | { 'TRACE_GROUP5': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 31 | { 'TRACE_GROUP6': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 32 | { 'TRACE_GROUP7': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 33 | { 'TRACE_GROUP8': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 34 | { 'TRACE_GROUP9': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } }, |
| 35 | { 'TRACE_GROUP10': { 'tag': ['Baseline'], 'traceType': 'Public', 'debugLevel': 'Ultra-Low' } } |
| 36 | ] |
| 37 | |
| 38 | def init_logger(log_filename): |
| 39 | logging.basicConfig(level=logging.DEBUG, |
| 40 | format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', |
| 41 | datefmt='%m-%d %H:%M:%S', |
| 42 | filename=log_filename) |
| 43 | console = logging.StreamHandler() |
| 44 | console.setLevel(logging.DEBUG) |
| 45 | formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') |
| 46 | console.setFormatter(formatter) |
| 47 | logging.getLogger('').addHandler(console) |
| 48 | def parsePsTrcPreprocessed(pstrc_file, inc_path): |
| 49 | global moduleList |
| 50 | tmp_h, tmp_pstrc_file = mkstemp() |
| 51 | with os.fdopen(tmp_h, 'w') as new_file: |
| 52 | prep_pstrc_file = pstrc_file+'.tmp' |
| 53 | logging.info('PreProcessing {}'.format(prep_pstrc_file)) |
| 54 | 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)) |
| 55 | parsePsTrc(prep_pstrc_file, new_file) |
| 56 | logging.info('Processing {}'.format(pstrc_file)) |
| 57 | parserState = ParserState.EXPECT_BEGIN |
| 58 | tmp_h, tmp_pstrc_file = mkstemp() |
| 59 | with os.fdopen(tmp_h, 'w') as new_file: |
| 60 | file = open(pstrc_file) |
| 61 | line = file.readline() |
| 62 | while line: |
| 63 | stripped= line.rstrip().lstrip() |
| 64 | if stripped == '': |
| 65 | line = file.readline() |
| 66 | continue |
| 67 | logging.debug('[IO] State {}: line: {}'.format(parserState, stripped)) |
| 68 | if parserState == ParserState.EXPECT_BEGIN: |
| 69 | if re.match(ParserState.EXPECT_BEGIN, stripped, re.IGNORECASE): |
| 70 | match = re.search(ParserState.EXPECT_BEGIN, stripped) |
| 71 | if match: |
| 72 | parserState = ParserState.TRC_MSG |
| 73 | else: |
| 74 | new_file.write(line) |
| 75 | else: |
| 76 | new_file.write(line) |
| 77 | elif parserState == ParserState.TRC_MSG: |
| 78 | if re.match(ParserState.END_TRACE_MAP, stripped, re.IGNORECASE): |
| 79 | _m = moduleList.pop(0) |
| 80 | j = json.dumps(_m, |
| 81 | sort_keys=True, |
| 82 | # escape utf-8 to ascii |
| 83 | ensure_ascii=True, |
| 84 | indent=2 |
| 85 | ) |
| 86 | filename = os.path.splitext(pstrc_file)[0] +'_'+ _m['module'].lower() + '_utmd.json' |
| 87 | new_file.write('// The trace map of {} is converted to UTMD file.\n'.format(module)) |
| 88 | new_file.write('// If you wished to modify your trace, please refer to {}\n'.format(os.path.basename(filename))) |
| 89 | new_file.write('#include"{}_precodegen.h"\n'.format(os.path.splitext(os.path.basename(filename))[0])) |
| 90 | parserState = ParserState.EXPECT_BEGIN |
| 91 | else: |
| 92 | new_file.write(line) |
| 93 | line = file.readline() |
| 94 | #force output for lpp_trc.h (no END_TRACE_MAP in file...) |
| 95 | for _m in moduleList: |
| 96 | filename = os.path.splitext(pstrc_file)[0] +'_'+ _m['module'].lower() + '_utmd.json' |
| 97 | new_file.write('// The trace map of {} is converted to UTMD file.\n'.format(module)) |
| 98 | new_file.write('// If you wished to modify your trace, please refer to {}\n'.format(os.path.basename(filename))) |
| 99 | new_file.write('#include"{}_precodegen.h"\n'.format(os.path.splitext(os.path.basename(filename))[0])) |
| 100 | if pstrc_file.endswith('lpp_trc.h'): |
| 101 | new_file.write('#endif /* _LPP_TRC_H */\n') |
| 102 | move(tmp_pstrc_file, pstrc_file) |
| 103 | def parsePsTrc(pstrc_file, new_file): |
| 104 | global module |
| 105 | global legacyParams |
| 106 | global classes |
| 107 | global msgs |
| 108 | global moduleList |
| 109 | logging.info('Processing {}'.format(pstrc_file)) |
| 110 | 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)) |
| 111 | parserState = ParserState.EXPECT_BEGIN |
| 112 | with open(pstrc_file) as file: |
| 113 | line = file.readline() |
| 114 | while line: |
| 115 | stripped= line.rstrip().lstrip() |
| 116 | if stripped == '': |
| 117 | line = file.readline() |
| 118 | continue |
| 119 | logging.debug('[IO] State {}: line: {}'.format(parserState, stripped)) |
| 120 | if parserState == ParserState.EXPECT_BEGIN: |
| 121 | if re.match(ParserState.EXPECT_BEGIN, stripped, re.IGNORECASE): |
| 122 | match = re.search(ParserState.EXPECT_BEGIN, stripped) |
| 123 | if match: |
| 124 | global module |
| 125 | module = match.group(2) |
| 126 | if match.group(4) and match.group(6): |
| 127 | legacyParams.update( {'predefinedMessageRange': { 'min': int(match.group(4)), 'max': int(match.group(6)) } } ) |
| 128 | else: |
| 129 | logging.warning("4th group / 6th group not found") |
| 130 | parserState = ParserState.TRC_MSG |
| 131 | else: |
| 132 | new_file.write(line) |
| 133 | else: |
| 134 | new_file.write(line) |
| 135 | elif parserState == ParserState.TRC_MSG: |
| 136 | if stripped.startswith('/*'): |
| 137 | while not stripped.endswith('*/'): |
| 138 | c = file.read(1) |
| 139 | stripped = stripped + c |
| 140 | line = file.readline() |
| 141 | continue |
| 142 | if stripped.startswith('TRC_MSG'): |
| 143 | while not re.match(ParserState.TRC_MSG, stripped, re.IGNORECASE) and line: |
| 144 | if stripped.endswith('\\'): |
| 145 | stripped = stripped[:-1:] |
| 146 | line = file.readline().lstrip().rstrip() |
| 147 | stripped = stripped + line |
| 148 | logging.error('strip anti-slash {}'.format(stripped)) |
| 149 | else: |
| 150 | line = file.readline().lstrip().rstrip() |
| 151 | stripped = stripped + line |
| 152 | logging.error('strip anti-slash {}'.format(stripped)) |
| 153 | # detect character encoding and transform to utf8 |
| 154 | if chardet.detect(stripped)['confidence'] > 0.75: |
| 155 | logging.debug('decode by {}'.format(chardet.detect(stripped)['encoding'])) |
| 156 | stripped = stripped.decode(chardet.detect(stripped)['encoding']).encode('utf8') |
| 157 | match = re.search(ParserState.TRC_MSG, stripped) |
| 158 | trc = {} |
| 159 | trc['traceClass'] = 'TRACE_INFO' |
| 160 | if match.group(4): |
| 161 | trc['format'] = match.group(2) + re.sub('"', '', match.group(4)) |
| 162 | else: |
| 163 | trc['format'] = match.group(2) |
| 164 | if not filter( lambda x: match.group(1) in x, msgs): |
| 165 | msgs.append( { match.group(1): trc } ) |
| 166 | else: |
| 167 | logging.error('Msg redefined {}'.format(match.group(1))) |
| 168 | logging.debug(match) |
| 169 | elif re.match(ParserState.END_TRACE_MAP, stripped, re.IGNORECASE): |
| 170 | moduleList.append({'module':module, |
| 171 | 'legacyParameters': legacyParams, |
| 172 | 'traceClassDefs': classes, |
| 173 | 'traceDefs': msgs, |
| 174 | 'traceFamily': 'PS' |
| 175 | }) |
| 176 | j = json.dumps({'module':module, |
| 177 | 'legacyParameters': legacyParams, |
| 178 | 'traceClassDefs': classes, |
| 179 | 'traceDefs': msgs, |
| 180 | 'traceFamily': 'PS' |
| 181 | }, |
| 182 | sort_keys=True, |
| 183 | # escape utf-8 to ascii |
| 184 | ensure_ascii=True, |
| 185 | indent=2 |
| 186 | ) |
| 187 | filename = os.path.splitext(os.path.splitext(pstrc_file)[0])[0] +'_'+ module.lower() + '_utmd.json' |
| 188 | logging.warning('write to {}'.format(filename)) |
| 189 | utmd_file = open(filename, 'w') |
| 190 | utmd_file.write(j) |
| 191 | new_file.write('// The trace map of {} is converted to UTMD file.\n'.format(module)) |
| 192 | new_file.write('// If you wished to modify your trace, please refer to {}\n'.format(os.path.basename(filename))) |
| 193 | new_file.write('#include"{}_precodegen.h"\n'.format(os.path.splitext(os.path.basename(filename))[0])) |
| 194 | parserState = ParserState.EXPECT_BEGIN |
| 195 | module = 'DUMMY' |
| 196 | legacyParams = {} |
| 197 | msgs = [] |
| 198 | else: |
| 199 | new_file.write(line) |
| 200 | line = file.readline() |
| 201 | def main(): |
| 202 | global args |
| 203 | parser = argparse.ArgumentParser(description='PSTRC-UTMD: UTMD file will be automatically generated aside pstrc_file\n\ |
| 204 | xxx_trc.h -> xxx_trc_utmd.json for single trace_map header\n\ |
| 205 | xxx_trc.h -> xxx_trc_mod_ooo_utmd.json, xxx_trc_mod_abc_utmd.json for multiple trace_map header\n\ |
| 206 | in this case the there are trace_map for MOD_OOO and MOD_ABC', |
| 207 | #formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| 208 | formatter_class=argparse.RawDescriptionHelpFormatter) |
| 209 | parser.add_argument("-v", action="version", version='1.0.0') |
| 210 | parser.add_argument("pstrc_file", |
| 211 | help="input PS TRC file") |
| 212 | parser.add_argument("-l", dest="log_file", |
| 213 | help="log file", |
| 214 | default='legacy-ps-utmd.log', |
| 215 | action="store") |
| 216 | args = parser.parse_args() |
| 217 | if args.pstrc_file is None: |
| 218 | parser.print_help() |
| 219 | quit() |
| 220 | init_logger(args.log_file) |
| 221 | copy(args.pstrc_file, args.pstrc_file+'.bak') |
| 222 | expand_file_mapping = {'lpp_trc': 'protocol/agps/lpp/include/', |
| 223 | 'mod_dast_trc': 'protocol/ddm/mod_dast/include/', |
| 224 | 'vgsm_trc': 'protocol/interface/vgnas/trace/', |
| 225 | 'ltecsr_trc': 'protocol/lte_csr/csr/inc/', |
| 226 | 'SST_trc': 'service/sst/include/', |
| 227 | 'tcm_trc': 'protocol/layer4/l4/tcm/common/' |
| 228 | } |
| 229 | if(args.pstrc_file.endswith('lpp_trc.h') or |
| 230 | args.pstrc_file.endswith('mod_dast_trc.h') or |
| 231 | args.pstrc_file.endswith('vgsm_trc.h') or |
| 232 | args.pstrc_file.endswith('ltecsr_trc.h') or |
| 233 | args.pstrc_file.endswith('SST_trc.h') or |
| 234 | os.path.basename(args.pstrc_file) == 'tcm_trc.h' |
| 235 | ): |
| 236 | logging.info('Inc path: {}'.format(expand_file_mapping[ os.path.splitext(os.path.basename(args.pstrc_file))[0] ]) ) |
| 237 | parsePsTrcPreprocessed(args.pstrc_file, expand_file_mapping[ os.path.splitext(os.path.basename(args.pstrc_file))[0] ]) |
| 238 | else: |
| 239 | tmp_h, tmp_pstrc_file = mkstemp() |
| 240 | with os.fdopen(tmp_h, 'w') as new_file: |
| 241 | parsePsTrc(args.pstrc_file, new_file) |
| 242 | move(tmp_pstrc_file, args.pstrc_file) |
| 243 | if __name__ == '__main__': |
| 244 | main() |
| 245 | |