]> arthur.barton.de Git - bup.git/blob - lib/bup/shquote.py
Merge branch 'bloom'
[bup.git] / lib / bup / shquote.py
1 import re
2
3 q = "'"
4 qq = '"'
5
6
7 class QuoteError(Exception):
8     pass
9
10
11 def _quotesplit(line):
12     inquote = None
13     inescape = None
14     wordstart = 0
15     word = ''
16     for i in range(len(line)):
17         c = line[i]
18         if inescape:
19             if inquote == q and c != q:
20                 word += '\\'  # single-q backslashes can only quote single-q
21             word += c
22             inescape = False
23         elif c == '\\':
24             inescape = True
25         elif c == inquote:
26             inquote = None
27             # this is un-sh-like, but do it for sanity when autocompleting
28             yield (wordstart, word)
29             word = ''
30             wordstart = i+1
31         elif not inquote and not word and (c == q or c == qq):
32             # the 'not word' constraint on this is un-sh-like, but do it
33             # for sanity when autocompleting
34             inquote = c
35             wordstart = i
36         elif not inquote and c in [' ', '\n', '\r', '\t']:
37             if word:
38                 yield (wordstart, word)
39             word = ''
40             wordstart = i+1
41         else:
42             word += c
43     if word:
44         yield (wordstart, word)
45     if inquote or inescape or word:
46         raise QuoteError()
47
48
49 def quotesplit(line):
50     l = []
51     try:
52         for i in _quotesplit(line):
53             l.append(i)
54     except QuoteError:
55         pass
56     return l
57
58
59 def unfinished_word(line):
60     try:
61         for (wordstart,word) in _quotesplit(line):
62             pass
63     except QuoteError:
64         firstchar = line[wordstart]
65         if firstchar in [q, qq]:
66             return (firstchar, word)
67         else:
68             return (None, word)
69     else:
70         return (None, '')
71
72
73 def quotify(qtype, word, terminate):
74     if qtype == qq:
75         return qq + word.replace(qq, '\\"') + (terminate and qq or '')
76     elif qtype == q:
77         return q + word.replace(q, "\\'") + (terminate and q or '')
78     else:
79         return re.sub(r'([\"\' \t\n\r])', r'\\\1', word)
80
81
82 def what_to_add(qtype, origword, newword, terminate):
83     if not newword.startswith(origword):
84         return ''
85     else:
86         qold = quotify(qtype, origword, terminate=False)
87         return quotify(qtype, newword, terminate=terminate)[len(qold):]