256 self.new_source() |
256 self.new_source() |
257 |
257 |
258 self.parse( |
258 self.parse( |
259 path, fp.read(), sections=sections, remap=remap, include=include |
259 path, fp.read(), sections=sections, remap=remap, include=include |
260 ) |
260 ) |
261 |
|
262 |
|
263 def parselist(value): |
|
264 """parse a configuration value as a list of comma/space separated strings |
|
265 |
|
266 >>> parselist(b'this,is "a small" ,test') |
|
267 ['this', 'is', 'a small', 'test'] |
|
268 """ |
|
269 |
|
270 def _parse_plain(parts, s, offset): |
|
271 whitespace = False |
|
272 while offset < len(s) and ( |
|
273 s[offset : offset + 1].isspace() or s[offset : offset + 1] == b',' |
|
274 ): |
|
275 whitespace = True |
|
276 offset += 1 |
|
277 if offset >= len(s): |
|
278 return None, parts, offset |
|
279 if whitespace: |
|
280 parts.append(b'') |
|
281 if s[offset : offset + 1] == b'"' and not parts[-1]: |
|
282 return _parse_quote, parts, offset + 1 |
|
283 elif s[offset : offset + 1] == b'"' and parts[-1][-1:] == b'\\': |
|
284 parts[-1] = parts[-1][:-1] + s[offset : offset + 1] |
|
285 return _parse_plain, parts, offset + 1 |
|
286 parts[-1] += s[offset : offset + 1] |
|
287 return _parse_plain, parts, offset + 1 |
|
288 |
|
289 def _parse_quote(parts, s, offset): |
|
290 if offset < len(s) and s[offset : offset + 1] == b'"': # "" |
|
291 parts.append(b'') |
|
292 offset += 1 |
|
293 while offset < len(s) and ( |
|
294 s[offset : offset + 1].isspace() |
|
295 or s[offset : offset + 1] == b',' |
|
296 ): |
|
297 offset += 1 |
|
298 return _parse_plain, parts, offset |
|
299 |
|
300 while offset < len(s) and s[offset : offset + 1] != b'"': |
|
301 if ( |
|
302 s[offset : offset + 1] == b'\\' |
|
303 and offset + 1 < len(s) |
|
304 and s[offset + 1 : offset + 2] == b'"' |
|
305 ): |
|
306 offset += 1 |
|
307 parts[-1] += b'"' |
|
308 else: |
|
309 parts[-1] += s[offset : offset + 1] |
|
310 offset += 1 |
|
311 |
|
312 if offset >= len(s): |
|
313 real_parts = _configlist(parts[-1]) |
|
314 if not real_parts: |
|
315 parts[-1] = b'"' |
|
316 else: |
|
317 real_parts[0] = b'"' + real_parts[0] |
|
318 parts = parts[:-1] |
|
319 parts.extend(real_parts) |
|
320 return None, parts, offset |
|
321 |
|
322 offset += 1 |
|
323 while offset < len(s) and s[offset : offset + 1] in [b' ', b',']: |
|
324 offset += 1 |
|
325 |
|
326 if offset < len(s): |
|
327 if offset + 1 == len(s) and s[offset : offset + 1] == b'"': |
|
328 parts[-1] += b'"' |
|
329 offset += 1 |
|
330 else: |
|
331 parts.append(b'') |
|
332 else: |
|
333 return None, parts, offset |
|
334 |
|
335 return _parse_plain, parts, offset |
|
336 |
|
337 def _configlist(s): |
|
338 s = s.rstrip(b' ,') |
|
339 if not s: |
|
340 return [] |
|
341 parser, parts, offset = _parse_plain, [b''], 0 |
|
342 while parser: |
|
343 parser, parts, offset = parser(parts, s, offset) |
|
344 return parts |
|
345 |
|
346 if value is not None and isinstance(value, bytes): |
|
347 result = _configlist(value.lstrip(b' ,\n')) |
|
348 else: |
|
349 result = value |
|
350 return result or [] |
|