3 # Copyright (C) 1999-2006 The ViewCVS Group. All Rights Reserved.
5 # By using this file, you agree to the terms and conditions set forth in
6 # the LICENSE.html file which can be found at the top level of the ViewVC
7 # distribution or at http://viewvc.org/license-1.html.
9 # For more information, visit http://viewvc.org/
11 # -----------------------------------------------------------------------
13 # This file was originally based on portions of the blame.py script by
16 # -----------------------------------------------------------------------
22 token_term = string.whitespace + ';'
24 # the algorithm is about the same speed for any CHUNK_SIZE chosen.
25 # grab a good-sized chunk, but not too large to overwhelm memory.
26 # note: we use a multiple of a standard block size
27 CHUNK_SIZE = 192 * 512 # about 100k
29 # CHUNK_SIZE = 5 # for debugging, make the function grind...
31 def __init__(self, file):
34 self.buf = self.rcsfile.read(self.CHUNK_SIZE)
36 raise RuntimeError, 'EOF'
39 "Get the next token from the RCS file."
41 # Note: we can afford to loop within Python, examining individual
42 # characters. For the whitespace and tokens, the number of iterations
43 # is typically quite small. Thus, a simple iterative loop will beat
44 # out more complex solutions.
51 buf = self.rcsfile.read(self.CHUNK_SIZE)
53 # signal EOF by returning None as the token
54 del self.buf # so we fail if get() is called again
58 if buf[idx] not in string.whitespace:
72 # find token characters in the current buffer
73 while end < len(buf) and buf[end] not in self.token_term:
75 token = token + buf[idx:end]
78 # we stopped before the end, so we have a full token
82 # we stopped at the end of the buffer, so we may have a partial token
83 buf = self.rcsfile.read(self.CHUNK_SIZE)
90 # a "string" which starts with the "@" character. we'll skip it when we
99 buf = self.rcsfile.read(self.CHUNK_SIZE)
101 raise RuntimeError, 'EOF'
102 i = string.find(buf, '@', idx)
104 chunks.append(buf[idx:])
107 if i == len(buf) - 1:
108 chunks.append(buf[idx:i])
110 buf = '@' + self.rcsfile.read(self.CHUNK_SIZE)
112 raise RuntimeError, 'EOF'
114 if buf[i + 1] == '@':
115 chunks.append(buf[idx:i+1])
119 chunks.append(buf[idx:i])
124 return string.join(chunks, '')
132 def match(self, match):
133 "Try to match the next token from the input buffer."
137 raise RuntimeError, ('Unexpected parsing error in RCS file.\n' +
138 'Expected token: %s, but saw: %s' % (match, token))
140 def unget(self, token):
141 "Put this token back, for the next get() to return."
143 # Override the class' .get method with a function which clears the
144 # overridden method then returns the pushed token. Since this function
145 # will not be looked up via the class mechanism, it should be a "normal"
146 # function, meaning it won't have "self" automatically inserted.
147 # Therefore, we need to pass both self and the token thru via defaults.
149 # note: we don't put this into the input buffer because it may have been
150 # @-unescaped already.
152 def give_it_back(self=self, token=token):
156 self.get = give_it_back
158 def mget(self, count):
159 "Return multiple tokens. 'next' is at the end."
161 for i in range(count):
162 result.append(self.get())
167 class Parser(common._Parser):
168 stream_class = _TokenStream
170 def parse_rcs_admin(self):
172 # Read initial token at beginning of line
173 token = self.ts.get()
175 # We're done once we reach the description of the RCS tree
176 if token[0] in string.digits:
181 semi, rev = self.ts.mget(2)
182 self.sink.set_head_revision(rev)
184 raise common.RCSExpected(semi, ';')
185 elif token == "branch":
186 semi, branch = self.ts.mget(2)
188 self.sink.set_principal_branch(branch)
193 raise common.RCSExpected(semi, ';')
194 elif token == "symbols":
199 (tag_name, tag_rev) = string.split(tag, ':')
200 self.sink.define_tag(tag_name, tag_rev)
201 elif token == "comment":
202 semi, comment = self.ts.mget(2)
203 self.sink.set_comment(comment)
205 raise common.RCSExpected(semi, ';')
206 elif token == "expand":
207 semi, expand_mode = self.ts.mget(2)
208 self.sink.set_expansion(expand_mode)
210 raise RCSExpected(semi, ';')
211 elif token == "locks":
216 (locker, rev) = string.split(tag,':')
217 self.sink.set_locker(rev, locker)
221 self.sink.set_locking("strict")
225 elif token == "access":
231 self.sink.set_access(accessors)
233 accessors = accessors + [ tag ]
235 # Chew up "newphrase".
238 # warn("Unexpected RCS token: $token\n")
240 raise RuntimeError, "Unexpected EOF"