Massive identifier substitution on C source files,,'''PYTHON SO


'''PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2--------------------------------------------1. This LICENSE AGREEMENT is between the Python Software Foundation('PSF'), and the Individual or Organization ('Licensee') accessing andotherwise using this software ('Python') in source or binary form andits associated documentation.2. Subject to the terms and conditions of this License Agreement, PSFhereby grants Licensee a nonexclusive, royalty-free, world-widelicense to reproduce, analyze, test, perform and/or display publicly,prepare derivative works, distribute, and otherwise use Pythonalone or in any derivative version, provided, however, that PSF'sLicense Agreement and PSF's notice of copyright, i.e., 'Copyright (c)2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved'are retained in Python alone or in any derivative version preparedby Licensee.3. In the event Licensee prepares a derivative work that is based onor incorporates Python or any part thereof, and wants to makethe derivative work available to others as provided herein, thenLicensee hereby agrees to include in any such work a brief summary ofthe changes made to Python.4. PSF is making Python available to Licensee on an 'AS IS'basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS ORIMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO ANDDISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESSFOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOTINFRINGE ANY THIRD PARTY RIGHTS.5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHONFOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS ASA RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.6. This License Agreement will automatically terminate upon a materialbreach of its terms and conditions.7. Nothing in this License Agreement shall be deemed to create anyrelationship of agency, partnership, or joint venture between PSF andLicensee.  This License Agreement does not grant permission to use PSFtrademarks or trade name in a trademark sense to endorse or promoteproducts or services of Licensee, or any third party.8. By copying, installing or otherwise using Python, Licenseeagrees to be bound by the terms and conditions of this LicenseAgreement.'''#! /usr/bin/env python# Perform massive identifier substitution on C source files.# This actually tokenizes the files (to some extent) so it can# avoid making substitutions inside strings or comments.# Inside strings, substitutions are never made; inside comments,# it is a user option (off by default).## The substitutions are read from one or more files whose lines,# when not empty, after stripping comments starting with #,# must contain exactly two words separated by whitespace: the# old identifier and its replacement.## The option -r reverses the sense of the substitutions (this may be# useful to undo a particular substitution).## If the old identifier is prefixed with a '*' (with no intervening# whitespace), then it will not be substituted inside comments.## Command line arguments are files or directories to be processed.# Directories are searched recursively for files whose name looks# like a C file (ends in .h or .c).  The special filename '-' means# operate in filter mode: read stdin, write stdout.## Symbolic links are always ignored (except as explicit directory# arguments).## The original files are kept as back-up with a '~' suffix.## Changes made are reported to stdout in a diff-like format.## NB: by changing only the function fixline() you can turn this# into a program for different changes to C source files; by# changing the function wanted() you can make a different selection of# files.import sysimport regeximport osfrom stat import *import getopterr = sys.stderr.writedbg = errrep = sys.stdout.writedef usage():    progname = sys.argv[0]    err('Usage: ' + progname +              ' [-c] [-r] [-s file] ... file-or-directory ...\n')    err('\n')    err('-c           : substitute inside comments\n')    err('-r           : reverse direction for following -s options\n')    err('-s substfile : add a file of substitutions\n')    err('\n')    err('Each non-empty non-comment line in a substitution file must\n')    err('contain exactly two words: an identifier and its replacement.\n')    err('Comments start with a # character and end at end of line.\n')    err('If an identifier is preceded with a *, it is not substituted\n')    err('inside a comment even when -c is specified.\n')def main():    try:        opts, args = getopt.getopt(sys.argv[1:], 'crs:')    except getopt.error, msg:        err('Options error: ' + str(msg) + '\n')        usage()        sys.exit(2)    bad = 0    if not args: # No arguments        usage()        sys.exit(2)    for opt, arg in opts:        if opt == '-c':            setdocomments()        if opt == '-r':            setreverse()        if opt == '-s':            addsubst(arg)    for arg in args:        if os.path.isdir(arg):            if recursedown(arg): bad = 1        elif os.path.islink(arg):            err(arg + ': will not process symbolic links\n')            bad = 1        else:            if fix(arg): bad = 1    sys.exit(bad)# Change this regular expression to select a different set of filesWanted = '^[a-zA-Z0-9_]+\.[ch]$'def wanted(name):    return regex.match(Wanted, name) >= 0def recursedown(dirname):    dbg('recursedown(%r)\n' % (dirname,))    bad = 0    try:        names = os.listdir(dirname)    except os.error, msg:        err(dirname + ': cannot list directory: ' + str(msg) + '\n')        return 1    names.sort()    subdirs = []    for name in names:        if name in (os.curdir, os.pardir): continue        fullname = os.path.join(dirname, name)        if os.path.islink(fullname): pass        elif os.path.isdir(fullname):            subdirs.append(fullname)        elif wanted(name):            if fix(fullname): bad = 1    for fullname in subdirs:        if recursedown(fullname): bad = 1    return baddef fix(filename):##  dbg('fix(%r)\n' % (filename,))    if filename == '-':        # Filter mode        f = sys.stdin        g = sys.stdout    else:        # File replacement mode        try:            f = open(filename, 'r')        except IOError, msg:            err(filename + ': cannot open: ' + str(msg) + '\n')            return 1        head, tail = os.path.split(filename)        tempname = os.path.join(head, '@' + tail)        g = None    # If we find a match, we rewind the file and start over but    # now copy everything to a temp file.    lineno = 0    initfixline()    while 1:        line = f.readline()        if not line: break        lineno = lineno + 1        while line[-2:] == '\\\n':            nextline = f.readline()            if not nextline: break            line = line + nextline            lineno = lineno + 1        newline = fixline(line)        if newline != line:            if g is None:                try:                    g = open(tempname, 'w')                except IOError, msg:                    f.close()                    err(tempname+': cannot create: '+                        str(msg)+'\n')                    return 1                f.seek(0)                lineno = 0                initfixline()                rep(filename + ':\n')                continue # restart from the beginning            rep(repr(lineno) + '\n')            rep('< ' + line)            rep('> ' + newline)        if g is not None:            g.write(newline)    # End of file    if filename == '-': return 0 # Done in filter mode    f.close()    if not g: return 0 # No changes    # Finishing touch -- move files    # First copy the file's mode to the temp file    try:        statbuf = os.stat(filename)        os.chmod(tempname, statbuf[ST_MODE] & 07777)    except os.error, msg:        err(tempname + ': warning: chmod failed (' + str(msg) + ')\n')    # Then make a backup of the original file as filename~    try:        os.rename(filename, filename + '~')    except os.error, msg:        err(filename + ': warning: backup failed (' + str(msg) + ')\n')    # Now move the temp file to the original file    try:        os.rename(tempname, filename)    except os.error, msg:        err(filename + ': rename failed (' + str(msg) + ')\n')        return 1    # Return succes    return 0# Tokenizing ANSI C (partly)Identifier = '\(struct \)?[a-zA-Z_][a-zA-Z0-9_]+'String = ''\([^\n\\']\|\\\\.\)*''Char = '\'\([^\n\\\']\|\\\\.\)*\''CommentStart = '/\*'CommentEnd = '\*/'Hexnumber = '0[xX][0-9a-fA-F]*[uUlL]*'Octnumber = '0[0-7]*[uUlL]*'Decnumber = '[1-9][0-9]*[uUlL]*'Intnumber = Hexnumber + '\|' + Octnumber + '\|' + DecnumberExponent = '[eE][-+]?[0-9]+'Pointfloat = '\([0-9]+\.[0-9]*\|\.[0-9]+\)\(' + Exponent + '\)?'Expfloat = '[0-9]+' + ExponentFloatnumber = Pointfloat + '\|' + ExpfloatNumber = Floatnumber + '\|' + Intnumber# Anything else is an operator -- don't list this explicitly because of '/*'OutsideComment = (Identifier, Number, String, Char, CommentStart)OutsideCommentPattern = '\(' + '\|'.join(OutsideComment) + '\)'OutsideCommentProgram = regex.compile(OutsideCommentPattern)InsideComment = (Identifier, Number, CommentEnd)InsideCommentPattern = '\(' + '\|'.join(InsideComment) + '\)'InsideCommentProgram = regex.compile(InsideCommentPattern)def initfixline():    global Program    Program = OutsideCommentProgramdef fixline(line):    global Program##  print '-->', repr(line)    i = 0    while i < len(line):        i = Program.search(line, i)        if i < 0: break        found = Program.group(0)##      if Program is InsideCommentProgram: print '...',##      else: print '   ',##      print found        if len(found) == 2:            if found == '/*':                Program = InsideCommentProgram            elif found == '*/':                Program = OutsideCommentProgram        n = len(found)        if Dict.has_key(found):            subst = Dict[found]            if Program is InsideCommentProgram:                if not Docomments:                    print 'Found in comment:', found                    i = i + n                    continue                if NotInComment.has_key(found):##                  print 'Ignored in comment:',##                  print found, '-->', subst##                  print 'Line:', line,                    subst = found##              else:##                  print 'Substituting in comment:',##                  print found, '-->', subst##                  print 'Line:', line,            line = line[:i] + subst + line[i+n:]            n = len(subst)        i = i + n    return lineDocomments = 0def setdocomments():    global Docomments    Docomments = 1Reverse = 0def setreverse():    global Reverse    Reverse = (not Reverse)Dict = {}NotInComment = {}def addsubst(substfile):    try:        fp = open(substfile, 'r')    except IOError, msg:        err(substfile + ': cannot read substfile: ' + str(msg) + '\n')        sys.exit(1)    lineno = 0    while 1:        line = fp.readline()        if not line: break        lineno = lineno + 1        try:            i = line.index('#')        except ValueError:            i = -1          # Happens to delete trailing \n        words = line[:i].split()        if not words: continue        if len(words) == 3 and words[0] == 'struct':            words[:2] = [words[0] + ' ' + words[1]]        elif len(words) <> 2:            err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line))            continue        if Reverse:            [value, key] = words        else:            [key, value] = words        if value[0] == '*':            value = value[1:]        if key[0] == '*':            key = key[1:]            NotInComment[key] = value        if Dict.has_key(key):            err('%s:%r: warning: overriding: %r %r\n' % (substfile, lineno, key, value))            err('%s:%r: warning: previous: %r\n' % (substfile, lineno, Dict[key]))        Dict[key] = value    fp.close()if __name__ == '__main__':    main()

评论关闭