1#!/usr/bin/python 2#!/neo/opt/bin/python 3 4import sys, string, os, getopt, signal, time 5sys.path.append("../python") 6import neo_cgi, neo_util 7import cStringIO 8 9class ClearSilverChecker: 10 def __init__ (self): 11 self.context = "" 12 self.data = "" 13 self.at = 0 14 self.cmd = "" 15 self.tokens = [] 16 17 def error(self, s): 18 lineno = self.lineno(self.data, self.at) 19 print "-E- [%s:%d] %s" % (self.context, lineno, s) 20 if self.cmd: 21 print " Command is %s" % self.cmd 22 if self.tokens: 23 print " Tokens: %s" % repr(self.tokens) 24 25 def warn(self, s): 26 lineno = self.lineno(self.data, self.at) 27 print "-W- [%s:%d] %s" % (self.context, lineno, s) 28 if self.cmd: 29 print " Command is %s" % self.cmd 30 if self.tokens: 31 print " Tokens: %s" % repr(self.tokens) 32 33 def check_file(self, filename): 34 print "Checking file %s" % filename 35 self.context = filename 36 try: 37 self.run_neo_cgi(filename) 38 except neo_util.ParseError, reason: 39 print "-E- %s" % str(reason) 40 self.data = open(filename, "r").read() 41 self.parse() 42 43 def run_neo_cgi(self, filename): 44 stdin = cStringIO.StringIO("") 45 stdout = cStringIO.StringIO() 46 neo_cgi.cgiWrap(stdin, stdout, {}) 47 neo_cgi.IgnoreEmptyFormVars(1) 48 ncgi = neo_cgi.CGI() 49 path = os.path.dirname(filename) 50 ncgi.hdf.setValue("hdf.loadpaths.path", path) 51 ncgi.display(filename) 52 return 53 54 def lineno(self, data, i): 55 return len(string.split(data[:i], '\n')) 56 57 def parse(self): 58 self.at = 0 59 x = string.find(self.data[self.at:], '<?cs ') 60 while x >= 0: 61 self.at = x + self.at 62 ce = string.find(self.data[self.at:], '?>') 63 if ce == -1: 64 self.error("Missing ?> in expression") 65 else: 66 ce = ce + self.at 67 self.check_command(ce) 68 69 # reset these class variables 70 self.cmd = "" 71 self.tokens = [] 72 self.at = self.at + 1 73 x = string.find(self.data[self.at:], '<?cs ') 74 75 def check_command(self, end): 76 cmd = self.data[self.at+5:end] 77 self.cmd = cmd 78 if cmd[0] == '/': 79 # handle end command 80 cmd = cmd[1:] 81 self.command_end(cmd) 82 return 83 84 pound = string.find(cmd, '#') 85 colon = string.find(cmd, ':') 86 bang = string.find(cmd, '!') 87 if colon == -1 and bang == -1: 88 if pound != -1: 89 #print "Found comment: %s" % cmd 90 pass 91 else: 92 self.command_begin(string.strip(cmd), "") 93 elif pound != -1 and bang != -1 and pound < bang: 94 # comment 95 #print "Found comment: %s" % cmd 96 pass 97 elif pound != -1 and colon != -1 and pound < colon: 98 # comment 99 #print "Found comment: %s" % cmd 100 pass 101 elif bang == -1: 102 arg = cmd[colon+1:] 103 cmd = cmd[:colon] 104 self.command_begin(cmd, arg) 105 elif colon == -1: 106 arg = cmd[bang+1:] 107 cmd = cmd[:bang] 108 self.command_begin(cmd, arg) 109 110 def command_end(self, cmd): 111 pass 112 113 def command_begin(self, cmd, args): 114 #print "%s -> %s" % (cmd, args) 115 if cmd == "alt": 116 self.check_expression(args) 117 elif cmd == "if": 118 self.check_expression(args) 119 elif cmd == "elif": 120 self.check_expression(args) 121 elif cmd == "else": 122 pass 123 elif cmd == "include": 124 self.check_expression(args) 125 elif cmd == "linclude": 126 self.check_expression(args) 127 elif cmd == "name": 128 self.check_expression(args) 129 elif cmd == "var": 130 self.check_expression(args) 131 elif cmd == "evar": 132 self.check_expression(args) 133 elif cmd == "lvar": 134 self.check_expression(args) 135 elif cmd == "def": 136 macro, args = self.split_macro(args) 137 if macro: self.check_expression(macro, lvalue=1) 138 if args:self.check_expression(args) 139 elif cmd == "call": 140 macro, args = self.split_macro(args) 141 if macro: self.check_expression(macro, lvalue=1) 142 if args:self.check_expression(args) 143 elif cmd == "with": 144 varname, args = self.split_equals(args) 145 if varname: self.check_expression(varname, lvalue=1) 146 if args: self.check_expression(args) 147 elif cmd == "each": 148 varname, args = self.split_equals(args) 149 if varname: self.check_expression(varname, lvalue=1) 150 if args: self.check_expression(args) 151 elif cmd == "loop": 152 varname, args = self.split_equals(args) 153 if varname: self.check_expression(varname, lvalue=1) 154 if args: self.check_expression(args) 155 elif cmd == "set": 156 varname, args = self.split_equals(args) 157 if varname: self.check_expression(varname, lvalue=1) 158 if args: self.check_expression(args) 159 else: 160 self.error("Unrecognized command %s" % cmd) 161 162 def split_equals(self, args): 163 x = string.find(args, '=') 164 if x == -1: 165 self.error("Missing equals") 166 return None, None 167 else: 168 return args[:x], args[x+1:] 169 170 def split_macro(self, args): 171 b = string.find(args, '(') 172 e = string.rfind(args, ')') 173 if b == -1: 174 self.error("Missing opening parenthesis") 175 return None, None 176 if e == -1: 177 self.error("Missing closing parenthesis") 178 return None, None 179 macro_name = args[:b] 180 args = args[b+1:e] 181 return macro_name, args 182 183 def check_expression(self, expr, lvalue=0): 184 tokens = self.tokenize_expression(expr) 185 #print repr(tokens) 186 if len(tokens) == 0: 187 self.error("Empty Expression") 188 189 _OP = 1 190 _VAR = 2 191 _VARN = 3 192 _STR = 4 193 _NUM = 5 194 195 _TOKEN_SEP = "\"?<>=!#-+|&,)*/%[]( \t\r\n" 196 197 def tokenize_expression(self, expr): 198 self.tokens = [] 199 while expr: 200 #print "expr: '%s'" % expr 201 expr = string.lstrip(expr) 202 len_expr = len(expr) 203 if len_expr == 0: break 204 if expr[:2] in ["<=", ">=", "==", "!=", "||", "&&"]: 205 self.tokens.append((ClearSilverChecker._OP, expr[:2])) 206 expr = expr[2:] 207 continue 208 elif expr[0] in ["!", "?", "<", ">", "+", "-", "*", "/", "%", "(", ")", "[", "]", ".", ',']: 209 self.tokens.append((ClearSilverChecker._OP, expr[0])) 210 expr = expr[1:] 211 continue 212 elif expr[0] in ["#", "$"]: 213 x = 1 214 if expr[1] in ['+', '-']: x=2 215 while len_expr > x and expr[x] not in ClearSilverChecker._TOKEN_SEP: x=x+1 216 if x == 0: 217 self.error("[1] Zero length token, unexpected character %s" % expr[0]) 218 x = 1 219 else: 220 token = expr[1:x] 221 if expr[0] == "#": 222 try: 223 n = int(token) 224 t_type = ClearSilverChecker._NUM 225 except ValueError: 226 t_type = ClearSilverChecker._VARN 227 else: 228 t_type = ClearSilverChecker._VAR 229 self.tokens.append((t_type, token)) 230 expr = expr[x:] 231 continue 232 elif expr[0] in ['"', "'"]: 233 x = string.find(expr[1:], expr[0]) 234 if x == -1: 235 self.error("Missing end of string %s " % expr) 236 break 237 else: 238 x = x + 1 239 self.tokens.append((ClearSilverChecker._STR, expr[1:x])) 240 expr = expr[x+2:] 241 continue 242 else: 243 x = 0 244 while len_expr > x and expr[x] not in ClearSilverChecker._TOKEN_SEP: x=x+1 245 if x == 0: 246 self.error("[2] Zero length token, unexpected character %s" % expr[0]) 247 x = 1 248 else: 249 token = expr[:x] 250 try: 251 n = int(token) 252 t_type = ClearSilverChecker._NUM 253 self.warn("This behavior changed in version 0.9: previously this was a variable name, now its a number: %s" % token) 254 except ValueError: 255 t_type = ClearSilverChecker._VAR 256 self.tokens.append((t_type, token)) 257 expr = expr[x:] 258 continue 259 return self.tokens 260 261 # For version 0.9, we changed two things, we should check for them 262 # both 263 # - an all numeric expression element is now considered a number and 264 # not an HDF variable name 265 # - we now use boolean evaluation in places that used to use either a 266 # special case or a numeric evaluation 267 268def usage(argv0): 269 print "%s: usage info!!" % argv0 270 271def main(argv): 272 alist, args = getopt.getopt(argv[1:], "", ["help"]) 273 274 for (field, val) in alist: 275 if field == "--help": 276 usage(argv[0]) 277 sys.exit(-1) 278 279 for file in args: 280 ClearSilverChecker().check_file(file) 281 282if __name__ == "__main__": 283 main(sys.argv) 284