xen-vtx-unstable
diff docs/pythfilter.py @ 6781:8ca0f98ba8e2
merge?
author | cl349@firebug.cl.cam.ac.uk |
---|---|
date | Tue Sep 13 15:33:37 2005 +0000 (2005-09-13) |
parents | 4d899a738d59 |
children | 72e4e2aab342 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/docs/pythfilter.py Tue Sep 13 15:33:37 2005 +0000 1.3 @@ -0,0 +1,658 @@ 1.4 +#!/usr/bin/env python 1.5 + 1.6 +# pythfilter.py v1.5.5, written by Matthias Baas (baas@ira.uka.de) 1.7 + 1.8 +# Doxygen filter which can be used to document Python source code. 1.9 +# Classes (incl. methods) and functions can be documented. 1.10 +# Every comment that begins with ## is literally turned into an 1.11 +# Doxygen comment. Consecutive comment lines are turned into 1.12 +# comment blocks (-> /** ... */). 1.13 +# All the stuff is put inside a namespace with the same name as 1.14 +# the source file. 1.15 + 1.16 +# Conversions: 1.17 +# ============ 1.18 +# ##-blocks -> /** ... */ 1.19 +# "class name(base): ..." -> "class name : public base {...}" 1.20 +# "def name(params): ..." -> "name(params) {...}" 1.21 + 1.22 +# Changelog: 1.23 +# 21.01.2003: Raw (r"") or unicode (u"") doc string will now be properly 1.24 +# handled. (thanks to Richard Laager for the patch) 1.25 +# 22.12.2003: Fixed a bug where no function names would be output for "def" 1.26 +# blocks that were not in a class. 1.27 +# (thanks to Richard Laager for the patch) 1.28 +# 12.12.2003: Implemented code to handle static and class methods with 1.29 +# this logic: Methods with "self" as the first argument are 1.30 +# non-static. Methods with "cls" are Python class methods, 1.31 +# which translate into static methods for Doxygen. Other 1.32 +# methods are assumed to be static methods. As should be 1.33 +# obvious, this logic doesn't take into account if the method 1.34 +# is actually setup as a classmethod() or a staticmethod(), 1.35 +# just if it follows the normal conventions. 1.36 +# (thanks to Richard Laager for the patch) 1.37 +# 11.12.2003: Corrected #includes to use os.path.sep instead of ".". Corrected 1.38 +# namespace code to use "::" instead of ".". 1.39 +# (thanks to Richard Laager for the patch) 1.40 +# 11.12.2003: Methods beginning with two underscores that end with 1.41 +# something other than two underscores are considered private 1.42 +# and are handled accordingly. 1.43 +# (thanks to Richard Laager for the patch) 1.44 +# 03.12.2003: The first parameter of class methods (self) is removed from 1.45 +# the documentation. 1.46 +# 03.11.2003: The module docstring will be used as namespace documentation 1.47 +# (thanks to Joe Bronkema for the patch) 1.48 +# 08.07.2003: Namespaces get a default documentation so that the namespace 1.49 +# and its contents will show up in the generated documentation. 1.50 +# 05.02.2003: Directories will be delted during synchronization. 1.51 +# 31.01.2003: -f option & filtering entire directory trees. 1.52 +# 10.08.2002: In base classes the '.' will be replaced by '::' 1.53 +# 18.07.2002: * and ** will be translated into arguments 1.54 +# 18.07.2002: Argument lists may contain default values using constructors. 1.55 +# 18.06.2002: Support for ## public: 1.56 +# 21.01.2002: from ... import will be translated to "using namespace ...;" 1.57 +# TODO: "from ... import *" vs "from ... import names" 1.58 +# TODO: Using normal imports: name.name -> name::name 1.59 +# 20.01.2002: #includes will be placed in front of the namespace 1.60 + 1.61 +###################################################################### 1.62 + 1.63 +# The program is written as a state machine with the following states: 1.64 +# 1.65 +# - OUTSIDE The current position is outside any comment, 1.66 +# class definition or function. 1.67 +# 1.68 +# - BUILD_COMMENT Begins with first "##". 1.69 +# Ends with the first token that is no "##" 1.70 +# at the same column as before. 1.71 +# 1.72 +# - BUILD_CLASS_DECL Begins with "class". 1.73 +# Ends with ":" 1.74 +# - BUILD_CLASS_BODY Begins just after BUILD_CLASS_DECL. 1.75 +# The first following token (which is no comment) 1.76 +# determines indentation depth. 1.77 +# Ends with a token that has a smaller indendation. 1.78 +# 1.79 +# - BUILD_DEF_DECL Begins with "def". 1.80 +# Ends with ":". 1.81 +# - BUILD_DEF_BODY Begins just after BUILD_DEF_DECL. 1.82 +# The first following token (which is no comment) 1.83 +# determines indentation depth. 1.84 +# Ends with a token that has a smaller indendation. 1.85 + 1.86 +import getopt 1.87 +import glob 1.88 +import os.path 1.89 +import re 1.90 +import shutil 1.91 +import string 1.92 +import sys 1.93 +import token 1.94 +import tokenize 1.95 + 1.96 +from stat import * 1.97 + 1.98 +OUTSIDE = 0 1.99 +BUILD_COMMENT = 1 1.100 +BUILD_CLASS_DECL = 2 1.101 +BUILD_CLASS_BODY = 3 1.102 +BUILD_DEF_DECL = 4 1.103 +BUILD_DEF_BODY = 5 1.104 +IMPORT = 6 1.105 +IMPORT_OP = 7 1.106 +IMPORT_APPEND = 8 1.107 + 1.108 +# Output file stream 1.109 +outfile = sys.stdout 1.110 + 1.111 +# Output buffer 1.112 +outbuffer = [] 1.113 + 1.114 +out_row = 1 1.115 +out_col = 0 1.116 + 1.117 +# Variables used by rec_name_n_param() 1.118 +name = "" 1.119 +param = "" 1.120 +doc_string = "" 1.121 +record_state = 0 1.122 +bracket_counter = 0 1.123 + 1.124 +# Tuple: (row,column) 1.125 +class_spos = (0,0) 1.126 +def_spos = (0,0) 1.127 +import_spos = (0,0) 1.128 + 1.129 +# Which import was used? ("import" or "from") 1.130 +import_token = "" 1.131 + 1.132 +# Comment block buffer 1.133 +comment_block = [] 1.134 +comment_finished = 0 1.135 + 1.136 +# Imported modules 1.137 +modules = [] 1.138 + 1.139 +# Program state 1.140 +stateStack = [OUTSIDE] 1.141 + 1.142 +# Keep track of whether module has a docstring 1.143 +module_has_docstring = False 1.144 + 1.145 +# Keep track of member protection 1.146 +protection_level = "public" 1.147 +private_member = False 1.148 + 1.149 +# Keep track of the module namespace 1.150 +namespace = "" 1.151 + 1.152 +###################################################################### 1.153 +# Output string s. '\n' may only be at the end of the string (not 1.154 +# somewhere in the middle). 1.155 +# 1.156 +# In: s - String 1.157 +# spos - Startpos 1.158 +###################################################################### 1.159 +def output(s,spos, immediate=0): 1.160 + global outbuffer, out_row, out_col, outfile 1.161 + 1.162 + os = string.rjust(s,spos[1]-out_col+len(s)) 1.163 + 1.164 + if immediate: 1.165 + outfile.write(os) 1.166 + else: 1.167 + outbuffer.append(os) 1.168 + 1.169 + assert -1 == string.find(s[0:-2], "\n"), s 1.170 + 1.171 + if (s[-1:]=="\n"): 1.172 + out_row = out_row+1 1.173 + out_col = 0 1.174 + else: 1.175 + out_col = spos[1]+len(s) 1.176 + 1.177 + 1.178 +###################################################################### 1.179 +# Records a name and parameters. The name is either a class name or 1.180 +# a function name. Then the parameter is either the base class or 1.181 +# the function parameters. 1.182 +# The name is stored in the global variable "name", the parameters 1.183 +# in "param". 1.184 +# The variable "record_state" holds the current state of this internal 1.185 +# state machine. 1.186 +# The recording is started by calling start_recording(). 1.187 +# 1.188 +# In: type, tok 1.189 +###################################################################### 1.190 +def rec_name_n_param(type, tok): 1.191 + global record_state,name,param,doc_string,bracket_counter 1.192 + s = record_state 1.193 + # State 0: Do nothing. 1.194 + if (s==0): 1.195 + return 1.196 + # State 1: Remember name. 1.197 + elif (s==1): 1.198 + name = tok 1.199 + record_state = 2 1.200 + # State 2: Wait for opening bracket or colon 1.201 + elif (s==2): 1.202 + if (tok=='('): 1.203 + bracket_counter = 1 1.204 + record_state=3 1.205 + if (tok==':'): record_state=4 1.206 + # State 3: Store parameter (or base class) and wait for an ending bracket 1.207 + elif (s==3): 1.208 + if (tok=='*' or tok=='**'): 1.209 + tok='' 1.210 + if (tok=='('): 1.211 + bracket_counter = bracket_counter+1 1.212 + if (tok==')'): 1.213 + bracket_counter = bracket_counter-1 1.214 + if bracket_counter==0: 1.215 + record_state=4 1.216 + else: 1.217 + param=param+tok 1.218 + # State 4: Look for doc string 1.219 + elif (s==4): 1.220 + if (type==token.NEWLINE or type==token.INDENT or type==token.SLASHEQUAL): 1.221 + return 1.222 + elif (tok==":"): 1.223 + return 1.224 + elif (type==token.STRING): 1.225 + while tok[:1]=='r' or tok[:1]=='u': 1.226 + tok=tok[1:] 1.227 + while tok[:1]=='"': 1.228 + tok=tok[1:] 1.229 + while tok[-1:]=='"': 1.230 + tok=tok[:-1] 1.231 + doc_string=tok 1.232 + record_state=0 1.233 + 1.234 +###################################################################### 1.235 +# Starts the recording of a name & param part. 1.236 +# The function rec_name_n_param() has to be fed with tokens. After 1.237 +# the necessary tokens are fed the name and parameters can be found 1.238 +# in the global variables "name" und "param". 1.239 +###################################################################### 1.240 +def start_recording(): 1.241 + global record_state,param,name, doc_string 1.242 + record_state=1 1.243 + name="" 1.244 + param="" 1.245 + doc_string="" 1.246 + 1.247 +###################################################################### 1.248 +# Test if recording is finished 1.249 +###################################################################### 1.250 +def is_recording_finished(): 1.251 + global record_state 1.252 + return record_state==0 1.253 + 1.254 +###################################################################### 1.255 +## Gather comment block 1.256 +###################################################################### 1.257 +def gather_comment(type,tok,spos): 1.258 + global comment_block,comment_finished 1.259 + if (type!=tokenize.COMMENT): 1.260 + comment_finished = 1 1.261 + else: 1.262 + # Output old comment block if a new one is started. 1.263 + if (comment_finished): 1.264 + print_comment(spos) 1.265 + comment_finished=0 1.266 + if (tok[0:2]=="##" and tok[0:3]!="###"): 1.267 + append_comment_lines(tok[2:]) 1.268 + 1.269 +###################################################################### 1.270 +## Output comment block and empty buffer. 1.271 +###################################################################### 1.272 +def print_comment(spos): 1.273 + global comment_block,comment_finished 1.274 + if (comment_block!=[]): 1.275 + output("/** ",spos) 1.276 + for c in comment_block: 1.277 + output(c,spos) 1.278 + output("*/\n",spos) 1.279 + comment_block = [] 1.280 + comment_finished = 0 1.281 + 1.282 +###################################################################### 1.283 +def set_state(s): 1.284 + global stateStack 1.285 + stateStack[len(stateStack)-1]=s 1.286 + 1.287 +###################################################################### 1.288 +def get_state(): 1.289 + global stateStack 1.290 + return stateStack[len(stateStack)-1] 1.291 + 1.292 +###################################################################### 1.293 +def push_state(s): 1.294 + global stateStack 1.295 + stateStack.append(s) 1.296 + 1.297 +###################################################################### 1.298 +def pop_state(): 1.299 + global stateStack 1.300 + stateStack.pop() 1.301 + 1.302 + 1.303 +###################################################################### 1.304 +def tok_eater(type, tok, spos, epos, line): 1.305 + global stateStack,name,param,class_spos,def_spos,import_spos 1.306 + global doc_string, modules, import_token, module_has_docstring 1.307 + global protection_level, private_member 1.308 + global out_row 1.309 + 1.310 + while out_row + 1 < spos[0]: 1.311 + output("\n", (0, 0)) 1.312 + 1.313 + rec_name_n_param(type,tok) 1.314 + if (string.replace(string.strip(tok)," ","")=="##private:"): 1.315 + protection_level = "private" 1.316 + output("private:\n",spos) 1.317 + elif (string.replace(string.strip(tok)," ","")=="##protected:"): 1.318 + protection_level = "protected" 1.319 + output("protected:\n",spos) 1.320 + elif (string.replace(string.strip(tok)," ","")=="##public:"): 1.321 + protection_level = "public" 1.322 + output("public:\n",spos) 1.323 + else: 1.324 + gather_comment(type,tok,spos) 1.325 + 1.326 + state = get_state() 1.327 + 1.328 +# sys.stderr.write("%d: %s\n"%(state, tok)) 1.329 + 1.330 + # OUTSIDE 1.331 + if (state==OUTSIDE): 1.332 + if (tok=="class"): 1.333 + start_recording() 1.334 + class_spos = spos 1.335 + push_state(BUILD_CLASS_DECL) 1.336 + elif (tok=="def"): 1.337 + start_recording() 1.338 + def_spos = spos 1.339 + push_state(BUILD_DEF_DECL) 1.340 + elif (tok=="import") or (tok=="from"): 1.341 + import_token = tok 1.342 + import_spos = spos 1.343 + modules = [] 1.344 + push_state(IMPORT) 1.345 + elif (spos[1] == 0 and tok[:3] == '"""'): 1.346 + # Capture module docstring as namespace documentation 1.347 + module_has_docstring = True 1.348 + append_comment_lines("\\namespace %s\n" % namespace) 1.349 + append_comment_lines(tok[3:-3]) 1.350 + print_comment(spos) 1.351 + 1.352 + # IMPORT 1.353 + elif (state==IMPORT): 1.354 + if (type==token.NAME): 1.355 + modules.append(tok) 1.356 + set_state(IMPORT_OP) 1.357 + # IMPORT_OP 1.358 + elif (state==IMPORT_OP): 1.359 + if (tok=="."): 1.360 + set_state(IMPORT_APPEND) 1.361 + elif (tok==","): 1.362 + set_state(IMPORT) 1.363 + else: 1.364 + for m in modules: 1.365 + output('#include "'+m.replace('.',os.path.sep)+'.py"\n', import_spos, immediate=1) 1.366 + if import_token=="from": 1.367 + output('using namespace '+m.replace('.', '::')+';\n', import_spos) 1.368 + pop_state() 1.369 + # IMPORT_APPEND 1.370 + elif (state==IMPORT_APPEND): 1.371 + if (type==token.NAME): 1.372 + modules[len(modules)-1]+="."+tok 1.373 + set_state(IMPORT_OP) 1.374 + # BUILD_CLASS_DECL 1.375 + elif (state==BUILD_CLASS_DECL): 1.376 + if (is_recording_finished()): 1.377 + s = "class "+name 1.378 + if (param!=""): s = s+" : public "+param.replace('.','::') 1.379 + if (doc_string!=""): 1.380 + append_comment_lines(doc_string) 1.381 + print_comment(class_spos) 1.382 + output(s+"\n",class_spos) 1.383 + output("{\n",(class_spos[0]+1,class_spos[1])) 1.384 + protection_level = "public" 1.385 + output(" public:\n",(class_spos[0]+2,class_spos[1])) 1.386 + set_state(BUILD_CLASS_BODY) 1.387 + # BUILD_CLASS_BODY 1.388 + elif (state==BUILD_CLASS_BODY): 1.389 + if (type!=token.INDENT and type!=token.NEWLINE and type!=40 and 1.390 + type!=tokenize.NL and type!=tokenize.COMMENT and 1.391 + (spos[1]<=class_spos[1])): 1.392 + output("}; // end of class\n",(out_row+1,class_spos[1])) 1.393 + pop_state() 1.394 + elif (tok=="def"): 1.395 + start_recording() 1.396 + def_spos = spos 1.397 + push_state(BUILD_DEF_DECL) 1.398 + # BUILD_DEF_DECL 1.399 + elif (state==BUILD_DEF_DECL): 1.400 + if (is_recording_finished()): 1.401 + param = param.replace("\n", " ") 1.402 + param = param.replace("=", " = ") 1.403 + params = param.split(",") 1.404 + if BUILD_CLASS_BODY in stateStack: 1.405 + if len(name) > 1 \ 1.406 + and name[0:2] == '__' \ 1.407 + and name[len(name)-2:len(name)] != '__' \ 1.408 + and protection_level != 'private': 1.409 + private_member = True 1.410 + output(" private:\n",(def_spos[0]+2,def_spos[1])) 1.411 + 1.412 + if (doc_string != ""): 1.413 + append_comment_lines(doc_string) 1.414 + 1.415 + print_comment(def_spos) 1.416 + 1.417 + output_function_decl(name, params) 1.418 +# output("{\n",(def_spos[0]+1,def_spos[1])) 1.419 + set_state(BUILD_DEF_BODY) 1.420 + # BUILD_DEF_BODY 1.421 + elif (state==BUILD_DEF_BODY): 1.422 + if (type!=token.INDENT and type!=token.NEWLINE \ 1.423 + and type!=40 and type!=tokenize.NL \ 1.424 + and (spos[1]<=def_spos[1])): 1.425 +# output("} // end of method/function\n",(out_row+1,def_spos[1])) 1.426 + if private_member and protection_level != 'private': 1.427 + private_member = False 1.428 + output(" " + protection_level + ":\n",(def_spos[0]+2,def_spos[1])) 1.429 + pop_state() 1.430 +# else: 1.431 +# output(tok,spos) 1.432 + 1.433 + 1.434 +def output_function_decl(name, params): 1.435 + global def_spos 1.436 + 1.437 + # Do we document a class method? then remove the 'self' parameter 1.438 + if params[0] == 'self': 1.439 + preamble = '' 1.440 + params = params[1:] 1.441 + else: 1.442 + preamble = 'static ' 1.443 + if params[0] == 'cls': 1.444 + params = params[1:] 1.445 + 1.446 + param_string = string.join(params, ", Type ") 1.447 + 1.448 + if param_string == '': 1.449 + param_string = '(' + param_string + ');\n' 1.450 + else: 1.451 + param_string = '(Type ' + param_string + ');\n' 1.452 + 1.453 + output(preamble, def_spos) 1.454 + output(name, def_spos) 1.455 + output(param_string, def_spos) 1.456 + 1.457 + 1.458 +def append_comment_lines(lines): 1.459 + map(append_comment_line, doc_string.split('\n')) 1.460 + 1.461 +paramRE = re.compile(r'(@param \w+):') 1.462 + 1.463 +def append_comment_line(line): 1.464 + global paramRE 1.465 + 1.466 + comment_block.append(paramRE.sub(r'\1', line) + '\n') 1.467 + 1.468 +def dump(filename): 1.469 + f = open(filename) 1.470 + r = f.readlines() 1.471 + for s in r: 1.472 + sys.stdout.write(s) 1.473 + 1.474 +def filter(filename): 1.475 + global name, module_has_docstring, source_root 1.476 + 1.477 + path,name = os.path.split(filename) 1.478 + root,ext = os.path.splitext(name) 1.479 + 1.480 + if source_root and path.find(source_root) == 0: 1.481 + path = path[len(source_root):] 1.482 + 1.483 + if path[0] == os.sep: 1.484 + path = path[1:] 1.485 + 1.486 + ns = path.split(os.sep) 1.487 + else: 1.488 + ns = [] 1.489 + 1.490 + ns.append(root) 1.491 + 1.492 + for n in ns: 1.493 + output("namespace " + n + " {\n",(0,0)) 1.494 + 1.495 + # set module name for tok_eater to use if there's a module doc string 1.496 + name = root 1.497 + 1.498 +# sys.stderr.write('Filtering "'+filename+'"...') 1.499 + f = open(filename) 1.500 + tokenize.tokenize(f.readline, tok_eater) 1.501 + f.close() 1.502 + print_comment((0,0)) 1.503 + 1.504 + output("\n",(0,0)) 1.505 + 1.506 + for n in ns: 1.507 + output("} // end of namespace\n",(0,0)) 1.508 + 1.509 + if not module_has_docstring: 1.510 + # Put in default namespace documentation 1.511 + output('/** \\namespace '+root+' \n',(0,0)) 1.512 + output(' \\brief Module "%s" */\n'%(root),(0,0)) 1.513 + 1.514 + for s in outbuffer: 1.515 + outfile.write(s) 1.516 + 1.517 + 1.518 +def filterFile(filename, out=sys.stdout): 1.519 + global outfile 1.520 + 1.521 + outfile = out 1.522 + 1.523 + try: 1.524 + root,ext = os.path.splitext(filename) 1.525 + 1.526 + if ext==".py": 1.527 + filter(filename) 1.528 + else: 1.529 + dump(filename) 1.530 + 1.531 +# sys.stderr.write("OK\n") 1.532 + except IOError,e: 1.533 + sys.stderr.write(e[1]+"\n") 1.534 + 1.535 + 1.536 +###################################################################### 1.537 + 1.538 +# preparePath 1.539 +def preparePath(path): 1.540 + """Prepare a path. 1.541 + 1.542 + Checks if the path exists and creates it if it does not exist. 1.543 + """ 1.544 + if not os.path.exists(path): 1.545 + parent = os.path.dirname(path) 1.546 + if parent!="": 1.547 + preparePath(parent) 1.548 + os.mkdir(path) 1.549 + 1.550 +# isNewer 1.551 +def isNewer(file1,file2): 1.552 + """Check if file1 is newer than file2. 1.553 + 1.554 + file1 must be an existing file. 1.555 + """ 1.556 + if not os.path.exists(file2): 1.557 + return True 1.558 + return os.stat(file1)[ST_MTIME]>os.stat(file2)[ST_MTIME] 1.559 + 1.560 +# convert 1.561 +def convert(srcpath, destpath): 1.562 + """Convert a Python source tree into a C+ stub tree. 1.563 + 1.564 + All *.py files in srcpath (including sub-directories) are filtered 1.565 + and written to destpath. If destpath exists, only the files 1.566 + that have been modified are filtered again. Files that were deleted 1.567 + from srcpath are also deleted in destpath if they are still present. 1.568 + The function returns the number of processed *.py files. 1.569 + """ 1.570 + count=0 1.571 + sp = os.path.join(srcpath,"*") 1.572 + sfiles = glob.glob(sp) 1.573 + dp = os.path.join(destpath,"*") 1.574 + dfiles = glob.glob(dp) 1.575 + leftovers={} 1.576 + for df in dfiles: 1.577 + leftovers[os.path.basename(df)]=1 1.578 + 1.579 + for srcfile in sfiles: 1.580 + basename = os.path.basename(srcfile) 1.581 + if basename in leftovers: 1.582 + del leftovers[basename] 1.583 + 1.584 + # Is it a subdirectory? 1.585 + if os.path.isdir(srcfile): 1.586 + sdir = os.path.join(srcpath,basename) 1.587 + ddir = os.path.join(destpath,basename) 1.588 + count+=convert(sdir, ddir) 1.589 + continue 1.590 + # Check the extension (only *.py will be converted) 1.591 + root, ext = os.path.splitext(srcfile) 1.592 + if ext.lower()!=".py": 1.593 + continue 1.594 + 1.595 + destfile = os.path.join(destpath,basename) 1.596 + if destfile==srcfile: 1.597 + print "WARNING: Input and output names are identical!" 1.598 + sys.exit(1) 1.599 + 1.600 + count+=1 1.601 +# sys.stdout.write("%s\015"%(srcfile)) 1.602 + 1.603 + if isNewer(srcfile, destfile): 1.604 + preparePath(os.path.dirname(destfile)) 1.605 +# out=open(destfile,"w") 1.606 +# filterFile(srcfile, out) 1.607 +# out.close() 1.608 + os.system("python %s -f %s>%s"%(sys.argv[0],srcfile,destfile)) 1.609 + 1.610 + # Delete obsolete files in destpath 1.611 + for df in leftovers: 1.612 + dname=os.path.join(destpath,df) 1.613 + if os.path.isdir(dname): 1.614 + try: 1.615 + shutil.rmtree(dname) 1.616 + except: 1.617 + print "Can't remove obsolete directory '%s'"%dname 1.618 + else: 1.619 + try: 1.620 + os.remove(dname) 1.621 + except: 1.622 + print "Can't remove obsolete file '%s'"%dname 1.623 + 1.624 + return count 1.625 + 1.626 + 1.627 +###################################################################### 1.628 +###################################################################### 1.629 +###################################################################### 1.630 + 1.631 +filter_file = False 1.632 +source_root = None 1.633 + 1.634 +try: 1.635 + opts, args = getopt.getopt(sys.argv[1:], "hfr:", ["help"]) 1.636 +except getopt.GetoptError,e: 1.637 + print e 1.638 + sys.exit(1) 1.639 + 1.640 +for o,a in opts: 1.641 + if o=="-f": 1.642 + filter_file = True 1.643 + 1.644 + if o=="-r": 1.645 + source_root = os.path.abspath(a) 1.646 + 1.647 +if filter_file: 1.648 + # Filter the specified file and print the result to stdout 1.649 + filename = string.join(args) 1.650 + filterFile(os.path.abspath(filename)) 1.651 +else: 1.652 + 1.653 + if len(args)!=2: 1.654 + sys.stderr.write("%s options input output\n"%(os.path.basename(sys.argv[0]))) 1.655 + sys.exit(1) 1.656 + 1.657 + # Filter an entire Python source tree 1.658 + print '"%s" -> "%s"\n'%(args[0],args[1]) 1.659 + c=convert(args[0],args[1]) 1.660 + print "%d files"%(c) 1.661 +