diff --git a/tren.py b/tren.py index aa12afb..01f593d 100755 --- a/tren.py +++ b/tren.py @@ -8,7 +8,7 @@ PROGNAME = "tren.py" BASENAME = PROGNAME.split(".py")[0] PROGENV = BASENAME.upper() -RCSID = "$Id: tren.py,v 1.157 2010/02/25 20:04:39 tundra Exp $" +RCSID = "$Id: tren.py,v 1.158 2010/02/26 00:08:44 tundra Exp $" VERSION = RCSID.split()[2] # Copyright Information @@ -82,20 +82,21 @@ # Literals ##### -ARROW = "--->" # Used for formatting renaming messages -COMMENT = "#" # Comment character in include files -DEFLEN = 80 # Default output line length -DEFSEP = "=" # Default rename command separator: old=new -DEFSUFFIX = ".backup" # String used to rename existing targets -DEFESC = "\\" # Escape character -GLOBAL = 0 # Indicates we want global replacement -INCL = "I" # Include file command line option -INDENT = " " # Indent string for nested messages +ARROW = "--->" # Used for formatting renaming messages +COMMENT = "#" # Comment character in include files +DEFINST = 0 # Default replacement instance +DEFLEN = 80 # Default output line length +DEFSEP = "=" # Default rename command separator: old=new +DEFSUFFIX = ".backup" # String used to rename existing targets +DEFESC = "\\" # Escape character +INCL = "I" # Include file command line option +INDENT = " " # Indent string for nested messages NULLESC = "Escape string" # Cannot be null NULLRENSEP = "Old/New separator string" # Cannot be null NULLSUFFIX = "Forced renaming suffix string" # Cannot be null -OPTINTRO = "-" # Option introducer -UPTO = "+" # "Replace up to ..." introducer +OPTINTRO = "-" # Option introducer +RANGESEP = ":" # Separator for instance ranges +SINGLEINST = "SINGLEINST" # Indicates a single, not range, replacement instance # Internal program state literals @@ -105,8 +106,9 @@ ERRORCONTINUE = "ERRORCONTINUE" EXISTSUFFIX = "EXISTSUFFIX" FORCERENAME = "FORCERENAME" +INSTANCESTART = "INSTANCESTART" +INSTANCEEND = "INSTANCEEND" MAXLINELEN = "MAXLINELEN" -INSTANCE = "INSTANCE" QUIET = "QUIET" REGEX = "REGEX" RENSEP = "RENSEP" @@ -167,7 +169,7 @@ eARGLENGTH = "%s must contain exactly %s character(s)!" eBADARG = "Invalid command line: %s!" eBADINCL = "option -%s requires argument" % INCL -eBADINSTANCE = "%s is an invalid replacement instance!" +eBADINSTANCE = "%s is an invalid replacement instance! Must be integer values in the form: n, n:n, :n, n:, or :" eBADLEN = "Bad line length '%s'!" eBADNEWOLD = "Bad -r argument '%s'! Requires exactly one new, old string separator (Default: " + DEFSEP + ")" eERROR = "ERROR" @@ -203,7 +205,7 @@ " -f Force renaming even if target file or directory name already exists (Default: False)", " -h Print help information (Default: False)", " -I file Include command line arguments from file", - " -i num Specify which instance to replace (Default: %s, Global Replace)" % GLOBAL, + " -i num Specify which instance to replace (Default: %s)" % DEFINST, " -P char Use 'char' as the escape sequence (Default: %s)" % DEFESC, " -q Quiet mode, do not show progress (Default: False)", " -R char Separator character for -r rename arguments (Default: %s)" % DEFSEP, @@ -226,18 +228,19 @@ ProgramOptions = { - DEBUG : False, # Debugging off - CASESENSITIVE : True, # Search is case-sensitive - ESCAPE : DEFESC, # Escape string - ERRORCONTINUE : False, # Do not continue after error - EXISTSUFFIX : DEFSUFFIX, # What to tack on when renaming existing targets - FORCERENAME : False, # Do not rename if target already exists - MAXLINELEN : DEFLEN, # Width of output messages - QUIET : False, # Display progress - INSTANCE : GLOBAL, # Default to global replacement - REGEX : False, # Do not treat old string as a regex - RENSEP : DEFSEP, # Old, New string separator for -r - TESTMODE : False # Test mode off + DEBUG : False, # Debugging off + CASESENSITIVE : True, # Search is case-sensitive + ESCAPE : DEFESC, # Escape string + ERRORCONTINUE : False, # Do not continue after error + EXISTSUFFIX : DEFSUFFIX, # What to tack on when renaming existing targets + FORCERENAME : False, # Do not rename if target already exists + INSTANCESTART : DEFINST, # Replace first, leftmost instance by default + INSTANCEEND : SINGLEINST, + MAXLINELEN : DEFLEN, # Width of output messages + QUIET : False, # Display progress + REGEX : False, # Do not treat old string as a regex + RENSEP : DEFSEP, # Old, New string separator for -r + TESTMODE : False # Test mode off } @@ -287,8 +290,9 @@ CASESENSITIVE : case sensitivity flag, ERRORCONTINUE : error continuation flag, FORCERENAME : force renaming flag, + INSTANCESTART : DReplace first, leftmost instance by default + INSTANCEEND : MAXLINELEN : max output line length, - INSTANCE : what instance(s) should be replaced, QUIET : quiet output flag, REGEX : regular expression enable flag, RENSEP : old/new rename separator string, @@ -483,7 +487,7 @@ # Only process leftmost occurence if global replace is off - if not renrequest[INSTANCE]: + if not renrequest[DEFINST]: oldstrings = [oldstrings[0],] # Replace selected substring(s). @@ -956,43 +960,81 @@ for opt, val in opts: + # Select case-sensitivity for replacements (or not) + if opt == "-C": ProgramOptions[CASESENSITIVE] = True if opt == "-c": ProgramOptions[CASESENSITIVE] = False + # Turn on debugging + if opt == "-d": ProgramOptions[DEBUG] = True DumpState() + + # Force continuation through errors, if possible + if opt == "-E": ProgramOptions[ERRORCONTINUE] = True + # Force renaming of existing targets + if opt == "-f": ProgramOptions[FORCERENAME] = True + + # Output usage information + if opt == "-h": Usage() sys.exit(0) + + # Specify which instances to replace + if opt == "-i": - # Record the presence of an "Replace up to ..." introducer - - prefix = val[0] - if prefix == UPTO: - val = val[1:] - - else: - prefix = "" - + # Parse the argument try: - instance = int(val) + + # Process ranges + + if val.count(RANGESEP): + + lhs, rhs = val.split(RANGESEP) + + + if not lhs: + lhs = None + + else: + lhs = int(lhs) + + if not rhs: + rhs = None + + else: + rhs = int(rhs) + + # Process single indexes + + else: + + lhs = int(val) + rhs = SINGLEINST + + # Something about the argument was bogus + except: ErrorMsg(eBADINSTANCE % val, EXIT=True) - ProgramOptions[INSTANCE] = (prefix, val) + ProgramOptions[INSTANCESTART] = lhs + ProgramOptions[INSTANCEEND] = rhs + + # Set the escape character if opt == "-P": if len(val) == 1: @@ -1000,15 +1042,21 @@ else: ErrorMsg(eARGLENGTH % (NULLESC, 1), EXIT=True) + # Set quiet mode + if opt == "-q": ProgramOptions[QUIET] = True + # Set the separator character for replacement specifications + if opt == '-R': if len(val) == 1: ProgramOptions[RENSEP] = val else: ErrorMsg(eARGLENGTH % (NULLRENSEP, 1), EXIT=True) + # Specify a replacement command + if opt == "-r": req = {} req[OLD], req[NEW] = GetOldNew(val) @@ -1016,18 +1064,27 @@ req[opt] = ProgramOptions[opt] targs.RenRequests.append(req) + # Specify a renaming suffix + if opt == "-S": if val: ProgramOptions[EXISTSUFFIX] = val else: ErrorMsg(eNULLARG % NULLSUFFIX, EXIT=True) + # Request test mode + if opt == "-t": ProgramOptions[TESTMODE] = True + + # Output program version info + if opt == "-v": PrintStdout(RCSID) + # Set output width + if opt == "-w": try: l = int(val) @@ -1037,6 +1094,8 @@ ErrorMsg(eLINELEN, EXIT=True) ProgramOptions[MAXLINELEN] = l + # Select whether 'old' replacement string is a regex or not + if opt == "-X": ProgramOptions[REGEX] = False