Show More
@@ -179,3 +179,86 class config(object): | |||||
179 | fp, fp.mode)) |
|
179 | fp, fp.mode)) | |
180 | self.parse(path, fp.read(), |
|
180 | self.parse(path, fp.read(), | |
181 | sections=sections, remap=remap, include=self.read) |
|
181 | sections=sections, remap=remap, include=self.read) | |
|
182 | ||||
|
183 | def parselist(value): | |||
|
184 | """parse a configuration value as a list of comma/space separated strings | |||
|
185 | ||||
|
186 | >>> parselist('this,is "a small" ,test') | |||
|
187 | ['this', 'is', 'a small', 'test'] | |||
|
188 | """ | |||
|
189 | ||||
|
190 | def _parse_plain(parts, s, offset): | |||
|
191 | whitespace = False | |||
|
192 | while offset < len(s) and (s[offset:offset + 1].isspace() | |||
|
193 | or s[offset:offset + 1] == ','): | |||
|
194 | whitespace = True | |||
|
195 | offset += 1 | |||
|
196 | if offset >= len(s): | |||
|
197 | return None, parts, offset | |||
|
198 | if whitespace: | |||
|
199 | parts.append('') | |||
|
200 | if s[offset:offset + 1] == '"' and not parts[-1]: | |||
|
201 | return _parse_quote, parts, offset + 1 | |||
|
202 | elif s[offset:offset + 1] == '"' and parts[-1][-1] == '\\': | |||
|
203 | parts[-1] = parts[-1][:-1] + s[offset:offset + 1] | |||
|
204 | return _parse_plain, parts, offset + 1 | |||
|
205 | parts[-1] += s[offset:offset + 1] | |||
|
206 | return _parse_plain, parts, offset + 1 | |||
|
207 | ||||
|
208 | def _parse_quote(parts, s, offset): | |||
|
209 | if offset < len(s) and s[offset:offset + 1] == '"': # "" | |||
|
210 | parts.append('') | |||
|
211 | offset += 1 | |||
|
212 | while offset < len(s) and (s[offset:offset + 1].isspace() or | |||
|
213 | s[offset:offset + 1] == ','): | |||
|
214 | offset += 1 | |||
|
215 | return _parse_plain, parts, offset | |||
|
216 | ||||
|
217 | while offset < len(s) and s[offset:offset + 1] != '"': | |||
|
218 | if (s[offset:offset + 1] == '\\' and offset + 1 < len(s) | |||
|
219 | and s[offset + 1:offset + 2] == '"'): | |||
|
220 | offset += 1 | |||
|
221 | parts[-1] += '"' | |||
|
222 | else: | |||
|
223 | parts[-1] += s[offset:offset + 1] | |||
|
224 | offset += 1 | |||
|
225 | ||||
|
226 | if offset >= len(s): | |||
|
227 | real_parts = _configlist(parts[-1]) | |||
|
228 | if not real_parts: | |||
|
229 | parts[-1] = '"' | |||
|
230 | else: | |||
|
231 | real_parts[0] = '"' + real_parts[0] | |||
|
232 | parts = parts[:-1] | |||
|
233 | parts.extend(real_parts) | |||
|
234 | return None, parts, offset | |||
|
235 | ||||
|
236 | offset += 1 | |||
|
237 | while offset < len(s) and s[offset:offset + 1] in [' ', ',']: | |||
|
238 | offset += 1 | |||
|
239 | ||||
|
240 | if offset < len(s): | |||
|
241 | if offset + 1 == len(s) and s[offset:offset + 1] == '"': | |||
|
242 | parts[-1] += '"' | |||
|
243 | offset += 1 | |||
|
244 | else: | |||
|
245 | parts.append('') | |||
|
246 | else: | |||
|
247 | return None, parts, offset | |||
|
248 | ||||
|
249 | return _parse_plain, parts, offset | |||
|
250 | ||||
|
251 | def _configlist(s): | |||
|
252 | s = s.rstrip(' ,') | |||
|
253 | if not s: | |||
|
254 | return [] | |||
|
255 | parser, parts, offset = _parse_plain, [''], 0 | |||
|
256 | while parser: | |||
|
257 | parser, parts, offset = parser(parts, s, offset) | |||
|
258 | return parts | |||
|
259 | ||||
|
260 | if value is not None and isinstance(value, bytes): | |||
|
261 | result = _configlist(value.lstrip(' ,\n')) | |||
|
262 | else: | |||
|
263 | result = value | |||
|
264 | return result or [] |
@@ -562,85 +562,11 class ui(object): | |||||
562 | >>> u.configlist(s, 'list1') |
|
562 | >>> u.configlist(s, 'list1') | |
563 | ['this', 'is', 'a small', 'test'] |
|
563 | ['this', 'is', 'a small', 'test'] | |
564 | """ |
|
564 | """ | |
565 |
|
565 | # default is not always a list | ||
566 | def _parse_plain(parts, s, offset): |
|
566 | if isinstance(default, bytes): | |
567 | whitespace = False |
|
567 | default = config.parselist(default) | |
568 | while offset < len(s) and (s[offset:offset + 1].isspace() |
|
568 | return self.configwith(config.parselist, section, name, default or [], | |
569 |
|
|
569 | 'list', untrusted) | |
570 | whitespace = True |
|
|||
571 | offset += 1 |
|
|||
572 | if offset >= len(s): |
|
|||
573 | return None, parts, offset |
|
|||
574 | if whitespace: |
|
|||
575 | parts.append('') |
|
|||
576 | if s[offset:offset + 1] == '"' and not parts[-1]: |
|
|||
577 | return _parse_quote, parts, offset + 1 |
|
|||
578 | elif s[offset:offset + 1] == '"' and parts[-1][-1] == '\\': |
|
|||
579 | parts[-1] = parts[-1][:-1] + s[offset:offset + 1] |
|
|||
580 | return _parse_plain, parts, offset + 1 |
|
|||
581 | parts[-1] += s[offset:offset + 1] |
|
|||
582 | return _parse_plain, parts, offset + 1 |
|
|||
583 |
|
||||
584 | def _parse_quote(parts, s, offset): |
|
|||
585 | if offset < len(s) and s[offset:offset + 1] == '"': # "" |
|
|||
586 | parts.append('') |
|
|||
587 | offset += 1 |
|
|||
588 | while offset < len(s) and (s[offset:offset + 1].isspace() or |
|
|||
589 | s[offset:offset + 1] == ','): |
|
|||
590 | offset += 1 |
|
|||
591 | return _parse_plain, parts, offset |
|
|||
592 |
|
||||
593 | while offset < len(s) and s[offset:offset + 1] != '"': |
|
|||
594 | if (s[offset:offset + 1] == '\\' and offset + 1 < len(s) |
|
|||
595 | and s[offset + 1:offset + 2] == '"'): |
|
|||
596 | offset += 1 |
|
|||
597 | parts[-1] += '"' |
|
|||
598 | else: |
|
|||
599 | parts[-1] += s[offset:offset + 1] |
|
|||
600 | offset += 1 |
|
|||
601 |
|
||||
602 | if offset >= len(s): |
|
|||
603 | real_parts = _configlist(parts[-1]) |
|
|||
604 | if not real_parts: |
|
|||
605 | parts[-1] = '"' |
|
|||
606 | else: |
|
|||
607 | real_parts[0] = '"' + real_parts[0] |
|
|||
608 | parts = parts[:-1] |
|
|||
609 | parts.extend(real_parts) |
|
|||
610 | return None, parts, offset |
|
|||
611 |
|
||||
612 | offset += 1 |
|
|||
613 | while offset < len(s) and s[offset:offset + 1] in [' ', ',']: |
|
|||
614 | offset += 1 |
|
|||
615 |
|
||||
616 | if offset < len(s): |
|
|||
617 | if offset + 1 == len(s) and s[offset:offset + 1] == '"': |
|
|||
618 | parts[-1] += '"' |
|
|||
619 | offset += 1 |
|
|||
620 | else: |
|
|||
621 | parts.append('') |
|
|||
622 | else: |
|
|||
623 | return None, parts, offset |
|
|||
624 |
|
||||
625 | return _parse_plain, parts, offset |
|
|||
626 |
|
||||
627 | def _configlist(s): |
|
|||
628 | s = s.rstrip(' ,') |
|
|||
629 | if not s: |
|
|||
630 | return [] |
|
|||
631 | parser, parts, offset = _parse_plain, [''], 0 |
|
|||
632 | while parser: |
|
|||
633 | parser, parts, offset = parser(parts, s, offset) |
|
|||
634 | return parts |
|
|||
635 |
|
||||
636 | result = self.config(section, name, untrusted=untrusted) |
|
|||
637 | if result is None: |
|
|||
638 | result = default or [] |
|
|||
639 | if isinstance(result, bytes): |
|
|||
640 | result = _configlist(result.lstrip(' ,\n')) |
|
|||
641 | if result is None: |
|
|||
642 | result = default or [] |
|
|||
643 | return result |
|
|||
644 |
|
570 | |||
645 | def hasconfig(self, section, name, untrusted=False): |
|
571 | def hasconfig(self, section, name, untrusted=False): | |
646 | return self._data(untrusted).hasitem(section, name) |
|
572 | return self._data(untrusted).hasitem(section, name) |
@@ -23,6 +23,7 def testmod(name, optionflags=0, testtar | |||||
23 |
|
23 | |||
24 | testmod('mercurial.changegroup') |
|
24 | testmod('mercurial.changegroup') | |
25 | testmod('mercurial.changelog') |
|
25 | testmod('mercurial.changelog') | |
|
26 | testmod('mercurial.config') | |||
26 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) |
|
27 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) | |
27 | testmod('mercurial.dispatch') |
|
28 | testmod('mercurial.dispatch') | |
28 | testmod('mercurial.encoding') |
|
29 | testmod('mercurial.encoding') |
General Comments 0
You need to be logged in to leave comments.
Login now