From 68f8a8061d4f217ec97d8dc19925ba3b57621be1 Mon Sep 17 00:00:00 2001 From: Fred Drake Date: Mon, 24 Sep 2001 20:01:28 +0000 Subject: [PATCH] New base class for the SGMLParser and HTMLParser classes from the sgmllib and HTMLParser modules (and indirectly for the htmllib.HTMLParser class). This has all the support for scanning over DOCTYPE declarations; it warrants having a base class since this is a fair amount of tedious code (since it's fairly strict), and should be in a separate module to avoid compiling many REs that are not used (which would happen if this were placed in either then sgmllib or HTMLParser module). --- Lib/markupbase.py | 306 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 Lib/markupbase.py diff --git a/Lib/markupbase.py b/Lib/markupbase.py new file mode 100644 index 00000000000..0bb7c893b05 --- /dev/null +++ b/Lib/markupbase.py @@ -0,0 +1,306 @@ +"""Shared support for scanning document type declarations in HTML and XHTML.""" + +import re +import string + +_declname_match = re.compile(r'[a-zA-Z][-_.a-zA-Z0-9]*\s*').match +_declstringlit_match = re.compile(r'(\'[^\']*\'|"[^"]*")\s*').match + +del re + + +class ParserBase: + """Parser base class which provides some common support methods used + by the SGML/HTML and XHTML parsers.""" + + def reset(self): + self.lineno = 1 + self.offset = 0 + + def getpos(self): + """Return current line number and offset.""" + return self.lineno, self.offset + + # Internal -- update line number and offset. This should be + # called for each piece of data exactly once, in order -- in other + # words the concatenation of all the input strings to this + # function should be exactly the entire input. + def updatepos(self, i, j): + if i >= j: + return j + rawdata = self.rawdata + nlines = string.count(rawdata, "\n", i, j) + if nlines: + self.lineno = self.lineno + nlines + pos = string.rindex(rawdata, "\n", i, j) # Should not fail + self.offset = j-(pos+1) + else: + self.offset = self.offset + j-i + return j + + _decl_otherchars = '' + + # Internal -- parse declaration (for use by subclasses). + def parse_declaration(self, i): + # This is some sort of declaration; in "HTML as + # deployed," this should only be the document type + # declaration (""). + rawdata = self.rawdata + import sys + j = i + 2 + assert rawdata[i:j] == "' + n = len(rawdata) + decltype, j = self._scan_name(j, i) + if j < 0: + return j + if decltype == "doctype": + self._decl_otherchars = '' + while j < n: + c = rawdata[j] + if c == ">": + # end of declaration syntax + data = rawdata[i+2:j] + if decltype == "doctype": + self.handle_decl(data) + else: + self.unknown_decl(data) + return j + 1 + if c in "\"'": + m = _declstringlit_match(rawdata, j) + if not m: + return -1 # incomplete + j = m.end() + elif c in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ": + name, j = self._scan_name(j, i) + elif c in self._decl_otherchars: + j = j + 1 + elif c == "[": + if decltype == "doctype": + j = self._parse_doctype_subset(j + 1, i) + else: + self.error("unexpected '[' char in declaration") + else: + self.error( + "unexpected %s char in declaration" % `rawdata[j]`) + if j < 0: + return j + return -1 # incomplete + + # Internal -- scan past the internal subset in a n: + # end of buffer; incomplete + return -1 + if rawdata[j:j+4] == "