| | #!/usr/bin/env python |
---|
| | # tren.py |
---|
| | # Copyright (c) 2010-2011 TundraWare Inc. |
---|
| | # Copyright (c) 2010-2020 TundraWare Inc. |
---|
| | # For Updates See: http://www.tundraware.com/Software/tren |
---|
| | |
---|
| | # Program Information |
---|
| | |
---|
| |
---|
| | |
---|
| | # Copyright Information |
---|
| | |
---|
| | CPRT = "(c)" |
---|
| | DATE = "2010-2011" |
---|
| | DATE = "2010-2020" |
---|
| | OWNER = "TundraWare Inc." |
---|
| | RIGHTS = "All Rights Reserved." |
---|
| | COPYRIGHT = "Copyright %s %s, %s %s" % (CPRT, DATE, OWNER, RIGHTS) |
---|
| | |
---|
| |
---|
| | elif OSNAME == 'posix': |
---|
| | POSIX = True |
---|
| | |
---|
| | # Set up Windows-specific stuff |
---|
| | |
---|
| | |
---|
| | if WINDOWS: |
---|
| | |
---|
| | # Try to load win32all stuff if it's available |
---|
| | |
---|
| |
---|
| | |
---|
| | else: |
---|
| | sys.stderr.write("Unsupported Operating System! Aborting ...\n") |
---|
| | sys.exit(1) |
---|
| | |
---|
| | |
---|
| | |
---|
| | #----------------------------------------------------------# |
---|
| | # Aliases & Redefinitions # |
---|
| | #----------------------------------------------------------# |
---|
| |
---|
| | |
---|
| | # Rename target keys |
---|
| | |
---|
| | BASE = "BASENAME" |
---|
| | PATHNAME = "PATHNAME" |
---|
| | PATHNAME = "PATHNAME" |
---|
| | STATS = "STATS" |
---|
| | |
---|
| | # These literals serve two purposes: |
---|
| | # |
---|
| |
---|
| | 't' : str.title, |
---|
| | 'u' : str.upper |
---|
| | } |
---|
| | |
---|
| | CASEOPS = CASETBL.keys() |
---|
| | CASEOPS = list(CASETBL.keys()) |
---|
| | CASEOPS.sort() |
---|
| | |
---|
| | |
---|
| | # Day And Month Conversion Tables |
---|
| | |
---|
| | |
---|
| | DAYS = {0:"Mon", 1:"Tue", 2:"Wed", 3:"Thu", 4:"Fri", 5:"Sat", 6:"Sun"} |
---|
| | |
---|
| | |
---|
| | MONTHS = {1:"Jan", 2:"Feb", 3:"Mar", 4:"Apr", 5:"May", 6:"Jun", |
---|
| | 7:"Jul", 8:"Aug", 9:"Sep", 10:"Oct", 11:"Nov", 12:"Dec"} |
---|
| | |
---|
| | # File Time Renaming Token Lookup Table |
---|
| |
---|
| | |
---|
| | ALPHABETS = { |
---|
| | |
---|
| | BINARY : ["0", "1"], |
---|
| | |
---|
| | |
---|
| | DECIMAL : ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], |
---|
| | |
---|
| | HEXLOWER : ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], |
---|
| | |
---|
| |
---|
| | QUIET : False, # Display progress |
---|
| | REGEX : False, # Do not treat old string as a regex |
---|
| | RENSEP : DEFSEP, # Old, New string separator for -r |
---|
| | TARGETSTART : False, # Entire file name is renaming target by default |
---|
| | TARGETEND : False, |
---|
| | TARGETEND : False, |
---|
| | TESTMODE : False # Test mode off |
---|
| | } |
---|
| | |
---|
| | |
---|
| |
---|
| | ##### |
---|
| | |
---|
| | class RenameTargets: |
---|
| | |
---|
| | """ |
---|
| | """ |
---|
| | This class is used to keep track of all the files and/or |
---|
| | directories we're renaming. After the class is constructed |
---|
| | and the command line fully parsed, this will contain: |
---|
| | |
---|
| |
---|
| | ORDERBYADATE-date... : [fullnames in order by atime within same 'date'] ... (repeated for each date), |
---|
| | ORDERBYCDATE-date... : [fullnames in order by ctime within same 'date'] ... (repeated for each date), |
---|
| | ORDERBYMDATE-date... : [fullnames in order by mtime within same 'date'] ... (repeated for each date) |
---|
| | } |
---|
| | |
---|
| | |
---|
| | self.RenRequests = [ |
---|
| | { |
---|
| | ASK : interactive ask flag |
---|
| | BACKUPS : do backups during forced renaming flag, |
---|
| |
---|
| | [ST_MTIME, {}, ORDERBYMTIME], |
---|
| | [ST_NLINK, {}, ORDERBYNLINK], |
---|
| | [ST_SIZE, {}, ORDERBYSIZE], |
---|
| | [ST_UID, {}, ORDERBYUID], |
---|
| | ["", {}, ORDERBYUSER], |
---|
| | ["", {}, ORDERBYUSER], |
---|
| | ] |
---|
| | |
---|
| | # Populate the data structures with each targets' stat information |
---|
| | |
---|
| |
---|
| | |
---|
| | try: |
---|
| | pathname, basename = os.path.split(fullname) |
---|
| | stats = os.stat(fullname) |
---|
| | except (IOError, OSError), (errno, errstr): |
---|
| | except (IOError, OSError) as xxx_todo_changeme2: |
---|
| | (errno, errstr) = xxx_todo_changeme2.args |
---|
| | ErrorMsg(eFILEOPEN % (fullname, errstr)) |
---|
| | |
---|
| | # Some operating systems (Windows) terminate the path with |
---|
| | # a separator, some (Posix) do not. |
---|
| | |
---|
| | if pathname[-1] != os.sep: |
---|
| | pathname += os.sep |
---|
| | |
---|
| | |
---|
| | # Store fullname, basename, and stat info for this file |
---|
| | |
---|
| | |
---|
| | if basename: |
---|
| | self.RenNames[fullname] = {BASE : basename, PATHNAME : pathname, STATS : stats} |
---|
| | |
---|
| | # Catch the case where they're trying to rename the root of the directory tree |
---|
| |
---|
| | elif order == ORDERBYUSER: |
---|
| | sortkey = self.__GetFileUsername(fullname) |
---|
| | |
---|
| | # Save into storage |
---|
| | |
---|
| | |
---|
| | if sortkey in storage: |
---|
| | storage[sortkey].append(fullname) |
---|
| | else: |
---|
| | storage[sortkey] = [fullname] |
---|
| |
---|
| | for seqtype in SeqTypes: |
---|
| | |
---|
| | statflag, storage, order = seqtype |
---|
| | |
---|
| | vieworder = storage.keys() |
---|
| | vieworder.sort() |
---|
| | vieworder = list(storage.keys()) |
---|
| | vieworder.sort() |
---|
| | |
---|
| | # Sort alphabetically when multiple filenames |
---|
| | # map to the same key, creating overall |
---|
| | # ordering as we go. |
---|
| |
---|
| | for dateorder, timeorder, year, mon, day in ((ORDERBYADATE, ORDERBYATIME, |
---|
| | FILETIMETOKS[TOKAYEAR], |
---|
| | FILETIMETOKS[TOKAMON], |
---|
| | FILETIMETOKS[TOKADAY]), |
---|
| | |
---|
| | |
---|
| | (ORDERBYCDATE, ORDERBYCTIME, |
---|
| | FILETIMETOKS[TOKCYEAR], |
---|
| | FILETIMETOKS[TOKCMON], |
---|
| | FILETIMETOKS[TOKCDAY]), |
---|
| |
---|
| | (ORDERBYMDATE, ORDERBYMTIME, |
---|
| | FILETIMETOKS[TOKMYEAR], |
---|
| | FILETIMETOKS[TOKMMON], |
---|
| | FILETIMETOKS[TOKMDAY])): |
---|
| | |
---|
| | |
---|
| | |
---|
| | lastdate = "" |
---|
| | for fullname in self.SortViews[timeorder]: |
---|
| | |
---|
| |
---|
| | if newdate != lastdate: |
---|
| | |
---|
| | self.DateViews[key] = [fullname] |
---|
| | lastdate = newdate |
---|
| | |
---|
| | |
---|
| | # Add file to existing list of others sharing that date |
---|
| | |
---|
| | else: |
---|
| | self.DateViews[key].append(fullname) |
---|
| |
---|
| | # End of '__init__()' |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Debug Dump |
---|
| | # Debug Dump |
---|
| | ##### |
---|
| | |
---|
| | def DumpObj(self): |
---|
| | |
---|
| |
---|
| | # Determine File's Group Name |
---|
| | ##### |
---|
| | |
---|
| | def __GetFileGroupname(self, fullname): |
---|
| | |
---|
| | |
---|
| | if POSIX: |
---|
| | return grp.getgrgid(self.RenNames[fullname][STATS][ST_GID])[0] |
---|
| | |
---|
| | else: |
---|
| |
---|
| | |
---|
| | retval = LookupAccountSid(fnhost, sidg)[0] |
---|
| | |
---|
| | # On any error, just act like win32all isn't there |
---|
| | |
---|
| | |
---|
| | except: |
---|
| | retval = WINGROUPNOT |
---|
| | |
---|
| | return retval |
---|
| |
---|
| | return pwd.getpwuid(self.RenNames[fullname][STATS][ST_UID])[0] |
---|
| | |
---|
| | else: |
---|
| | retval = WINDOWSUSER |
---|
| | |
---|
| | |
---|
| | if WIN32ALL: |
---|
| | |
---|
| | try: |
---|
| | |
---|
| |
---|
| | |
---|
| | retval = LookupAccountSid(fnhost, sido)[0] |
---|
| | |
---|
| | # On any error, just act like win32all isn't there |
---|
| | |
---|
| | |
---|
| | except: |
---|
| | retval = WINUSERNOT |
---|
| | |
---|
| | return retval |
---|
| |
---|
| | newname = oldname |
---|
| | |
---|
| | # Keep track of incremental renaming for use by debug |
---|
| | RenSequence = [oldname] |
---|
| | |
---|
| | |
---|
| | for renrequest in self.RenRequests: |
---|
| | |
---|
| | |
---|
| | # Select portion of name targeted for renaming |
---|
| | |
---|
| | lname = "" |
---|
| | rname = "" |
---|
| |
---|
| | # Condition values so that range slicing works properly below. |
---|
| | # This couldn't be done at the time the target range was |
---|
| | # saved intially, because the length of the name being processed |
---|
| | # isn't known until here. |
---|
| | |
---|
| | |
---|
| | if tstart == None: |
---|
| | tstart = 0 |
---|
| | |
---|
| | if tend == None: |
---|
| | tend = len(newname) |
---|
| | |
---|
| | |
---|
| | if tstart or tend: |
---|
| | |
---|
| | bound = len(newname) |
---|
| | |
---|
| | |
---|
| | # Normalize negative refs so we can use consistent |
---|
| | # logic below |
---|
| | |
---|
| | if tstart < 0: |
---|
| |
---|
| | if newname[tstart:tend]: |
---|
| | lname, newname, rname = newname[:tstart], newname[tstart:tend], newname[tend:] |
---|
| | |
---|
| | else: |
---|
| | lname, newname, rname = newname, "", "" |
---|
| | |
---|
| | lname, newname, rname = newname, "", "" |
---|
| | |
---|
| | |
---|
| | # Handle conventional string replacement renaming requests |
---|
| | # An empty newname here means that the -T argument processing |
---|
| | # selected a new string and/or was out of bounds -> we ignore the request. |
---|
| |
---|
| | |
---|
| | # Find every instance of the 'old' string in the |
---|
| | # current filename. 'Find' in this case can be either |
---|
| | # a regular expression pattern match or a literal |
---|
| | # string match. |
---|
| | # string match. |
---|
| | # |
---|
| | # Either way, each 'hit' is recorded as a tuple: |
---|
| | # |
---|
| | # (index to beginning of hit, beginning of next non-hit text) |
---|
| |
---|
| | |
---|
| | else: |
---|
| | |
---|
| | searchtarget = newname |
---|
| | |
---|
| | |
---|
| | # Collapse case if requested |
---|
| | |
---|
| | |
---|
| | if not renrequest[CASESENSITIVE]: |
---|
| | |
---|
| | searchtarget = searchtarget.lower() |
---|
| | old = old.lower() |
---|
| |
---|
| | newname = newname[:i[0]] + new + newname[i[1]:] |
---|
| | |
---|
| | |
---|
| | # Handle case conversion renaming requests |
---|
| | |
---|
| | |
---|
| | elif renrequest[CASECONV]: |
---|
| | newname = CASETBL[renrequest[CASECONV]](newname) |
---|
| | |
---|
| | # Any subsequent replacements operate on the modified name |
---|
| |
---|
| | newname = lname + newname + rname |
---|
| | |
---|
| | # Keep track of incremental renaming for use by debug |
---|
| | RenSequence.append(newname) |
---|
| | |
---|
| | |
---|
| | # Show the incremental renaming steps if debug is on |
---|
| | |
---|
| | if ProgramOptions[DEBUG]: |
---|
| | DebugMsg(dRENSEQ % ARROW.join(RenSequence)) |
---|
| |
---|
| | # Nothing to do, if old- and new names are the same |
---|
| | |
---|
| | if newname != oldname: |
---|
| | self.__RenameIt(pathname, oldname, newname) |
---|
| | |
---|
| | |
---|
| | # End of 'ProcessRenameRequests()' |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| |
---|
| | |
---|
| | self.indentlevel += 1 |
---|
| | indent = self.indentlevel * INDENT |
---|
| | newlen = len(newname) |
---|
| | |
---|
| | |
---|
| | # First make sure the new name meets length constraints |
---|
| | |
---|
| | if newlen < MINNAMELEN: |
---|
| | ErrorMsg(indent + eNAMESHORT% (oldname, newname, MINNAMELEN)) |
---|
| |
---|
| | self.__RenameIt(pathname, newname, bkuname) |
---|
| | |
---|
| | else: |
---|
| | InfoMsg(iFORCEDNOBKU % (fullold, fullnew)) |
---|
| | |
---|
| | |
---|
| | else: |
---|
| | InfoMsg(indent + iRENSKIPPED % (fullnew, fullold)) |
---|
| | doit = False |
---|
| | |
---|
| |
---|
| | # A blank line means take the default - do nothing. |
---|
| | |
---|
| | if not answer: |
---|
| | answer = ASKNO.lower() |
---|
| | |
---|
| | |
---|
| | if answer == ASKNO.lower(): |
---|
| | doit = False |
---|
| | |
---|
| | if answer == ASKYES.lower(): |
---|
| |
---|
| | if answer == ASKQUIT.lower(): |
---|
| | sys.exit(1) |
---|
| | |
---|
| | if doit: |
---|
| | |
---|
| | |
---|
| | # In test mode, track file names that would be produced. |
---|
| | |
---|
| | |
---|
| | if ProgramOptions[TESTMODE]: |
---|
| | |
---|
| | self.NewFiles.append(fullnew) |
---|
| | self.RenamedFiles.append(fullold) |
---|
| | |
---|
| | |
---|
| | if fullold in self.NewFiles: |
---|
| | self.NewFiles.remove(fullold) |
---|
| | |
---|
| | |
---|
| | if fullnew in self.RenamedFiles: |
---|
| | self.RenamedFiles.remove(fullnew) |
---|
| | |
---|
| | InfoMsg(indent + iRENAMING % (fullold, fullnew)) |
---|
| |
---|
| | if not ProgramOptions[TESTMODE]: |
---|
| | |
---|
| | try: |
---|
| | os.rename(fullold, fullnew) |
---|
| | except OSError, (errno, errstr): |
---|
| | except OSError as xxx_todo_changeme: |
---|
| | (errno, errstr) = xxx_todo_changeme.args |
---|
| | ErrorMsg(eRENAMEFAIL % (fullold, fullnew, errstr)) |
---|
| | |
---|
| | self.indentlevel -= 1 |
---|
| | |
---|
| | # End of '__RenameIt()' |
---|
| | |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Resolve Rename Tokens |
---|
| | ##### |
---|
| | |
---|
| |
---|
| | |
---|
| | for r in rentokens: |
---|
| | |
---|
| | fullrentoken = "%s%s%s" % (TOKDELIM, r[2], TOKDELIM) # Need this for error messages. |
---|
| | |
---|
| | |
---|
| | ### |
---|
| | # File Attribute Renaming Tokens |
---|
| | ### |
---|
| | |
---|
| | if r[2] == TOKFILDEV: |
---|
| | r[2] = str(self.RenNames[target][STATS][ST_DEV]) |
---|
| | |
---|
| | |
---|
| | elif r[2] == TOKFILFNAME: |
---|
| | r[2] = os.path.basename(target) |
---|
| | |
---|
| | elif r[2] == TOKFILGID: |
---|
| |
---|
| | r[2] = str(self.RenNames[target][STATS][ST_UID]) |
---|
| | |
---|
| | elif r[2] == TOKFILUSER: |
---|
| | r[2] = self.__GetFileUsername(target) |
---|
| | |
---|
| | |
---|
| | |
---|
| | ### |
---|
| | # File Time Renaming Tokens |
---|
| | ### |
---|
| |
---|
| | r[2] = MONTHS[val] |
---|
| | |
---|
| | elif parms[2] == "tm_wday": |
---|
| | r[2] = DAYS[val] |
---|
| | |
---|
| | |
---|
| | ### |
---|
| | # System Renaming Tokens |
---|
| | ### |
---|
| | |
---|
| | |
---|
| | # Environment Variable replacement token |
---|
| | |
---|
| | |
---|
| | elif r[2].startswith(TOKENV): |
---|
| | |
---|
| | r[2] = os.getenv(r[2][1:]) |
---|
| | |
---|
| | |
---|
| | # Handle case for nonexistent environment variable |
---|
| | |
---|
| | |
---|
| | if not r[2]: |
---|
| | r[2] = "" |
---|
| | |
---|
| | |
---|
| | |
---|
| | |
---|
| | # Command Run replacement token |
---|
| | |
---|
| | elif r[2].startswith(TOKCMDEXEC) and r[2].endswith(TOKCMDEXEC): |
---|
| | |
---|
| |
---|
| | pipe = os.popen(command, 'r') |
---|
| | |
---|
| | # Handle Unix variants |
---|
| | |
---|
| | else: |
---|
| | else: |
---|
| | pipe = os.popen('{ ' + command + '; } 2>&1', 'r') |
---|
| | |
---|
| | output = pipe.read() |
---|
| | status = pipe.close() |
---|
| |
---|
| | if status == None: |
---|
| | status = 0 |
---|
| | |
---|
| | # Nonzero status means error attempting to execute the command |
---|
| | |
---|
| | |
---|
| | if status: |
---|
| | ErrorMsg(eEXECFAIL % (fullrentoken, command)) |
---|
| | |
---|
| | # Otherwise swap the command with its results, stripping newlines |
---|
| | |
---|
| | |
---|
| | else: |
---|
| | r[2] = output.replace("\n", "") |
---|
| | |
---|
| | |
---|
| | # Random Number Replacement token |
---|
| | |
---|
| | |
---|
| | elif r[2].startswith(TOKRAND): |
---|
| | |
---|
| | random.seed() |
---|
| | |
---|
| |
---|
| | ErrorMsg(eTOKRANDIG % fullrentoken) |
---|
| | |
---|
| | if precision < 1: |
---|
| | ErrorMsg(eTOKRANDIG % fullrentoken) |
---|
| | |
---|
| | |
---|
| | fmt = '"%0' + str(precision) + 'd" % random.randint(0, pow(10, precision)-1)' |
---|
| | r[2] = eval(fmt) |
---|
| | |
---|
| | # Name So Far Replacement Token |
---|
| |
---|
| | |
---|
| | ### |
---|
| | # Sequence Renaming Tokens |
---|
| | ### |
---|
| | |
---|
| | |
---|
| | elif r[2] and (r[2][0] == TOKASCEND or r[2][0] == TOKDESCEND): |
---|
| | |
---|
| | # Parse the Sequence Renaming Token into the token itself |
---|
| | # and its corresponding formatting field. |
---|
| |
---|
| | |
---|
| | token = r[2][1:] |
---|
| | |
---|
| | found = False |
---|
| | for seqtoken in self.SortViews.keys() + [ORDERBYADATE, ORDERBYCDATE, ORDERBYMDATE]: |
---|
| | for seqtoken in list(self.SortViews.keys()) + [ORDERBYADATE, ORDERBYCDATE, ORDERBYMDATE]: |
---|
| | |
---|
| | if token.split(ALPHADELIM)[0] == (seqtoken): |
---|
| | |
---|
| | token, field = token[:len(seqtoken)], token[len(seqtoken):] |
---|
| |
---|
| | if not alphadelim: |
---|
| | ErrorMsg(eALPHABETMISSING % fullrentoken) |
---|
| | |
---|
| | # Empty alphabet string means default to decimal counting |
---|
| | |
---|
| | |
---|
| | if not alphabet: |
---|
| | alphabet = DECIMAL |
---|
| | |
---|
| | |
---|
| | if alphabet not in ALPHABETS: |
---|
| | ErrorMsg(eALPHABETEXIST % fullrentoken) |
---|
| | |
---|
| | |
---|
| |
---|
| | # (which is just the index of that filename in the |
---|
| | # list). |
---|
| | |
---|
| | # One of the standard sorted views requested |
---|
| | |
---|
| | |
---|
| | if token in self.SortViews: |
---|
| | orderedlist = self.SortViews[token][:] |
---|
| | |
---|
| | # One of the views sorted within dates requested |
---|
| |
---|
| | |
---|
| | ### |
---|
| | # Unrecognized Renaming Token |
---|
| | ### |
---|
| | |
---|
| | |
---|
| | else: |
---|
| | ErrorMsg(eTOKUNKNOWN % fullrentoken) |
---|
| | |
---|
| | |
---|
| | ### |
---|
| | # Successful Lookup, Do the actual replacement |
---|
| | ### |
---|
| | |
---|
| | renstring = renstring[:r[0]] + r[2] + renstring[r[1]+1:] |
---|
| | |
---|
| | |
---|
| | return renstring |
---|
| | |
---|
| | # End of '__ResolveRenameTokens()' |
---|
| | |
---|
| | |
---|
| | # End of class 'RenameTargets' |
---|
| | |
---|
| | |
---|
| | |
---|
| | #----------------------------------------------------------# |
---|
| | # Supporting Function Definitions # |
---|
| | #----------------------------------------------------------# |
---|
| |
---|
| | |
---|
| | |
---|
| | def ComputeSeqString(fmt, incr, alphabet): |
---|
| | |
---|
| | """ |
---|
| | """ |
---|
| | fmt = A literal "format field" string |
---|
| | incr = A integer to be "added" to the field |
---|
| | alphabet = The alphabet of characters to use, in ascending order |
---|
| | |
---|
| |
---|
| | result longer than fmt has MSD dropped, thereby effectively |
---|
| | rolling over the count. If 'fmt' is null on entry, the final |
---|
| | result length is unlimited. |
---|
| | """ |
---|
| | |
---|
| | |
---|
| | base = len(alphabet) |
---|
| | |
---|
| | # Do position-wise "addition" via symbol substitution moving from |
---|
| | # right-to-left adjusting for the fact that not all symbols in the |
---|
| | # format string will be in the alphabet. |
---|
| | |
---|
| | |
---|
| | |
---|
| | # First convert the increment into a string in the base of the |
---|
| | # alphabet |
---|
| | |
---|
| |
---|
| | if abs(i) <= incrlen: |
---|
| | sum += alphabet.index(incr[i]) |
---|
| | |
---|
| | # Do arithmetic modulo alphabet length |
---|
| | |
---|
| | |
---|
| | carry, digit = sum/base, sum % base |
---|
| | |
---|
| | if not carry: |
---|
| | carry = None |
---|
| |
---|
| | |
---|
| | # Result length constrained by format string |
---|
| | |
---|
| | if fmtlen: |
---|
| | |
---|
| | |
---|
| | if len(newval) > fmtlen: |
---|
| | InfoMsg(iSEQTOOLONG % (newval,fmt)) |
---|
| | newval = newval[-fmtlen:] |
---|
| | |
---|
| |
---|
| | ##### |
---|
| | # Condition Line Length With Fancy Wrap And Formatting |
---|
| | ##### |
---|
| | |
---|
| | def ConditionLine(msg, |
---|
| | def ConditionLine(msg, |
---|
| | PAD=PADCHAR, \ |
---|
| | WIDTH=PADWIDTH, \ |
---|
| | wrapindent=WRAPINDENT ): |
---|
| | |
---|
| |
---|
| | # Print A Debug Message |
---|
| | ##### |
---|
| | |
---|
| | def DebugMsg(msg): |
---|
| | |
---|
| | |
---|
| | l = ConditionLine(msg) |
---|
| | for msg in l: |
---|
| | PrintStderr(PROGNAME + " " + dDEBUG + ": " + msg) |
---|
| | |
---|
| |
---|
| | DebugMsg(SEPARATOR) |
---|
| | DebugMsg(dCURSTATE) |
---|
| | DebugMsg(SEPARATOR) |
---|
| | |
---|
| | opts = ProgramOptions.keys() |
---|
| | opts = list(ProgramOptions.keys()) |
---|
| | opts.sort() |
---|
| | for o in opts: |
---|
| | DebugMsg(ColumnPad([o, ProgramOptions[o]])) |
---|
| | |
---|
| |
---|
| | def GetOldNew(arg): |
---|
| | |
---|
| | |
---|
| | escaping = False |
---|
| | numseps = 0 |
---|
| | numseps = 0 |
---|
| | sepindex = 0 |
---|
| | oldnewsep = ProgramOptions[RENSEP] |
---|
| | |
---|
| | i = 0 |
---|
| |
---|
| | |
---|
| | if (i > 0 and (arg[i-1] != ProgramOptions[ESCAPE])) or i == 0: |
---|
| | sepindex = i |
---|
| | numseps += 1 |
---|
| | |
---|
| | |
---|
| | i += len(oldnewsep) |
---|
| | |
---|
| | else: |
---|
| | i += 1 |
---|
| |
---|
| | # contents at that position in the command line. |
---|
| | |
---|
| | field = OPTIONS[i] |
---|
| | position = field.find(INCL) |
---|
| | |
---|
| | |
---|
| | if field.startswith(OPTINTRO) and (position > -1): |
---|
| | |
---|
| | |
---|
| | |
---|
| | lhs = field[:position] |
---|
| | rhs = field[position+1:] |
---|
| | |
---|
| | # Make sure the include symbol isn't part of some |
---|
| |
---|
| | if c in lhs: |
---|
| | |
---|
| | previousopt = True |
---|
| | break |
---|
| | |
---|
| | |
---|
| | # If the include symbol appears in the context of a |
---|
| | # previous option, skip this field, otherwise process |
---|
| | # it as an include. |
---|
| | |
---|
| | |
---|
| | if not previousopt: |
---|
| | |
---|
| | |
---|
| | FoundNewInclude = True |
---|
| | if lhs == OPTINTRO: |
---|
| | lhs = "" |
---|
| | |
---|
| |
---|
| | n = [lhs] + n |
---|
| | |
---|
| | OPTIONS = OPTIONS[:i] + n + OPTIONS[i+1:] |
---|
| | |
---|
| | except IOError, (errno, errstr): |
---|
| | except IOError as xxx_todo_changeme1: |
---|
| | (errno, errstr) = xxx_todo_changeme1.args |
---|
| | ErrorMsg(eFILEOPEN % (inclfile, errstr)) |
---|
| | |
---|
| | |
---|
| | i += 1 |
---|
| | |
---|
| | return OPTIONS |
---|
| | |
---|
| |
---|
| | |
---|
| | def searchpath(filename, pathlist, pathdelim): |
---|
| | |
---|
| | # What we'll return if we find nothing |
---|
| | |
---|
| | |
---|
| | retval = [] |
---|
| | |
---|
| | # Find all instances of filename in specified paths |
---|
| | |
---|
| |
---|
| | # Program Entry Point # |
---|
| | #----------------------------------------------------------# |
---|
| | |
---|
| | # Set up proper include path delimiter |
---|
| | |
---|
| | |
---|
| | |
---|
| | if WINDOWS: |
---|
| | PATHDEL = PATHDELWIN |
---|
| | |
---|
| |
---|
| | |
---|
| | |
---|
| | ##### |
---|
| | # Command Line Preprocessing |
---|
| | # |
---|
| | # |
---|
| | # Some things have to be done *before* the command line |
---|
| | # options can actually be processed. This includes: |
---|
| | # |
---|
| | # 1) Prepending any options specified in the environment variable. |
---|
| |
---|
| | # And parse the command line |
---|
| | |
---|
| | try: |
---|
| | opts, args = getopt.getopt(OPTIONS, OPTIONSLIST) |
---|
| | except getopt.GetoptError, (errmsg, badarg): |
---|
| | except getopt.GetoptError as xxx_todo_changeme3: |
---|
| | (errmsg, badarg) = xxx_todo_changeme3.args |
---|
| | ErrorMsg(eBADARG % errmsg) |
---|
| | |
---|
| | # Create and populate an object with rename targets. This must be |
---|
| | # done here because this object also stores the -r renaming requests |
---|
| |
---|
| | if opt == "-b": |
---|
| | ProgramOptions[BACKUPS] = False |
---|
| | |
---|
| | # Select case-sensitivity for replacements (or not) |
---|
| | |
---|
| | |
---|
| | if opt == "-C": |
---|
| | ProgramOptions[CASESENSITIVE] = True |
---|
| | |
---|
| | if opt == "-c": |
---|
| |
---|
| | ProgramOptions[DEBUG] = True |
---|
| | DumpState() |
---|
| | |
---|
| | # Force case conversion |
---|
| | |
---|
| | |
---|
| | if opt == "-e": |
---|
| | |
---|
| | # Make sure we support the requested case conversion |
---|
| | if val in CASEOPS: |
---|
| | |
---|
| | ProgramOptions[CASECONV] = val |
---|
| | |
---|
| | # Construct a renaming request |
---|
| | |
---|
| | |
---|
| | req = {} |
---|
| | req[OLD], req[NEW] = None, None |
---|
| | for opt in ProgramOptions: |
---|
| | req[opt] = ProgramOptions[opt] |
---|
| |
---|
| | |
---|
| | # Error out if we don't recognize it |
---|
| | else: |
---|
| | ErrorMsg(eBADCASECONV % (val, ", ".join(CASEOPS))) |
---|
| | |
---|
| | |
---|
| | |
---|
| | # Force renaming of existing targets |
---|
| | |
---|
| | if opt == "-f": |
---|
| |
---|
| | else: |
---|
| | ErrorMsg(eARGLENGTH % (NULLESC, 1)) |
---|
| | |
---|
| | # Set quiet mode |
---|
| | |
---|
| | |
---|
| | if opt == "-q": |
---|
| | ProgramOptions[QUIET] = True |
---|
| | |
---|
| | # Set the separator character for replacement specifications |
---|
| |
---|
| | # Release the target container if we created one |
---|
| | |
---|
| | del targs |
---|
| | |
---|
| | |
---|
| | |