Changed renaming templates: g -> GID, G -> GNAME, L -> LEN, F -> FNAME, u -> UID, U -> UNAME.
Upped MAXINCLUDES to 1000.
Cleaned up Usage() output.
Removed extraneous "]' option that was previously accepted by getopt() as legal.
Factored out the getopt() string as a literal at the top of the program.
Fixed bug in ProcessIncludes() so include symbol ignored if in context of a previous option argument.
1 parent 938d5b8 commit ac89ad844c59877a89a874f44e5a24954f4d4d86
@tundra tundra authored on 8 Mar 2010
Showing 1 changed file
View
208
tren.py
 
PROGNAME = "tren.py"
BASENAME = PROGNAME.split(".py")[0]
PROGENV = BASENAME.upper()
RCSID = "$Id: tren.py,v 1.172 2010/03/06 16:26:17 tundra Exp $"
RCSID = "$Id: tren.py,v 1.173 2010/03/08 16:41:23 tundra Exp $"
VERSION = RCSID.split()[2]
 
# Copyright Information
 
#####
# General Program Constants
#####
 
MAXINCLUDES = 50 # Maximum number of includes allowed
MAXINCLUDES = 1000 # Maximum number of includes allowed - used to catch circular references
MAXNAMELEN = 255 # Maximum file or directory name length
MINNAMELEN = 1 # Minimum file or directory name length
 
#####
PADWIDTH = 30 # Column width
LSTPAD = 13 # Padding to use when dumping lists
WRAPINDENT = 8 # Extra indent on wrapped lines
MINLEN = PADWIDTH + WRAPINDENT + 1 # Minimum line length
 
 
#####
# Command Line Option Strings
#####
 
# List all legal command line options that will be processed by getopt() later.
# We exclude -I here because it is parsed manually before the getopt() call.
 
OPTIONSLIST = "Ccdfhi:P:qR:r:S:tvw:Xx" # All legal command line options in getopt() format
 
 
#####
# Literals
 
TOKCMDEXEC = "`" # Delimiter for command execution renaming tokens
TOKDELIM = "/" # Delimiter for all renaming tokens
TOKENV = "$" # Introducer for environment variable replacement tokens
TOKFILGID = "g" # File GID replacement token
TOKFILGRP = "G" # File Group Name replacement token
TOKFILLEN = "L" # File Length replacement token
TOKFILNAM = "F" # File Name replacement token
TOKFILUID = "u" # File UID replacement token
TOKFILUNAM = "U" # File User Name replacement token
TOKFILGID = "GID" # File GID replacement token
TOKFILGRP = "GNAME" # File Group Name replacement token
TOKFILLEN = "LEN" # File Length replacement token
TOKFILNAM = "FNAME" # File Name replacement token
TOKFILUID = "UID" # File UID replacement token
TOKFILUNAM = "UNAME" # File User Name replacement token
 
 
# Internal program state literals
 
" -r old=new Replace old with new in file or directory names",
" -S suffix Suffix to use when renaming existing filenames (Default: %s)" % DEFSUFFIX,
" -t Test mode, don't rename, just show what the program *would* do (Default: False)",
" -v Print detailed program version information and continue (Default: False)",
" -w Line length of diagnostic and error output (Default: %s)" % DEFLEN,
" -w width Line length of diagnostic and error output (Default: %s)" % DEFLEN,
" -X Treat the renaming strings literally (Default)",
" -x Treat the old replacement string as a Python regular expression (Default: False)",
]
 
 
def ProcessIncludes(OPTIONS):
 
""" Resolve include file references allowing for nested includes.
This has to be done here separate from the command line options so
that getopt() processing below will "see" the included statements.
This has to be done here separate from the command line
options so that normal getopt() processing below will "see"
the included statements.
 
This is a bit tricky because we have to handle every possible
legal command line syntax for option specification:
 
-....I filename
-....Ifilename
"""
 
# Build a list of all the options that take arguments. This is
# needed to determine whether the include symbol is an include
# option or part of an argument to a preceding option.
 
OPTIONSWITHARGS = ""
for i in re.finditer(":", OPTIONSLIST):
OPTIONSWITHARGS += OPTIONSLIST[i.start() - 1]
 
NUMINCLUDES = 0
FoundNewInclude = True
 
while FoundNewInclude:
# isolating the requested filename and replaciing its
# contents at that position in the command line.
 
field = OPTIONS[i]
if field.startswith(OPTINTRO) and (field.find(INCL) > -1):
 
FoundNewInclude = True
lhs, rhs = field.split(INCL)
 
if lhs == OPTINTRO:
lhs = ""
 
if rhs == "":
 
if i < len(OPTIONS)-1:
 
inclfile = OPTIONS[i+1]
OPTIONS = OPTIONS[:i+1] + OPTIONS[i+2:]
 
# We have an include without a filename at the end
# of the command line which is bogus.
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
# previous option argument
 
previousopt = False
for c in OPTIONSWITHARGS:
 
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 = ""
 
if rhs == "":
 
if i < len(OPTIONS)-1:
 
inclfile = OPTIONS[i+1]
OPTIONS = OPTIONS[:i+1] + OPTIONS[i+2:]
 
# We have an include without a filename at the end
# of the command line which is bogus.
else:
ErrorMsg(eBADARG % eBADINCL)
 
else:
ErrorMsg(eBADARG % eBADINCL)
 
else:
inclfile = rhs
 
# Before actually doing the include, make sure we've
# not exceeded the limit. This is here mostly to make
# sure we stop recursive/circular includes.
 
NUMINCLUDES += 1
if NUMINCLUDES > MAXINCLUDES:
ErrorMsg(eTOOMANYINC)
 
# Read the included file, stripping out comments
 
try:
n = []
f = open(inclfile)
for line in f.readlines():
line = line.split(COMMENT)[0]
n += line.split()
f.close()
# Keep track of the filenames being included
IncludedFiles.append(os.path.abspath(inclfile))
 
# Insert content of included file at current
# command line position
 
# A non-null left hand side means that there were
# options before the include we need to preserve
 
if lhs:
n = [lhs] + n
 
OPTIONS = OPTIONS[:i] + n + OPTIONS[i+1:]
except IOError as e:
ErrorMsg(eFILEOPEN % (inclfile, e.args[1]))
inclfile = rhs
 
# Before actually doing the include, make sure we've
# not exceeded the limit. This is here mostly to make
# sure we stop recursive/circular includes.
 
NUMINCLUDES += 1
if NUMINCLUDES > MAXINCLUDES:
ErrorMsg(eTOOMANYINC)
 
# Read the included file, stripping out comments
 
try:
n = []
f = open(inclfile)
for line in f.readlines():
line = line.split(COMMENT)[0]
n += line.split()
f.close()
 
# Keep track of the filenames being included for debug output
 
IncludedFiles.append(os.path.abspath(inclfile))
 
# Insert content of included file at current
# command line position
 
# A non-null left hand side means that there were
# options before the include we need to preserve
 
if lhs:
n = [lhs] + n
 
OPTIONS = OPTIONS[:i] + n + OPTIONS[i+1:]
 
except IOError as e:
ErrorMsg(eFILEOPEN % (inclfile, e.args[1]))
i += 1
 
return OPTIONS
 
# And parse the command line
 
try:
opts, args = getopt.getopt(OPTIONS, 'Ccdfhi:P:qR:r:S:tvw:Xx]')
opts, args = getopt.getopt(OPTIONS, OPTIONSLIST)
except getopt.GetoptError as e:
ErrorMsg(eBADARG % e.args[0])
 
# Create and populate an object with rename targets. This must be