mp.py

Go to the documentation of this file.
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...