00001 # ToDo 00002 # 00003 # Add a syntax like 00004 # .define mp_XXX 00005 # with no definition of the value. When this is encountered, 00006 # the script will get the variable's value from the python 00007 # global variables. This makes it easier to define multiline 00008 # strings and get them into the output. 00009 00010 00011 ## 00012 # 00013 # A macro processor; print the man page for details. 00014 # 00015 # Copyright (C) 2002 GDS Software 00016 # 00017 # This program is free software; you can redistribute it and/or 00018 # modify it under the terms of the GNU General Public License as 00019 # published by the Free Software Foundation; either version 2 of 00020 # the License, or (at your option) any later version. 00021 # 00022 # This program is distributed in the hope that it will be useful, 00023 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00024 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00025 # GNU General Public License for more details. 00026 # 00027 # You should have received a copy of the GNU General Public 00028 # License along with this program; if not, write to the Free 00029 # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00030 # MA 02111-1307 USA 00031 # 00032 # See http://www.gnu.org/licenses/licenses.html for more details. 00033 # 00034 00035 import string, sys, os, re 00036 00037 script = os.path.split(sys.argv[0])[1] 00038 verbose = 0 # Log to stderr if true 00039 dump_macros = 0 00040 special_char = "." 00041 files_to_process = None 00042 output_on = 1 00043 out = None # Output stream writing function 00044 current_file = "" 00045 current_line = 0 00046 macros = {} 00047 macro_names = [] 00048 start_dir = os.getcwd() 00049 cmd_char = "." # Character that denotes a command line 00050 include_dirs = [] # Where to search for include files 00051 00052 # Globals to help with evaluating chunks of code 00053 code_mode = 0 # If true, we're in a code section 00054 current_code = "" # String to hold the code lines 00055 code_names = {} # Keep track of named sections of code 00056 00057 # The following regular expression is used to identify lines that contain 00058 # formatting strings that need to be expanded with the global dictionary. 00059 need_global_expansion = re.compile(r"%\(([a-zA-Z][a-zA-Z_]*)\)") 00060 00061 #x = " %(a)s kdjfkdj %(kj)d " 00062 #mo = need_global_expansion.search(x) 00063 #a = 9 00064 #kj = 898 00065 #if mo: 00066 # print "match" 00067 # print "groups() = ", mo.groups() 00068 # varname = mo.groups()[0] 00069 # if globals().has_key(varname): 00070 # print "In globals dict" 00071 # else: 00072 # print "Not in globals dict" 00073 #else: 00074 # print "no match" 00075 #print "Substitution:" 00076 #print x % globals() 00077 #sys.exit(0) 00078 00079 special_macros = ''' 25 Aug 2002 Is the current date in DD MMM YYYY format. 00080 25 Is the current date's day in DD form. 00081 08 Is the current date's month in MM (01-12) form. 00082 Aug Is the current date's month in MMM (Jan-Dec) form. 00083 02 Is the current date's year in YY form. 00084 2002 Is the current date's year in YYYY form. 00085 10:06:34 Is the current time in HH:MM:SS AM/PM format. 00086 10 Is the current time's hour in 24 hour format 00087 10 Is the current time's hour in 12 hour format 00088 06 Is the current time's minute (00-59) 00089 34 Is the current time's second (00-59) 00090 AM Is the current time's AM or PM designator 00091 This program is free software; you can redistribute it and/or 00092 modify it under the terms of the GNU General Public License as 00093 published by the Free Software Foundation; either version 2 of 00094 the License, or (at your option) any later version. 00095 00096 This program is distributed in the hope that it will be useful, 00097 but WITHOUT ANY WARRANTY; without even the implied warranty of 00098 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00099 GNU General Public License for more details. 00100 00101 You should have received a copy of the GNU General Public 00102 License along with this program; if not, write to the Free 00103 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00104 MA 02111-1307 USA 00105 00106 See http://www.gnu.org/licenses/licenses.html for more details. The GNU General Public License Notice (text) 00107 This program is free software; you can redistribute it and/or 00108 modify it under the terms of the GNU General Public License as 00109 published by the Free Software Foundation; either version 2 of 00110 the License, or (at your option) any later version.<p> 00111 00112 This program is distributed in the hope that it will be useful, 00113 but WITHOUT ANY WARRANTY; without even the implied warranty of 00114 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00115 GNU General Public License for more details.<p> 00116 00117 You should have received a copy of the GNU General Public 00118 License along with this program; if not, write to the Free 00119 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00120 MA 02111-1307 USA<p> 00121 00122 See <a href="http://www.gnu.org/licenses/licenses.html">http://www.gnu.org/licenses/licenses.html</a> for more details. 00123 The GNU General Public License Notice (html)''' 00124 00125 GPL_txt = '''This program is free software; you can redistribute it and/or 00126 modify it under the terms of the GNU General Public License as 00127 published by the Free Software Foundation; either version 2 of 00128 the License, or (at your option) any later version. 00129 00130 This program is distributed in the hope that it will be useful, 00131 but WITHOUT ANY WARRANTY; without even the implied warranty of 00132 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00133 GNU General Public License for more details. 00134 00135 You should have received a copy of the GNU General Public 00136 License along with this program; if not, write to the Free 00137 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00138 MA 02111-1307 USA 00139 00140 See http://www.gnu.org/licenses/licenses.html for more details.''' 00141 00142 gnu_url = "http://www.gnu.org/licenses/licenses.html" 00143 00144 GPL_html = '''This program is free software; you can redistribute it and/or 00145 modify it under the terms of the GNU General Public License as 00146 published by the Free Software Foundation; either version 2 of 00147 the License, or (at your option) any later version.<p> 00148 00149 This program is distributed in the hope that it will be useful, 00150 but WITHOUT ANY WARRANTY; without even the implied warranty of 00151 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00152 GNU General Public License for more details.<p> 00153 00154 You should have received a copy of the GNU General Public 00155 License along with this program; if not, write to the Free 00156 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00157 MA 02111-1307 USA<p> 00158 00159 See <a href="%s">%s</a> for more details. 00160 ''' % (gnu_url, gnu_url) 00161 del gnu_url 00162 00163 def Usage(): 00164 print '''Usage: %(script)s [options] file1 [file2...] 00165 Options 00166 -d Print list of macro definitions found in files 00167 -h Print a man page 00168 -I dir Define an include directory 00169 Command lines have the form (whitespace after '.' optional): 00170 . command [parameters] 00171 Commands: 00172 define Macro = Value Define a new macro 00173 # This line is a comment 00174 on Turn output on 00175 off Turn output off 00176 code [name] Define a [named] section of python code 00177 endcode End of python code section 00178 include Insert a file; error if not found 00179 sinclude Insert a file; no error if not found 00180 cd [dir] Change the current directory 00181 Special macros 00182 %(special_macros)s''' % globals() 00183 00184 def ManPage(): 00185 print '''NAME 00186 %(script)s - Macro processor 00187 Version: $Revision: 1.9 $ 00188 00189 SYNOPSIS 00190 %(script)s [options] file1 [file2...] 00191 00192 DESCRIPTION 00193 00194 The %(script)s script is intended to be used as a macro processor. 00195 It is primarily a string substitution tool. However, since it is 00196 implemented in python, it allows the use of arbitrary python code 00197 in your text files. 00198 00199 %(script)s replaces strings in the input files, then prints them 00200 to stdout. It knows nothing about things like identifiers or 00201 tokens in programming languages. It's a dumb text substitution 00202 program. Thus, you must make SURE your macro names will not be 00203 found in text except where you deliberately put them in. A 00204 suggestion would be to prefix all macro names with "mp_". 00205 00206 For example, suppose the macro mp_MyMacro had the value of 00207 "abc123" (quote characters not included). Then if the macro 00208 processor encountered the following line 00209 00210 This is mp_MyMacro4. 00211 00212 the line would be transformed to: 00213 00214 This is abc1234. 00215 00216 In other words, the string "mp_MyMacro" was found on the line 00217 and the substitution was made. This is done until no more macro 00218 definitions are found on the line; then the line is printed to 00219 stdout. 00220 00221 Programmers would probably see the 'mp_MyMacro4' above as a 00222 token and expect the substitution to be based on tokens found. 00223 The %(script)s doesn't behave this way; a common mistake is to 00224 define macros with similar names: 00225 00226 .define mp_MyMacro =abc123 00227 .define mp_MyMacro4 =xyz 00228 00229 Then, when the macro processor encounters 'mp_MyMacro4' in the 00230 input text, we'd expect to see 'xyz' subsituted. But what 00231 happens is that 'abc123' is substituted, since the name 00232 mp_MyMacro was matched. The lesson is to never name a macro 00233 with a string that will appear in another macro name. 00234 00235 You can add built-in macros to the script by editting the 00236 BuildSpecialMacros() function. 00237 00238 Options 00239 -d 00240 Print a list of macro definitions found in the input files to 00241 stdout. 00242 00243 -h 00244 Prints this man page. 00245 00246 -I dir 00247 Define an include directory. When a file is included, it 00248 is first looked for in the current directory (or the 00249 indicated directory). If it cannot be found, directories 00250 specified with the -I option are searched sequentially 00251 and the first match is used. More than one -I option 00252 can be given. 00253 00254 Command lines 00255 Command lines to the macro processor are denoted by having a '.' 00256 character in the first column. You can edit the IsCommandLine() 00257 function in the script if you'd like to change this syntax. 00258 00259 The general form of a command is: 00260 00261 . token [token's arguments] 00262 00263 There can be optional whitespace between the '.' character and 00264 the characters of the token. 00265 00266 The allowed command tokens are: 00267 00268 define macro = value 00269 Defines the value of a macro. All characters after the '=' 00270 character become part of the macro's value, except for the 00271 newline. 00272 00273 cd dir 00274 Set the current directory of the macro processor to dir. 00275 If dir is missing, the current directory is set to what it 00276 was at the start of the script. 00277 00278 code [code_section_name] 00279 endcode 00280 These two tokens must appear on a line by themselves. They 00281 delimit lines of text that will be interpreted as python 00282 code. Typically, this is used to define and set some global 00283 variables that are used for variable expansions in lines. 00284 See the Examples section below for details. However, 00285 arbitrary processing can be done. Any variables that you 00286 define in your code section are added to the global variable 00287 namespace of the %(script)s script. 00288 00289 If code_section_name is given, it must be encountered only 00290 once while processing, otherwise an error will occur and 00291 processing stops. You can use this feature to avoid 00292 accidentally including files multiple times (if your code 00293 in the included file has a name, the %(script)s script will 00294 stop executing the second time it is included). 00295 00296 include file 00297 Used to include another file at this point. The behavior is 00298 to read all the lines of the indicated file and insert them 00299 at the current location. It is a fatal error if the file 00300 cannot be found. The 00301 00302 sinclude file 00303 Same as include, except it's not an error if the file cannot 00304 be found. 00305 00306 # 00307 If this character follows the command line string (with optional 00308 preceding whitespace), the line is considered a comment and the 00309 line as a whole is discarded. 00310 00311 on 00312 Turns macro substitution back on if it was off. Ignored if it is 00313 already on. 00314 00315 off 00316 Turns macro substitution off. Ignored if it is already off. 00317 00318 Built-in macros 00319 There are some built-in macros: 00320 %(special_macros)s 00321 00322 Python variables 00323 You may use python variable references in your text. These references 00324 must be of the form '%%(varname)s', where varname is the name of a 00325 python variable and s is a formatting string, such as 's', 'd', 'f', 00326 etc. These expressions will be evaluated with the global dictionary 00327 in effect at the time the code is evaluated. 00328 00329 Typical use of this functionality is to give counters that get 00330 incremented or to define multiline strings. 00331 00332 Example 00333 The following example shows a simple use of python code to 00334 generate serial numbers for a set of files. The idea is that the 00335 serial numbers will be incremented each time they are referenced, 00336 allowing a set of files to have unique numbers. 00337 00338 File 1 contains: 00339 .code 00340 sn = 100 # Starting serial number 00341 def IncrementSerialNumber(): 00342 global sn 00343 sn += 1 00344 .endcode 00345 This is file 1. The serial number is %%(sn)d. 00346 .code 00347 IncrementSerialNumber() 00348 .endcode 00349 00350 File 2 contains: 00351 This is file 2. The serial number is %%(sn)d. 00352 .code 00353 IncrementSerialNumber() 00354 .endcode 00355 00356 Running the command 00357 00358 python mp.py 1 2 00359 00360 produces the output: 00361 00362 This is file 1. The serial number is 100. 00363 This is file 2. The serial number is 101. 00364 00365 Note: any global variables and functions you define in your code 00366 will be put into the %(script)s script's global namespace. 00367 00368 ''' % globals() 00369 00370 def Log(str): 00371 if verbose: 00372 #sys.stderr.write("+ " + str) 00373 sys.stdout.write("+ " + str) #xx 00374 00375 def Initialize(): 00376 global files_to_process 00377 global out 00378 import getopt 00379 try: 00380 optlist, args = getopt.getopt(sys.argv[1:], "dhI:v") 00381 except getopt.error, str: 00382 print "getopt error: %s\n" % str 00383 sys.exit(1) 00384 for opt in optlist: 00385 if opt[0] == "-d": 00386 global dump_macros 00387 dump_macros = 1 00388 if opt[0] == "-v": 00389 global verbose 00390 verbose = 1 00391 if opt[0] == "-h": 00392 ManPage() 00393 sys.exit(0) 00394 if opt[0] == "-I": 00395 global include_dirs 00396 include_dirs.append(opt[1]) 00397 files_to_process = args 00398 if len(files_to_process) == 0: 00399 Usage() 00400 Log("dump_macros = %d\n" % dump_macros) 00401 Log("verbose = %d\n" % verbose) 00402 Log("files_to_process = %s\n" % `files_to_process`) 00403 Log("-" * 70 + "\n") 00404 out = sys.stdout.write 00405 BuildSpecialMacros() 00406 assert(len(cmd_char) == 1) 00407 00408 ## 00409 # Construct the special macros used by the script. Edit this 00410 # function as needed to add your own built-in macros. 00411 # 00412 def BuildSpecialMacros(): 00413 global macros, macro_names 00414 import time 00415 tm = time.localtime(time.time()) 00416 settings = [ 00417 ["25 Aug 2002", "%d %b %Y"], 00418 ["25", "%d"], 00419 ["08", "%m"], 00420 ["Aug", "%b"], 00421 ["02", "%y"], 00422 ["2002", "%Y"], 00423 ["10:06:34", "%H:%M:%S"], 00424 ["10", "%H"], 00425 ["10", "%I"], 00426 ["06", "%M"], 00427 ["34", "%S"], 00428 ["AM", "%p"], 00429 ] 00430 for setting in settings: 00431 key = setting[0] 00432 value = [time.strftime(setting[1], tm), 0, ""] 00433 macros[key] = value 00434 if verbose: 00435 Log("%-20s %s\n" % (key, value)) 00436 # Add the GPL macros. 00437 macros['This program is free software; you can redistribute it and/or \nmodify it under the terms of the GNU General Public License as \npublished by the Free Software Foundation; either version 2 of \nthe License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, \nbut WITHOUT ANY WARRANTY; without even the implied warranty of \nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \nGNU General Public License for more details. \n\nYou should have received a copy of the GNU General Public \nLicense along with this program; if not, write to the Free \nSoftware Foundation, Inc., 59 Temple Place, Suite 330, Boston, \nMA 02111-1307 USA \n\nSee http://www.gnu.org/licenses/licenses.html for more details.'] = [GPL_txt, 0, ""] 00438 macros['This program is free software; you can redistribute it and/or \nmodify it under the terms of the GNU General Public License as \npublished by the Free Software Foundation; either version 2 of \nthe License, or (at your option) any later version.<p> \n\nThis program is distributed in the hope that it will be useful, \nbut WITHOUT ANY WARRANTY; without even the implied warranty of \nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \nGNU General Public License for more details.<p> \n\nYou should have received a copy of the GNU General Public \nLicense along with this program; if not, write to the Free \nSoftware Foundation, Inc., 59 Temple Place, Suite 330, Boston, \nMA 02111-1307 USA<p> \n\nSee <a href="http://www.gnu.org/licenses/licenses.html">http://www.gnu.org/licenses/licenses.html</a> for more details. \n'] = [GPL_html, 0, ""] 00439 macro_names = macros.keys() 00440 macro_names.sort() 00441 00442 def Error(msg): 00443 sys.stderr.write(msg) 00444 sys.exit(1) 00445 00446 ## 00447 # The line is a command line, so parse out the command and execute 00448 # it. If we're in code mode, the line is appended to the current_code 00449 # string. 00450 # 00451 def ProcessCommandLine(line): 00452 global output_on, macros, macro_names 00453 global code_mode, current_code, codes_names 00454 # If we're in code mode, just append the line to current_code and return 00455 # (unless we're at the code end). 00456 if code_mode and line[0] != cmd_char: 00457 Log("Code line: " + line) 00458 current_code = current_code + line 00459 return 00460 str = string.strip(line[1:]) 00461 if len(str) == 0: 00462 return 00463 fields = string.split(str) 00464 Log("Command line: " + line) 00465 if len(fields) == 0: 00466 return 00467 cmd = fields[0] 00468 if cmd == "define": 00469 if len(fields) < 3: 00470 Error("Too few fields in line %d of file '%s'\n" % (current_line, current_file)) 00471 macro_name = fields[1] 00472 loc_eq = string.find(line, "=") 00473 if loc_eq < 0: 00474 Error("Missing '=' in line %d of file '%s'\n" % (current_line, current_file)) 00475 macro_value = line[loc_eq+1:] 00476 # Remove the trailing newline if it is present 00477 if macro_value[-1] == "\n": 00478 macro_value = macro_value[:-1] 00479 if dump_macros: 00480 out("%s = '%s'\n" % (macro_name, macro_value)) 00481 if macros.has_key(macro_name): 00482 msg = "Warning: redefining macro name '%s' in line %d of file '%s'\n" % (macro_name, current_line, current_file) 00483 msg = msg + (" Previous definition at line %d of file '%s'\n" % (macros[macro_name][1], macros[macro_name][2])) 00484 sys.stderr.write(msg) 00485 macros[macro_name] = [macro_value, current_line, current_file] 00486 macro_names = macros.keys() 00487 macro_names.sort() 00488 Log("Defined %s to '%s'\n" % (macro_name, macro_value)) 00489 elif cmd == "code": 00490 # Beginning of a code section. If it's got a name, let's make 00491 # sure it hasn't been executed before. 00492 if len(fields) > 1: 00493 # It's got a name 00494 code_name = fields[1] 00495 if code_names.has_key(code_name): 00496 msg = "Error: code section named '%s' at line %d of file '%s' already defined\n" % (code_name, curr_line, curr_file) 00497 msg = msg + ("Previous definition line %d in file '%s'\n" % (code_names[code_name][0], code_names[code_name][1])) 00498 Error(msg) 00499 else: 00500 # Add it to the dictionary 00501 code_names[code_name] = [curr_line, curr_file] 00502 # Flag that we're now reading code 00503 code_mode = 1 00504 elif cmd == "endcode": 00505 # End of a code section. Compile and execute the code. 00506 if not code_mode: 00507 Error("Error: endcode at line %d of file '%s' missing a matching previous 'code' token\n" % (curr_line, curr_file)) 00508 code_mode = 0 00509 # Compile and execute. If we get an exception, the user will 00510 # know about where the problem is because the file and line 00511 # number of the endcode statement will be in the traceback. 00512 loc = "[%s:%d]" % (current_file, current_line) 00513 co = compile(current_code, loc, "exec") 00514 exec co 00515 # Save our variables in the global namespace, but remove this 00516 # function's locals. 00517 code_variables = locals() 00518 vars = ["loc", "co", "str", "fields", "line", "cmd"] 00519 for var in vars: 00520 del code_variables[var] 00521 # Now add these to the global dictionary 00522 g = globals() 00523 for varname in code_variables.keys(): 00524 g[varname] = code_variables[varname] 00525 elif cmd == "cd": 00526 if len(fields) > 1: 00527 os.chdir(fields[1]) 00528 else: 00529 os.chdir(start_dir) 00530 elif cmd[0] == "#": 00531 # It's a comment - ignore it 00532 pass 00533 elif cmd == "on": 00534 output_on = 1 00535 elif cmd == "off": 00536 output_on = 0 00537 elif cmd == "include": 00538 if len(fields) != 2: 00539 Error("Bad include in line %d of file '%s': missing file\n" % (current_line, current_file)) 00540 file = FindIncludeFile(fields[1]) 00541 if file == "": 00542 Error("Error: include file '%s' in line %d of file '%s' not found\n" % (fields[1], current_line, current_file)) 00543 ProcessFile(file, 0, current_line, current_file) 00544 elif cmd == "sinclude": 00545 if len(fields) != 2: 00546 Error("Bad sinclude in line %d of file '%s'\n" % (current_line, current_file)) 00547 file = FindIncludeFile(fields[1]) 00548 ProcessFile(file, 1, current_line, current_file) 00549 else: 00550 Error("Command '%s' on line %d of file '%s' not recognized\n" % (cmd, current_line, current_file)) 00551 00552 ## 00553 # Search for the indicated file. If it is an absolute path, just 00554 # return it. If it is a relative path, first try the current directory, 00555 # then the directories in the include_dirs list. If it is not found, 00556 # return an empty string. Otherwise return the full path name. 00557 # 00558 def FindIncludeFile(file): 00559 import os 00560 if os.path.isfile(file): 00561 path = os.path.normcase(os.path.abspath(file)) 00562 return path 00563 # Didn't find it, so search include_dirs 00564 for dir in include_dirs: 00565 path = os.path.normcase(os.path.join(dir, file)) 00566 if os.path.isfile(path): 00567 return os.path.abspath(path) 00568 # Couldn't find it, so return empty string 00569 return "" 00570 00571 ## 00572 # This function determines if the line is a command line; if so, return 00573 # true. Otherwise, return false. Note we always return 1 if we're in 00574 # code mode. 00575 # 00576 def IsCommandLine(line): 00577 if line[0] == cmd_char or code_mode != 0: 00578 return 1 00579 else: 00580 return 0 00581 00582 ## 00583 # We look for any macro name matches. Any that are found are 00584 # replaced, then we start the search over again so we don't miss 00585 # any macros within macros. 00586 # 00587 def ExpandMacros(line): 00588 done = 0 00589 while not done: 00590 found = 0 # Flags finding at least one macro 00591 for macro in macro_names: 00592 pos = string.find(line, macro) 00593 if pos != -1: 00594 # Found a macro name in the line 00595 found = 1 00596 old_value = macro 00597 new_value = macros[macro][0] 00598 line = string.replace(line, old_value, new_value) 00599 break 00600 if found == 0: 00601 done = 1 00602 # If current_code is not the null string, we've had at least one 00603 # code section, so evaluate using the global variables. We'll only 00604 # do this if the line has at least one formatting string of the 00605 # form %(varname)X, where varname is the name of a global variable 00606 # and X is s, d, etc. 00607 if len(current_code) > 0: 00608 mo = need_global_expansion.search(line) 00609 if mo: 00610 line = line % globals() 00611 return line 00612 00613 ## 00614 # Determine if the line is a command line or not. If it is, process 00615 # it with ProcessCommandLine(). Otherwise, expand the macros in the 00616 # line and print it to stdout. 00617 # 00618 def ProcessLine(line): 00619 if IsCommandLine(line): 00620 ProcessCommandLine(line) 00621 else: 00622 if output_on and not dump_macros: 00623 Output(line) 00624 00625 00626 ## 00627 # Send the line to the output stream. First, expand all the macros 00628 # in the line. Then check the character before the trailing newline: 00629 # if it is a '\' character, remove the newline unless the character 00630 # before that is another '\', in which case substitute '\' for the 00631 # '\\' and keep the newline. 00632 # 00633 def Output(line): 00634 line = ExpandMacros(line) 00635 if len(line) < 2: 00636 out(line) 00637 return 00638 if line[-2] == '\\': 00639 # Second to last character is a backslash 00640 if len(line) > 2: 00641 # If the character before the last backslash is a backslash, 00642 # just output the line as is. 00643 if line[-3] == "\\": 00644 out(line) 00645 else: 00646 # It's an escaped backslash, so chop off the newline 00647 out(line[:-2]) 00648 else: 00649 # It's just a backslash and a newline. 00650 return 00651 else: 00652 out(line) 00653 00654 ## 00655 # Read in and process each line in the file. The 00656 # ignore_failure_to_open variable is used to handle the sinclude case 00657 # when a file is missing or can't be opened. 00658 # 00659 # If present, restore_line and restore_file are used to reset the 00660 # current_line and current_file global variables, since we're in a 00661 # recursive call from include or sinclude commands. 00662 # 00663 def ProcessFile(file, ignore_failure_to_open=0, restore_line=0, restore_file=""): 00664 global current_file 00665 global current_line 00666 try: 00667 ifp = open(file) 00668 except: 00669 if ignore_failure_to_open: 00670 return 00671 else: 00672 Error("Couldn't open file '%s' for reading\n" % file) 00673 str = "\n\n===== %s processing file '%s' =====\n\n" 00674 Log(str % ("Started", file)) 00675 line = ifp.readline() 00676 current_file = file 00677 current_line = 1 00678 while line: 00679 ProcessLine(line) 00680 line = ifp.readline() 00681 current_line = current_line + 1 00682 ifp.close() 00683 if restore_line: 00684 current_line = restore_line 00685 if restore_file: 00686 current_file = restore_file 00687 Log(str % ("Finished", file)) 00688 00689 def main(): 00690 Initialize() 00691 for file in files_to_process: 00692 ProcessFile(file) 00693 sys.exit(0) 00694 00695 main() 00696 00697
© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."
Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.
122,241 lines of code and growing...