summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDaniel Walton <dwalton@cumulusnetworks.com>2016-09-23 15:27:26 +0200
committerDaniel Walton <dwalton@cumulusnetworks.com>2016-09-23 15:27:26 +0200
commita5b5627b8b7e63f73d856802394ed7e39e26da0b (patch)
treeafa6bd1ce8c046e083323293db11f64aa55ed5c1 /tools
parentChange {json} to [json] (diff)
downloadfrr-a5b5627b8b7e63f73d856802394ed7e39e26da0b.tar.xz
frr-a5b5627b8b7e63f73d856802394ed7e39e26da0b.zip
tools: argv_translator convert <1-255> to (1-255), ()s to <>s, etc
Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
Diffstat (limited to 'tools')
-rwxr-xr-xtools/argv_translator.py252
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)