diff options
Diffstat (limited to 'tools/argv_translator.py')
-rwxr-xr-x | tools/argv_translator.py | 252 |
1 files changed, 217 insertions, 35 deletions
diff --git a/tools/argv_translator.py b/tools/argv_translator.py index 3464a81d7..08a680066 100755 --- a/tools/argv_translator.py +++ b/tools/argv_translator.py @@ -3,7 +3,9 @@ import re import sys import os -from pprint import pformat +import subprocess +from copy import deepcopy +from pprint import pformat, pprint def token_is_variable(line_number, token): @@ -28,26 +30,16 @@ def token_is_variable(line_number, token): assert '|' not in token, "%d: Weird token %s has a | but does not start with [ or (" % (line_number, token) if token in ('WORD', - '.LINE', # where is this defined? - 'LINE', - 'BANDWIDTH', - 'RMAP_NAME', - 'ROUTEMAP_NAME', - 'IPV6ADDR', - 'IF_OR_ADDR', - 'INTERFACE', - 'PERCENTAGE', - 'IFNAME', - 'NAME', - 'BITPATTERN', - 'PATH', + '.LINE', + '.AA:NN', 'A.B.C.D', 'A.B.C.D/M', 'X:X::X:X', 'X:X::X:X/M', - 'ASN:nn_or_IP-address:nn'): # where is this defined? + 'ASN:nn_or_IP-address:nn'): return True + # Anything in all caps in a variable if token.upper() == token: return True @@ -58,10 +50,7 @@ def token_is_variable(line_number, token): return False - tokens = [] - - -def line_to_tokens(text): +def line_to_tokens(line_number, text): """ Most of the time whitespace can be used to split tokens (set|clear) <interface> clagd-enable (no|yes) @@ -92,7 +81,8 @@ def line_to_tokens(text): for char in text: if char == ' ': if parens == 0 and brackets == 0 and curlys == 0 and less_greater == 0: - tokens.append(''.join(token_text)) + if token_text: + tokens.append(''.join(token_text)) token_index += 1 token_text = [] else: @@ -122,7 +112,8 @@ def line_to_tokens(text): elif char == '>': less_greater -= 1 - token_text.append(char) + if char: + token_text.append(char) if token_text: tokens.append(''.join(token_text)) @@ -130,6 +121,8 @@ def line_to_tokens(text): return tokens +''' +# No longer used now that all indexes have been updated def get_argv_translator(line_number, line): table = {} line = line.strip() @@ -149,14 +142,146 @@ def get_argv_translator(line_number, line): continue if token_is_variable(line_number, token): - print "%s is a token" % token + # print "%s is a token" % token table[old_style_index] = token_index old_style_index += 1 else: - print "%s is NOT a token" % token + # print "%s is NOT a token" % token pass return table +''' + +def get_argv_variable_indexes(line_number, line): + indexes = {} + + line = line.strip() + assert line.startswith('"'), "%d: line does not start with \"\n%s" % (line_number, line) + assert line.endswith('",'), "%d: line does not end with \",\n%s" % (line_number, line) + line = line[1:-2] + max_index = 0 + + for (token_index, token) in enumerate(line_to_tokens(line_number, line)): + if not token: + raise Exception("%d: empty token" % line_number) + + if token_is_variable(line_number, token): + # print "%s is a token" % token + indexes[token_index] = True + max_index = token_index + + return (max_index, indexes) + + +class DEFUN(object): + + def __init__(self, line_number, command_string_expanded, lines): + # name, name_cmd, command_string, help_strings, guts): + self.line_number = line_number + self.name = None + self.name_cmd = None + self.command_string = None + self.command_string_expanded = command_string_expanded + self.help_strings = [] + self.guts = [] + + ''' +DEFUN (no_bgp_maxmed_onstartup, + no_bgp_maxmed_onstartup_cmd, + "no bgp max-med on-startup", + NO_STR + BGP_STR + "Advertise routes with max-med\n" + "Effective on a startup\n") + + ''' + state = 'HEADER' + for (line_number, line) in enumerate(lines): + + if state == 'HEADER': + if line_number == 0: + re_name = re.search('DEFUN \((.*),', line.strip()) + self.name = re_name.group(1) + + elif line_number == 1: + self.name_cmd = line.strip()[0:-1] # chop the trailing comma + + elif line_number == 2: + self.command_string = line + state = 'HELP' + + elif state == 'HELP': + if line.strip() == '{': + self.guts.append(line) + state = 'BODY' + else: + self.help_strings.append(line) + + elif state == 'BODY': + if line.rstrip() == '}': + self.guts.append(line) + state = None + else: + self.guts.append(line) + + else: + raise Exception("invalid state %s" % state) + + # print "%d %7s: %s" % (line_number, state, line.rstrip()) + + assert self.command_string, "No command string for\n%s" % pformat(lines) + + def __str__(self): + return self.name + + def sanity_check(self): + (max_index, variable_indexes) = get_argv_variable_indexes(self.line_number, self.command_string_expanded) + + # sanity check that each argv index matches a variable in the command string + for line in self.guts: + if 'argv[' in line and '->arg' in line: + tmp_line = deepcopy(line) + re_argv = re.search('^.*?argv\[(\d+)\]->arg(.*)$', tmp_line) + + while re_argv: + index = int(re_argv.group(1)) + if index not in variable_indexes and index <= max_index: + raise Exception("%d: index %s is not a variable in the command string" % (self.line_number, index)) + tmp_line = re_argv.group(2) + re_argv = re.search('^.*?argv\[(\d+)\]->arg(.*)$', tmp_line) + + def get_new_command_string(self): + line = self.command_string + # dwalton + # Change <1-255> to (1-255) + # Change (foo|bar) to <foo|bar> + # Change {wazzup} to [wazzup]....there shouldn't be many of these + + line = line.replace('(', '<') + line = line.replace(')', '>') + line = line.replace('{', '[') + line = line.replace('}', ']') + re_range = re.search('^(.*?)<(\d+-\d+)>(.*)$', line) + + while re_range: + line = "%s(%s)%s" % (re_range.group(1), re_range.group(2), re_range.group(3)) + re_range = re.search('^(.*?)<(\d+-\d+)>(.*)$', line) + + if not line.endswith('\n'): + line += '\n' + + return line + + def dump(self): + lines = [] + lines.append("DEFUN (%s,\n" % self.name) + lines.append(" %s,\n" % self.name_cmd) + lines.append(self.get_new_command_string()) + lines.extend(self.help_strings) + lines.extend(self.guts) + return ''.join(lines) + + def update_argvs(filename): @@ -166,19 +291,27 @@ def update_argvs(filename): state = None defun_line_number = None cmd_string = None - argv_translator = {} - print_translator = False + # argv_translator = {} + # print_translator = False + variable_indexes = {} + max_index = 0 + defun_lines = [] + defuns = {} + command_string = None for (line_number, line) in enumerate(fh.readlines()): - new_line = line + # new_line = line if state is None: if line.startswith('DEFUN ('): assert line.count(',') == 1, "%d: Too many commas in\n%s" % (line_number, line) state = 'DEFUN_HEADER' defun_line_number = line_number + defun_lines.append(line) elif state == 'DEFUN_HEADER': + defun_lines.append(line) + if line.startswith('DEFUN'): raise Exception("ERROR on line %d, found DEFUN inside DEFUN" % line_number) @@ -259,40 +392,89 @@ def update_argvs(filename): if line.rstrip().endswith('" ,'): line = line.replace('" ,', '",') + command_string = line + ''' + # No longer used now that all indexes have been updated argv_translator = get_argv_translator(line_number, line) print_translator = True + ''' elif state == 'DEFUN_BODY': + defun_lines.append(line) + if line.rstrip() == '}': + new_defun = DEFUN(defun_line_number, command_string, defun_lines) + defuns[new_defun.name] = new_defun state = None - defun_line_number = None - cmd_string = None - argv_translator = {} + command_string = None + defun_lines = [] + # cmd_string = None + # defun_line_number = None + # argv_translator = {} + + ''' + # No longer used now that all indexes have been updated elif 'argv[' in new_line and '->arg' not in new_line: for index in reversed(argv_translator.keys()): old_argv = "argv[%d]" % index new_argv = "argv[%d]->arg" % argv_translator[index] new_line = new_line.replace(old_argv, new_argv) + ''' # uncomment to debug state machine - print "%5d %12s: %s" % (line_number, state, new_line.rstrip()) + # print "%5d %12s: %s" % (line_number, state, line.rstrip()) + + ''' + # No longer used now that all indexes have been updated if print_translator: print "%s\n" % pformat(argv_translator) print_translator = False + ''' + + lines.append(line) + - lines.append(new_line) + for defun in defuns.itervalues(): + defun.sanity_check() + + # Now write the file but allow the DEFUN object to update the contents of the DEFUN () with open(filename, 'w') as fh: + state = None + for line in lines: - fh.write(line) + + if state is None: + if line.startswith('DEFUN ('): + state = 'DEFUN_HEADER' + re_name = re.search('DEFUN \((.*),', line.strip()) + name = re_name.group(1) + defun = defuns.get(name) + fh.write(defun.dump()) + else: + fh.write(line) + + elif state == 'DEFUN_HEADER': + if line.strip() == '{': + state = 'DEFUN_BODY' + + elif state == 'DEFUN_BODY': + if line.rstrip() == '}': + state = None + if __name__ == '__main__': - filename = sys.argv[1] - if os.path.exists(filename): + if len(sys.argv) == 2: + filename = sys.argv[1] update_argvs(filename) + else: - print "ERROR: could not find file %s" % filename + output = subprocess.check_output("grep -l DEFUN *.c", shell=True).splitlines() + for filename in output: + filename = filename.strip() + print "crunching %s" % filename + update_argvs(filename) |