12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#!/usr/bin/env python
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import re
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def quote(input_str, specials, escape='\\'):
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Returns a quoted version of |str|, where every character in the
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  iterable |specials| (usually a set or a string) and the escape
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  character |escape| is replaced by the original character preceded by
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  the escape character."""
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  assert len(escape) == 1
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # Since escape is used in replacement pattern context, so we need to
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # ensure that it stays a simple literal and cannot affect the \1
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  # that will follow it.
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if escape == '\\':
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    escape = '\\\\'
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if len(specials) > 0:
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return re.sub(r'(' + r'|'.join(specials)+r'|'+escape + r')',
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  escape + r'\1', input_str)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return re.sub(r'(' + escape + r')', escape + r'\1', input_str)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def unquote(input_str, specials, escape='\\'):
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """Splits the input string |input_str| where special characters in
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  the input |specials| are, if not quoted by |escape|, used as
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delimiters to split the string.  The returned value is a list of
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  strings of alternating non-specials and specials used to break the
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string. The list will always begin with a possibly empty string of
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  non-specials, but may end with either specials or non-specials."""
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  assert len(escape) == 1
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out = []
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cur_out = []
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cur_special = False
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  lit_next = False
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for c in input_str:
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if cur_special:
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      lit_next = (c == escape)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if c not in specials or lit_next:
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cur_special = False
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        out.append(''.join(cur_out))
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if not lit_next:
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          cur_out = [c]
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else:
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          cur_out = []
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cur_out.append(c)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if lit_next:
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        cur_out.append(c)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lit_next = False
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lit_next = c == escape
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if c not in specials:
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if not lit_next:
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            cur_out.append(c)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        else:
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          out.append(''.join(cur_out))
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          cur_out = [c]
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          cur_special = True
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out.append(''.join(cur_out))
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return out
68