The usual...
diff --git a/Lib/dos-8x3/configpa.py b/Lib/dos-8x3/configpa.py
index dd8b6d8..e1ce9dd 100644
--- a/Lib/dos-8x3/configpa.py
+++ b/Lib/dos-8x3/configpa.py
@@ -33,11 +33,24 @@
sections()
return all the configuration section names, sans DEFAULT
+ has_section(section)
+ return whether the given section exists
+
options(section)
return list of configuration options for the named section
+ has_option(section, option)
+ return whether the given section has the given option
+
read(filenames)
- read and parse the list of named configuration files
+ read and parse the list of named configuration files, given by
+ name. A single filename is also allowed. Non-existing files
+ are ignored.
+
+ readfp(fp, filename=None)
+ read and parse one configuration file, given as a file object.
+ The filename defaults to fp.name; it is only used in error
+ messages (if fp has no `name' attribute, the string `<???>' is used).
get(section, option, raw=0, vars=None)
return a string value for the named option. All % interpolations are
@@ -158,6 +171,7 @@
return self.__sections.has_key(section)
def options(self, section):
+ """Return a list of option names for the given section name."""
try:
opts = self.__sections[section].copy()
except KeyError:
@@ -165,16 +179,49 @@
opts.update(self.__defaults)
return opts.keys()
+ def has_option(self, section, option):
+ """Return whether the given section has the given option."""
+ try:
+ opts = self.__sections[section]
+ except KeyError:
+ raise NoSectionError(section)
+ return opts.has_key(option)
+
def read(self, filenames):
- """Read and parse a list of filenames."""
+ """Read and parse a filename or a list of filenames.
+
+ Files that cannot be opened are silently ignored; this is
+ designed so that you can specify a list of potential
+ configuration file locations (e.g. current directory, user's
+ home directory, systemwide directory), and all existing
+ configuration files in the list will be read. A single
+ filename may also be given.
+ """
if type(filenames) is type(''):
filenames = [filenames]
- for file in filenames:
+ for filename in filenames:
try:
- fp = open(file, 'r')
- self.__read(fp)
+ fp = open(filename)
except IOError:
- pass
+ continue
+ self.__read(fp, filename)
+ fp.close()
+
+ def readfp(self, fp, filename=None):
+ """Like read() but the argument must be a file-like object.
+
+ The `fp' argument must have a `readline' method. Optional
+ second argument is the `filename', which if not given, is
+ taken from fp.name. If fp has no `name' attribute, `<???>' is
+ used.
+
+ """
+ if filename is None:
+ try:
+ filename = fp.name
+ except AttributeError:
+ filename = '<???>'
+ self.__read(fp, filename)
def get(self, section, option, raw=0, vars=None):
"""Get an option value for a given section.
@@ -199,7 +246,7 @@
# Update with the entry specific variables
if vars:
d.update(vars)
- option = string.lower(option)
+ option = self.optionxform(option)
try:
rawval = d[option]
except KeyError:
@@ -212,7 +259,7 @@
depth = 0
while depth < 10: # Loop through this until it's done
depth = depth + 1
- if not string.find(value, "%("):
+ if string.find(value, "%(") >= 0:
try:
value = value % d
except KeyError, key:
@@ -236,25 +283,28 @@
raise ValueError, 'Not a boolean: %s' % v
return val
+ def optionxform(self, optionstr):
+ return string.lower(optionstr)
+
#
# Regular expressions for parsing section headers and options. Note a
# slight semantic change from the previous version, because of the use
# of \w, _ is allowed in section header names.
- __SECTCRE = re.compile(
+ SECTCRE = re.compile(
r'\[' # [
- r'(?P<header>[-\w]+)' # `-', `_' or any alphanum
+ r'(?P<header>[-\w_.*,(){}]+)' # a lot of stuff found by IvL
r'\]' # ]
)
- __OPTCRE = re.compile(
- r'(?P<option>[-.\w]+)' # - . _ alphanum
- r'[ \t]*[:=][ \t]*' # any number of space/tab,
+ OPTCRE = re.compile(
+ r'(?P<option>[-\w_.*,(){}]+)' # a lot of stuff found by IvL
+ r'[ \t]*(?P<vi>[:=])[ \t]*' # any number of space/tab,
# followed by separator
# (either : or =), followed
# by any # space/tab
r'(?P<value>.*)$' # everything up to eol
)
- def __read(self, fp):
+ def __read(self, fp, fpname):
"""Parse a sectioned setup file.
The sections in setup file contains a title line at the top,
@@ -277,7 +327,7 @@
if string.strip(line) == '' or line[0] in '#;':
continue
if string.lower(string.split(line)[0]) == 'rem' \
- and line[0] == "r": # no leading whitespace
+ and line[0] in "rR": # no leading whitespace
continue
# continuation line?
if line[0] in ' \t' and cursect is not None and optname:
@@ -287,7 +337,7 @@
# a section header or option header?
else:
# is it a section header?
- mo = self.__SECTCRE.match(line)
+ mo = self.SECTCRE.match(line)
if mo:
sectname = mo.group('header')
if self.__sections.has_key(sectname):
@@ -301,13 +351,19 @@
optname = None
# no section header in the file?
elif cursect is None:
- raise MissingSectionHeaderError(fp.name, lineno, `line`)
+ raise MissingSectionHeaderError(fpname, lineno, `line`)
# an option line?
else:
- mo = self.__OPTCRE.match(line)
+ mo = self.OPTCRE.match(line)
if mo:
- optname, optval = mo.group('option', 'value')
+ optname, vi, optval = mo.group('option', 'vi', 'value')
optname = string.lower(optname)
+ if vi in ('=', ':') and ';' in optval:
+ # ';' is a comment delimiter only if it follows
+ # a spacing character
+ pos = string.find(optval, ';')
+ if pos and optval[pos-1] in string.whitespace:
+ optval = optval[:pos]
optval = string.strip(optval)
# allow empty values
if optval == '""':
@@ -319,7 +375,7 @@
# raised at the end of the file and will contain a
# list of all bogus lines
if not e:
- e = ParsingError(fp.name)
+ e = ParsingError(fpname)
e.append(lineno, `line`)
# if any parsing errors occurred, raise an exception
if e: