[Zope-Checkins] CVS: Packages/ZConfig - cfgparser.py:1.1.2.1 Context.py:1.15.10.4 ApacheStyle.py:NONE

Fred L. Drake, Jr. fred@zope.com
Tue, 10 Dec 2002 13:50:12 -0500


Update of /cvs-repository/Packages/ZConfig
In directory cvs.zope.org:/tmp/cvs-serv25692

Modified Files:
      Tag: zconfig-schema-devel-branch
	Context.py 
Added Files:
      Tag: zconfig-schema-devel-branch
	cfgparser.py 
Removed Files:
      Tag: zconfig-schema-devel-branch
	ApacheStyle.py 
Log Message:
Restructure the parser so it is not just one giant function.
This separates some of the syntax matters from dealing with semantics.


=== Added File Packages/ZConfig/cfgparser.py ===
"""Configuration parser."""

from ZConfig import ConfigurationError, ConfigurationSyntaxError
from ZConfig.Substitution import isname, substitute

try:
    True
except NameError:
    True = 1
    False = 0


class ZConfigParser:
    def __init__(self, resource, context):
        self.resource = resource
        self.context = context
        self.file = resource.file
        self.url = resource.url
        self.lineno = 0
        self.stack = []
        self.defs = {}

    def nextline(self):
        line = self.file.readline()
        if line:
            self.lineno += 1
            return False, line.strip()
        else:
            return True, None

    def parse(self, section):
        done, line = self.nextline()
        while not done:
            if not line:
                # blank line
                pass
            elif line[0] == "#":
                # comment
                pass

            elif line[:2] == "</":
                # section end
                if line[-1] != ">":
                    self.error("malformed section end")
                section = self.end_section(section, line[2:-1])

            elif line[0] == "<":
                # section start
                if line[-1] != ">":
                    self.error("malformed section start")
                section = self.start_section(section, line[1:-1])

            elif line[0] == "%":
                self.handle_directive(section, line[1:])

            else:
                self.handle_key_value(section, line)

            done, line = self.nextline()

        if self.stack:
            self.error("unclosed sections not allowed")

    def start_section(self, section, rest):
        isempty = rest[-1:] == "/"
        if isempty:
            text = rest[:-1].rstrip()
        else:
            text = rest.rstrip()
        # parse section start stuff here
        m = _section_start_rx.match(text)
        if not m:
            self.error("malformed section header")
        type, name, delegatename = m.group('type', 'name', 'delegatename')
        try:
            newsect = self.context.nestSection(section, type, name,
                                               delegatename)
        except ConfigurationError, e:
            self.error(e[0])
        if not isempty:
            self.stack.append(section)
            return newsect
        else:
            return section

    def end_section(self, section, rest):
        if not self.stack:
            self.error("unexpected section end")
        type = rest.rstrip().lower()
        if type != section.type:
            self.error("unbalanced section end")
        try:
            section.finish()
        except ConfigurationError, e:
            self.error(e[0])
        return self.stack.pop()

    def handle_key_value(self, section, rest):
        m = _keyvalue_rx.match(rest)
        if not m:
            self.error("malformed configuration data")
        key, value = m.group('key', 'value')
        if not value:
            value = ''
        else:
            value = substitute(value, self.defs)
        try:
            section.addValue(key, value)
        except ConfigurationError, e:
            self.error(e[0])

    def handle_directive(self, section, rest):
        m = _keyvalue_rx.match(rest)
        if not m:
            self.error("missing or unrecognized directive")
        name, arg = m.group('key', 'value')
        if name not in ("define", "include"):
            self.error("unknown directive: " + `name`)
        if not arg:
            self.error("missing argument to %%%s directive" % name)
        if name == "include":
            self.handle_include(section, arg)
        elif name == "define":
            self.handle_define(section, arg)
        else:
            assert 0, "unexpected directive for " + `"%" + rest`

    def handle_include(self, section, rest):
        import urlparse
        newurl = urlparse.urljoin(self.url, rest)
        self.context.includeConfiguration(section, newurl)

    def handle_define(self, section, rest):
        parts = rest.split(None, 1)
        defname = parts[0].lower()
        defvalue = ''
        if len(parts) == 2:
            defvalue = parts[1]
        if self.defs.has_key(defname):
            self.error("cannot redefine " + `defname`)
        if not isname(defname):
            self.error("not a substitution legal name: " + `defname`)
        self.defs[defname] = defvalue

    def error(self, message):
        raise ConfigurationSyntaxError(message, self.url, self.lineno)


import re
# _name_re cannot allow "(" or ")" since we need to be able to tell if
# a section has a name or not: <section (name)> would be ambiguous if
# parentheses were allowed in names.
_name_re = r"[^\s()]+"
_keyvalue_rx = re.compile(r"(?P<key>%s)\s*(?P<value>[^\s].*)?$"
                          % _name_re)
_section_start_rx = re.compile(r"(?P<type>%s)"
                               r"(?:\s+(?P<name>%s))?"
                               r"(?:\s*[(](?P<delegatename>%s)[)])?"
                               r"$"
                               % (_name_re, _name_re, _name_re))
del re


=== Packages/ZConfig/Context.py 1.15.10.3 => 1.15.10.4 ===
--- Packages/ZConfig/Context.py:1.15.10.3	Tue Dec 10 11:46:08 2002
+++ Packages/ZConfig/Context.py	Tue Dec 10 13:50:11 2002
@@ -5,8 +5,7 @@
 import ZConfig
 
 from ZConfig import loader
-
-from Config import Configuration
+from ZConfig.Config import Configuration
 
 
 class Context(loader.BaseLoader):
@@ -33,8 +32,8 @@
         return type.lower()
 
     def parse(self, resource, section):
-        from ApacheStyle import Parse
-        Parse(resource, self, section)
+        from ZConfig.cfgparser import ZConfigParser
+        ZConfigParser(resource, self).parse(section)
 
     # public API
 

=== Removed File Packages/ZConfig/ApacheStyle.py ===