1.1 --- a/vContent.py Fri Oct 17 23:12:25 2008 +0200
1.2 +++ b/vContent.py Sat Oct 18 01:41:15 2008 +0200
1.3 @@ -33,16 +33,28 @@
1.4 http://rfc.net/rfc2426.html
1.5 """
1.6
1.7 +try:
1.8 + set
1.9 +except NameError:
1.10 + from sets import Set as set
1.11 +
1.12 # Encoding-related imports.
1.13
1.14 import base64, quopri
1.15
1.16 +# Tokenisation help.
1.17 +
1.18 +import re
1.19 +
1.20 # Simple reader class.
1.21
1.22 class Reader:
1.23
1.24 "A simple class wrapping a file, providing simple pushback capabilities."
1.25
1.26 + SEPARATORS = re.compile('[;:"]')
1.27 + SEPARATORS_PLUS_EQUALS = re.compile('[=;:"]')
1.28 +
1.29 def __init__(self, f, non_standard_newline=0):
1.30
1.31 """
1.32 @@ -95,8 +107,6 @@
1.33 was found, return the entire string together with a target of None.
1.34 """
1.35
1.36 - indexes = {}
1.37 -
1.38 # Remember the entire text read and the index of the current line in
1.39 # that text.
1.40
1.41 @@ -106,40 +116,59 @@
1.42 lines.append(line)
1.43 start = 0
1.44
1.45 - while indexes == {} and line != "":
1.46 - for target in targets:
1.47 - index = line.find(target)
1.48 + # Remember the first target.
1.49 +
1.50 + first = None
1.51 + first_pos = None
1.52 + in_quoted_region = 0
1.53
1.54 - # Always choose the first matching target.
1.55 + # Process each line, looking for the targets.
1.56 +
1.57 + while line != "":
1.58 + match = targets.search(line, start)
1.59 +
1.60 + # Where nothing matches, get the next line.
1.61
1.62 - if index != -1 and not indexes.has_key(start + index):
1.63 - indexes[start + index] = target
1.64 + if match is None:
1.65 + line = self.readline()
1.66 + lines.append(line)
1.67 + start = 0
1.68
1.69 - start += len(line)
1.70 - line = self.readline()
1.71 - lines.append(line)
1.72 + # Where a double quote matches, toggle the region state.
1.73
1.74 - text = "".join(lines)
1.75 + elif match.group() == '"':
1.76 + in_quoted_region = not in_quoted_region
1.77 + start = match.end()
1.78 +
1.79 + # Where something else matches outside a region, stop searching.
1.80
1.81 - if indexes:
1.82 - min_index = reduce(min, indexes.keys())
1.83 - target = indexes[min_index]
1.84 + elif not in_quoted_region:
1.85 + first = match.group()
1.86 + first_pos = match.start()
1.87 + break
1.88
1.89 - # Skip the target.
1.90 - # Since the end of the buffer should always be a newline, ignore the
1.91 - # last element.
1.92 + # Otherwise, keep looking for the end of the region.
1.93 +
1.94 + else:
1.95 + start = match.end()
1.96 +
1.97 + # Where no more input can provide the targets, return a special result.
1.98
1.99 - lines = text[min_index + len(target):].split("\n")[:]
1.100 - if not lines[-1]:
1.101 - del lines[-1]
1.102 - lines.reverse()
1.103 + else:
1.104 + text = "".join(lines)
1.105 + return text, None
1.106 +
1.107 + # Push back the text after the target.
1.108
1.109 - for line in lines:
1.110 - self.pushback(line + "\n")
1.111 + after_target = lines[-1][first_pos + len(first):]
1.112 + self.pushback(after_target)
1.113
1.114 - return text[:min_index], target
1.115 - else:
1.116 - return text, None
1.117 + # Produce the lines until the matching line, together with the portion
1.118 + # of the matching line before the target.
1.119 +
1.120 + lines[-1] = lines[-1][:first_pos]
1.121 + text = "".join(lines)
1.122 + return text, first
1.123
1.124 class StreamParser:
1.125
1.126 @@ -176,7 +205,7 @@
1.127 f = self.f
1.128
1.129 parameters = {}
1.130 - name, sep = f.read_until([";", ":"])
1.131 + name, sep = f.read_until(f.SEPARATORS)
1.132
1.133 name = name.strip()
1.134
1.135 @@ -187,11 +216,11 @@
1.136
1.137 # Find the actual modifier.
1.138
1.139 - parameter_name, sep = f.read_until(["=", ";", ":"])
1.140 + parameter_name, sep = f.read_until(f.SEPARATORS_PLUS_EQUALS)
1.141 parameter_name = parameter_name.strip()
1.142
1.143 if sep == "=":
1.144 - parameter_value, sep = f.read_until([";", ":"])
1.145 + parameter_value, sep = f.read_until(f.SEPARATORS)
1.146 parameter_value = parameter_value.strip()
1.147 else:
1.148 parameter_value = None
1.149 @@ -313,7 +342,7 @@
1.150 def handleProperty(self, name, parameters, value):
1.151
1.152 """
1.153 - Record the component with the given 'name', 'parameters' and 'value' as
1.154 + Record the property with the given 'name', 'parameters' and 'value' as
1.155 part of the current component's children.
1.156 """
1.157