Ignore:
Timestamp:
Mar 19, 2014, 11:11:30 AM (11 years ago)
Author:
dmik
Message:

python: Update vendor to 2.7.6.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • python/vendor/current/Lib/HTMLParser.py

    r2 r388  
    1515
    1616interesting_normal = re.compile('[&<]')
    17 interesting_cdata = re.compile(r'<(/|\Z)')
    1817incomplete = re.compile('&[a-zA-Z#]')
    1918
     
    2423piclose = re.compile('>')
    2524commentclose = re.compile(r'--\s*>')
    26 tagfind = re.compile('[a-zA-Z][-.a-zA-Z0-9:_]*')
     25tagfind = re.compile('([a-zA-Z][-.a-zA-Z0-9:_]*)(?:\s|/(?!>))*')
     26# see http://www.w3.org/TR/html5/tokenization.html#tag-open-state
     27# and http://www.w3.org/TR/html5/tokenization.html#tag-name-state
     28tagfind_tolerant = re.compile('[a-zA-Z][^\t\n\r\f />\x00]*')
     29
    2730attrfind = re.compile(
    28     r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*'
    29     r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]*))?')
     31    r'((?<=[\'"\s/])[^\s/>][^\s/=>]*)(\s*=+\s*'
     32    r'(\'[^\']*\'|"[^"]*"|(?![\'"])[^>\s]*))?(?:\s|/(?!>))*')
    3033
    3134locatestarttagend = re.compile(r"""
    3235  <[a-zA-Z][-.a-zA-Z0-9:_]*          # tag name
    33   (?:\s+                             # whitespace before attribute name
    34     (?:[a-zA-Z_][-.:a-zA-Z0-9_]*     # attribute name
    35       (?:\s*=\s*                     # value indicator
     36  (?:[\s/]*                          # optional whitespace before attribute name
     37    (?:(?<=['"\s/])[^\s/>][^\s/=>]*  # attribute name
     38      (?:\s*=+\s*                    # value indicator
    3639        (?:'[^']*'                   # LITA-enclosed value
    37           |\"[^\"]*\"                # LIT-enclosed value
    38           |[^'\">\s]+                # bare value
     40          |"[^"]*"                   # LIT-enclosed value
     41          |(?!['"])[^>\s]*           # bare value
    3942         )
    40        )?
    41      )
    42    )*
     43       )?(?:\s|/(?!>))*
     44     )*
     45   )?
    4346  \s*                                # trailing whitespace
    4447""", re.VERBOSE)
    4548endendtag = re.compile('>')
     49# the HTML 5 spec, section 8.1.2.2, doesn't allow spaces between
     50# </ and the tag name, so maybe this should be fixed
    4651endtagfind = re.compile('</\s*([a-zA-Z][-.a-zA-Z0-9:_]*)\s*>')
    4752
     
    97102        self.lasttag = '???'
    98103        self.interesting = interesting_normal
     104        self.cdata_elem = None
    99105        markupbase.ParserBase.reset(self)
    100106
    101107    def feed(self, data):
    102         """Feed data to the parser.
     108        r"""Feed data to the parser.
    103109
    104110        Call this as often as you want, with as little or as much text
     
    121127        return self.__starttag_text
    122128
    123     def set_cdata_mode(self):
    124         self.interesting = interesting_cdata
     129    def set_cdata_mode(self, elem):
     130        self.cdata_elem = elem.lower()
     131        self.interesting = re.compile(r'</\s*%s\s*>' % self.cdata_elem, re.I)
    125132
    126133    def clear_cdata_mode(self):
    127134        self.interesting = interesting_normal
     135        self.cdata_elem = None
    128136
    129137    # Internal -- handle data as far as reasonable.  May leave state
     
    139147                j = match.start()
    140148            else:
     149                if self.cdata_elem:
     150                    break
    141151                j = n
    142152            if i < j: self.handle_data(rawdata[i:j])
     
    154164                    k = self.parse_pi(i)
    155165                elif startswith("<!", i):
    156                     k = self.parse_declaration(i)
     166                    k = self.parse_html_declaration(i)
    157167                elif (i + 1) < n:
    158168                    self.handle_data("<")
     
    161171                    break
    162172                if k < 0:
    163                     if end:
    164                         self.error("EOF in middle of construct")
    165                     break
     173                    if not end:
     174                        break
     175                    k = rawdata.find('>', i + 1)
     176                    if k < 0:
     177                        k = rawdata.find('<', i + 1)
     178                        if k < 0:
     179                            k = i + 1
     180                    else:
     181                        k += 1
     182                    self.handle_data(rawdata[i:k])
    166183                i = self.updatepos(i, k)
    167184            elif startswith("&#", i):
     
    176193                    continue
    177194                else:
     195                    if ";" in rawdata[i:]: #bail by consuming &#
     196                        self.handle_data(rawdata[0:2])
     197                        i = self.updatepos(i, 2)
    178198                    break
    179199            elif startswith('&', i):
     
    204224                assert 0, "interesting.search() lied"
    205225        # end while
    206         if end and i < n:
     226        if end and i < n and not self.cdata_elem:
    207227            self.handle_data(rawdata[i:n])
    208228            i = self.updatepos(i, n)
    209229        self.rawdata = rawdata[i:]
     230
     231    # Internal -- parse html declarations, return length or -1 if not terminated
     232    # See w3.org/TR/html5/tokenization.html#markup-declaration-open-state
     233    # See also parse_declaration in _markupbase
     234    def parse_html_declaration(self, i):
     235        rawdata = self.rawdata
     236        if rawdata[i:i+2] != '<!':
     237            self.error('unexpected call to parse_html_declaration()')
     238        if rawdata[i:i+4] == '<!--':
     239            # this case is actually already handled in goahead()
     240            return self.parse_comment(i)
     241        elif rawdata[i:i+3] == '<![':
     242            return self.parse_marked_section(i)
     243        elif rawdata[i:i+9].lower() == '<!doctype':
     244            # find the closing >
     245            gtpos = rawdata.find('>', i+9)
     246            if gtpos == -1:
     247                return -1
     248            self.handle_decl(rawdata[i+2:gtpos])
     249            return gtpos+1
     250        else:
     251            return self.parse_bogus_comment(i)
     252
     253    # Internal -- parse bogus comment, return length or -1 if not terminated
     254    # see http://www.w3.org/TR/html5/tokenization.html#bogus-comment-state
     255    def parse_bogus_comment(self, i, report=1):
     256        rawdata = self.rawdata
     257        if rawdata[i:i+2] not in ('<!', '</'):
     258            self.error('unexpected call to parse_comment()')
     259        pos = rawdata.find('>', i+2)
     260        if pos == -1:
     261            return -1
     262        if report:
     263            self.handle_comment(rawdata[i+2:pos])
     264        return pos + 1
    210265
    211266    # Internal -- parse processing instr, return end or -1 if not terminated
     
    235290        assert match, 'unexpected call to parse_starttag()'
    236291        k = match.end()
    237         self.lasttag = tag = rawdata[i+1:k].lower()
     292        self.lasttag = tag = match.group(1).lower()
    238293
    239294        while k < endpos:
     
    247302                 attrvalue[:1] == '"' == attrvalue[-1:]:
    248303                attrvalue = attrvalue[1:-1]
     304            if attrvalue:
    249305                attrvalue = self.unescape(attrvalue)
    250306            attrs.append((attrname.lower(), attrvalue))
     
    260316            else:
    261317                offset = offset + len(self.__starttag_text)
    262             self.error("junk characters in start tag: %r"
    263                        % (rawdata[k:endpos][:20],))
     318            self.handle_data(rawdata[i:endpos])
     319            return endpos
    264320        if end.endswith('/>'):
    265321            # XHTML-style empty tag: <span attr="value" />
     
    268324            self.handle_starttag(tag, attrs)
    269325            if tag in self.CDATA_CONTENT_ELEMENTS:
    270                 self.set_cdata_mode()
     326                self.set_cdata_mode(tag)
    271327        return endpos
    272328
     
    298354                # '/' from a '/>' ending
    299355                return -1
    300             self.updatepos(i, j)
    301             self.error("malformed start tag")
     356            if j > i:
     357                return j
     358            else:
     359                return i + 1
    302360        raise AssertionError("we should not get here!")
    303361
     
    309367        if not match:
    310368            return -1
    311         j = match.end()
     369        gtpos = match.end()
    312370        match = endtagfind.match(rawdata, i) # </ + tag + >
    313371        if not match:
    314             self.error("bad end tag: %r" % (rawdata[i:j],))
    315         tag = match.group(1)
    316         self.handle_endtag(tag.lower())
     372            if self.cdata_elem is not None:
     373                self.handle_data(rawdata[i:gtpos])
     374                return gtpos
     375            # find the name: w3.org/TR/html5/tokenization.html#tag-name-state
     376            namematch = tagfind_tolerant.match(rawdata, i+2)
     377            if not namematch:
     378                # w3.org/TR/html5/tokenization.html#end-tag-open-state
     379                if rawdata[i:i+3] == '</>':
     380                    return i+3
     381                else:
     382                    return self.parse_bogus_comment(i)
     383            tagname = namematch.group().lower()
     384            # consume and ignore other stuff between the name and the >
     385            # Note: this is not 100% correct, since we might have things like
     386            # </tag attr=">">, but looking for > after tha name should cover
     387            # most of the cases and is much simpler
     388            gtpos = rawdata.find('>', namematch.end())
     389            self.handle_endtag(tagname)
     390            return gtpos+1
     391
     392        elem = match.group(1).lower() # script or style
     393        if self.cdata_elem is not None:
     394            if elem != self.cdata_elem:
     395                self.handle_data(rawdata[i:gtpos])
     396                return gtpos
     397
     398        self.handle_endtag(elem)
    317399        self.clear_cdata_mode()
    318         return j
     400        return gtpos
    319401
    320402    # Overridable -- finish processing of start+end tag: <tag.../>
     
    356438
    357439    def unknown_decl(self, data):
    358         self.error("unknown declaration: %r" % (data,))
     440        pass
    359441
    360442    # Internal -- helper to remove special character quoting
     
    365447        def replaceEntities(s):
    366448            s = s.groups()[0]
    367             if s[0] == "#":
    368                 s = s[1:]
    369                 if s[0] in ['x','X']:
    370                     c = int(s[1:], 16)
    371                 else:
    372                     c = int(s)
    373                 return unichr(c)
     449            try:
     450                if s[0] == "#":
     451                    s = s[1:]
     452                    if s[0] in ['x','X']:
     453                        c = int(s[1:], 16)
     454                    else:
     455                        c = int(s)
     456                    return unichr(c)
     457            except ValueError:
     458                return '&#'+s+';'
    374459            else:
    375460                # Cannot use name2codepoint directly, because HTMLParser supports apos,
Note: See TracChangeset for help on using the changeset viewer.