#!/usr/bin/python #!/neo/opt/bin/python import sys, string, os, getopt, signal, time sys.path.append("../python") import neo_cgi, neo_util import cStringIO class ClearSilverChecker: def __init__ (self): self.context = "" self.data = "" self.at = 0 self.cmd = "" self.tokens = [] def error(self, s): lineno = self.lineno(self.data, self.at) print "-E- [%s:%d] %s" % (self.context, lineno, s) if self.cmd: print " Command is %s" % self.cmd if self.tokens: print " Tokens: %s" % repr(self.tokens) def warn(self, s): lineno = self.lineno(self.data, self.at) print "-W- [%s:%d] %s" % (self.context, lineno, s) if self.cmd: print " Command is %s" % self.cmd if self.tokens: print " Tokens: %s" % repr(self.tokens) def check_file(self, filename): print "Checking file %s" % filename self.context = filename try: self.run_neo_cgi(filename) except neo_util.ParseError, reason: print "-E- %s" % str(reason) self.data = open(filename, "r").read() self.parse() def run_neo_cgi(self, filename): stdin = cStringIO.StringIO("") stdout = cStringIO.StringIO() neo_cgi.cgiWrap(stdin, stdout, {}) neo_cgi.IgnoreEmptyFormVars(1) ncgi = neo_cgi.CGI() path = os.path.dirname(filename) ncgi.hdf.setValue("hdf.loadpaths.path", path) ncgi.display(filename) return def lineno(self, data, i): return len(string.split(data[:i], '\n')) def parse(self): self.at = 0 x = string.find(self.data[self.at:], '<?cs ') while x >= 0: self.at = x + self.at ce = string.find(self.data[self.at:], '?>') if ce == -1: self.error("Missing ?> in expression") else: ce = ce + self.at self.check_command(ce) # reset these class variables self.cmd = "" self.tokens = [] self.at = self.at + 1 x = string.find(self.data[self.at:], '<?cs ') def check_command(self, end): cmd = self.data[self.at+5:end] self.cmd = cmd if cmd[0] == '/': # handle end command cmd = cmd[1:] self.command_end(cmd) return pound = string.find(cmd, '#') colon = string.find(cmd, ':') bang = string.find(cmd, '!') if colon == -1 and bang == -1: if pound != -1: #print "Found comment: %s" % cmd pass else: self.command_begin(string.strip(cmd), "") elif pound != -1 and bang != -1 and pound < bang: # comment #print "Found comment: %s" % cmd pass elif pound != -1 and colon != -1 and pound < colon: # comment #print "Found comment: %s" % cmd pass elif bang == -1: arg = cmd[colon+1:] cmd = cmd[:colon] self.command_begin(cmd, arg) elif colon == -1: arg = cmd[bang+1:] cmd = cmd[:bang] self.command_begin(cmd, arg) def command_end(self, cmd): pass def command_begin(self, cmd, args): #print "%s -> %s" % (cmd, args) if cmd == "alt": self.check_expression(args) elif cmd == "if": self.check_expression(args) elif cmd == "elif": self.check_expression(args) elif cmd == "else": pass elif cmd == "include": self.check_expression(args) elif cmd == "linclude": self.check_expression(args) elif cmd == "name": self.check_expression(args) elif cmd == "var": self.check_expression(args) elif cmd == "evar": self.check_expression(args) elif cmd == "lvar": self.check_expression(args) elif cmd == "def": macro, args = self.split_macro(args) if macro: self.check_expression(macro, lvalue=1) if args:self.check_expression(args) elif cmd == "call": macro, args = self.split_macro(args) if macro: self.check_expression(macro, lvalue=1) if args:self.check_expression(args) elif cmd == "with": varname, args = self.split_equals(args) if varname: self.check_expression(varname, lvalue=1) if args: self.check_expression(args) elif cmd == "each": varname, args = self.split_equals(args) if varname: self.check_expression(varname, lvalue=1) if args: self.check_expression(args) elif cmd == "loop": varname, args = self.split_equals(args) if varname: self.check_expression(varname, lvalue=1) if args: self.check_expression(args) elif cmd == "set": varname, args = self.split_equals(args) if varname: self.check_expression(varname, lvalue=1) if args: self.check_expression(args) else: self.error("Unrecognized command %s" % cmd) def split_equals(self, args): x = string.find(args, '=') if x == -1: self.error("Missing equals") return None, None else: return args[:x], args[x+1:] def split_macro(self, args): b = string.find(args, '(') e = string.rfind(args, ')') if b == -1: self.error("Missing opening parenthesis") return None, None if e == -1: self.error("Missing closing parenthesis") return None, None macro_name = args[:b] args = args[b+1:e] return macro_name, args def check_expression(self, expr, lvalue=0): tokens = self.tokenize_expression(expr) #print repr(tokens) if len(tokens) == 0: self.error("Empty Expression") _OP = 1 _VAR = 2 _VARN = 3 _STR = 4 _NUM = 5 _TOKEN_SEP = "\"?<>=!#-+|&,)*/%[]( \t\r\n" def tokenize_expression(self, expr): self.tokens = [] while expr: #print "expr: '%s'" % expr expr = string.lstrip(expr) len_expr = len(expr) if len_expr == 0: break if expr[:2] in ["<=", ">=", "==", "!=", "||", "&&"]: self.tokens.append((ClearSilverChecker._OP, expr[:2])) expr = expr[2:] continue elif expr[0] in ["!", "?", "<", ">", "+", "-", "*", "/", "%", "(", ")", "[", "]", ".", ',']: self.tokens.append((ClearSilverChecker._OP, expr[0])) expr = expr[1:] continue elif expr[0] in ["#", "$"]: x = 1 if expr[1] in ['+', '-']: x=2 while len_expr > x and expr[x] not in ClearSilverChecker._TOKEN_SEP: x=x+1 if x == 0: self.error("[1] Zero length token, unexpected character %s" % expr[0]) x = 1 else: token = expr[1:x] if expr[0] == "#": try: n = int(token) t_type = ClearSilverChecker._NUM except ValueError: t_type = ClearSilverChecker._VARN else: t_type = ClearSilverChecker._VAR self.tokens.append((t_type, token)) expr = expr[x:] continue elif expr[0] in ['"', "'"]: x = string.find(expr[1:], expr[0]) if x == -1: self.error("Missing end of string %s " % expr) break else: x = x + 1 self.tokens.append((ClearSilverChecker._STR, expr[1:x])) expr = expr[x+2:] continue else: x = 0 while len_expr > x and expr[x] not in ClearSilverChecker._TOKEN_SEP: x=x+1 if x == 0: self.error("[2] Zero length token, unexpected character %s" % expr[0]) x = 1 else: token = expr[:x] try: n = int(token) t_type = ClearSilverChecker._NUM self.warn("This behavior changed in version 0.9: previously this was a variable name, now its a number: %s" % token) except ValueError: t_type = ClearSilverChecker._VAR self.tokens.append((t_type, token)) expr = expr[x:] continue return self.tokens # For version 0.9, we changed two things, we should check for them # both # - an all numeric expression element is now considered a number and # not an HDF variable name # - we now use boolean evaluation in places that used to use either a # special case or a numeric evaluation def usage(argv0): print "%s: usage info!!" % argv0 def main(argv): alist, args = getopt.getopt(argv[1:], "", ["help"]) for (field, val) in alist: if field == "--help": usage(argv[0]) sys.exit(-1) for file in args: ClearSilverChecker().check_file(file) if __name__ == "__main__": main(sys.argv)