| #!/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) |