# explode-macro.py # Copyright 2006, Eli Fulkerson # www.elifulkerson.com # # Syntax and explanation at http://www.elifulkerson.com/projects/macro-language-for-cisco-configuration.php # # import string import re import sys class Block: "A Block is a set of lines that may be repeated, with their children, arbitrarily" def __init__(self, str, parent): self.str = string.strip(str) self.parent = parent self.children = [] def addchild(self, child): self.children.append(child) def output(self,indent=-1): regex_variable = re.compile('\{\w+\}') regex_range = re.compile('\{\d+-\d+\}') match = regex_range.findall(self.str) start,stop = 1,2 global interval # There is some redundent code here... if match: tmp = match[0] tmp = string.replace(tmp, "{", "") tmp = string.replace(tmp, "}", "") tmp = string.replace(tmp, "-", " ") start,stop = string.split(tmp) for each in range(int(start), int(stop)+1): print " " * interval * indent + string.replace(self.str, match[0], str(each)) for each in self.children: each.output(indent+1) return match = regex_variable.findall(self.str) if match: global defines tmp = match[0] tmp = string.replace(tmp, "{", "") tmp = string.replace(tmp, "}", "") print " " * interval * indent + string.replace(self.str, match[0], defines[tmp]) for each in self.children: each.output(indent+1) return print " " * interval * indent + self.str for each in self.children: each.output(indent+1) examplesyntax = """ interface FastEthernet0/{1-20} switchport access vlan {visitor_vlan} no shutdown interface FastEthernet0/{21-30} switchport access vlan {staff_vlan} no shutdown #define visitor_vlan 200 #define staff_vlan 100 """ try: filename = sys.argv[1] f = open(filename, 'r') filestring = f.read() f.close() except: print "Error: You haven't specified an input file." print "" print "Syntax is:" print "explode-macro.py " print "" print "Any line including {a-b}, where a and b are integers, will be" print "output once for each integer value between a and b inclusive, with" print "the value replacing {a-b}" print "" print "Any line including {something}, where there is no '-' character, will" print "output the value from a corresponding:" print "#define something blah" print "... line." print "" print "Example:" print examplesyntax sys.exit(1) regex_define = re.compile('^#define\s\w+\s.+') regex_variable = re.compile('\{\w+\}') regex_range = re.compile('\{\d+-\d+\}') regex_tabs = re.compile('^\s+') global defines defines = {} global interval interval = 0 numspaces = 0 oldspaces = 0 root = Block("", 0) current = root " first, build the structure and read in the defines... " for line in string.split(filestring, "\n"): " count the number of leading spaces " oldspaces = numspaces numspaces = 0 match = regex_tabs.findall(line) if match: numspaces = len(match[0]) if oldspaces != numspaces: if interval == 0: interval = numspaces - oldspaces else: if (oldspaces - numspaces) % interval != 0: print "Error! Unusual block spacing. Once a spacing interval is set, all remaining lines must be a multiple of it." sys.exit(1) " we don't worry about queuing up #define statements... just save the values " match = regex_define.findall(line) if match: key,val=string.split(match[0])[1:] defines[key] = val else: line = string.strip(line) " this is a child element " if numspaces > oldspaces: tmp = Block(line, last) last.addchild(tmp) current = last " this is a peer element " if numspaces == oldspaces: tmp = Block(line, current) current.addchild(tmp) " we have to go up. We may have to skip several layers. Check the interval " if numspaces < oldspaces: x = 0 while x < (oldspaces - numspaces) / interval: current = current.parent x = x + 1 tmp = Block(line, current) current.addchild(tmp) last = tmp " The structure is built, let it output itself " root.output()