/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/cmdline.py

  • Committer: Robert Collins
  • Date: 2010-07-04 06:22:11 UTC
  • mto: This revision was merged to the branch mainline in revision 5332.
  • Revision ID: robertc@robertcollins.net-20100704062211-tk9hw6bnsn5x47fm
``bzrlib.lsprof.profile`` will no longer silently generate bad threaded
profiles when concurrent profile requests are made. Instead the profile
requests will be serialised. Reentrant requests will now deadlock.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Unicode-compatible command-line splitter for all platforms."""
 
18
 
 
19
import re
 
20
 
 
21
 
 
22
_whitespace_match = re.compile(u'\s', re.UNICODE).match
 
23
 
 
24
 
 
25
class _PushbackSequence(object):
 
26
    def __init__(self, orig):
 
27
        self._iter = iter(orig)
 
28
        self._pushback_buffer = []
 
29
 
 
30
    def next(self):
 
31
        if len(self._pushback_buffer) > 0:
 
32
            return self._pushback_buffer.pop()
 
33
        else:
 
34
            return self._iter.next()
 
35
 
 
36
    def pushback(self, char):
 
37
        self._pushback_buffer.append(char)
 
38
 
 
39
    def __iter__(self):
 
40
        return self
 
41
 
 
42
 
 
43
class _Whitespace(object):
 
44
    def process(self, next_char, context):
 
45
        if _whitespace_match(next_char):
 
46
            if len(context.token) > 0:
 
47
                return None
 
48
            else:
 
49
                return self
 
50
        elif next_char in context.allowed_quote_chars:
 
51
            context.quoted = True
 
52
            return _Quotes(next_char, self)
 
53
        elif next_char == u'\\':
 
54
            return _Backslash(self)
 
55
        else:
 
56
            context.token.append(next_char)
 
57
            return _Word()
 
58
 
 
59
 
 
60
class _Quotes(object):
 
61
    def __init__(self, quote_char, exit_state):
 
62
        self.quote_char = quote_char
 
63
        self.exit_state = exit_state
 
64
 
 
65
    def process(self, next_char, context):
 
66
        if next_char == u'\\':
 
67
            return _Backslash(self)
 
68
        elif next_char == self.quote_char:
 
69
            return self.exit_state
 
70
        else:
 
71
            context.token.append(next_char)
 
72
            return self
 
73
 
 
74
 
 
75
class _Backslash(object):
 
76
    # See http://msdn.microsoft.com/en-us/library/bb776391(VS.85).aspx
 
77
    def __init__(self, exit_state):
 
78
        self.exit_state = exit_state
 
79
        self.count = 1
 
80
 
 
81
    def process(self, next_char, context):
 
82
        if next_char == u'\\':
 
83
            self.count += 1
 
84
            return self
 
85
        elif next_char in context.allowed_quote_chars:
 
86
            # 2N backslashes followed by a quote are N backslashes
 
87
            context.token.append(u'\\' * (self.count/2))
 
88
            # 2N+1 backslashes follwed by a quote are N backslashes followed by
 
89
            # the quote which should not be processed as the start or end of
 
90
            # the quoted arg
 
91
            if self.count % 2 == 1:
 
92
                # odd number of \ escapes the quote
 
93
                context.token.append(next_char)
 
94
            else:
 
95
                # let exit_state handle next_char
 
96
                context.seq.pushback(next_char)
 
97
            self.count = 0
 
98
            return self.exit_state
 
99
        else:
 
100
            # N backslashes not followed by a quote are just N backslashes
 
101
            if self.count > 0:
 
102
                context.token.append(u'\\' * self.count)
 
103
                self.count = 0
 
104
            # let exit_state handle next_char
 
105
            context.seq.pushback(next_char)
 
106
            return self.exit_state
 
107
 
 
108
    def finish(self, context):
 
109
        if self.count > 0:
 
110
            context.token.append(u'\\' * self.count)
 
111
 
 
112
 
 
113
class _Word(object):
 
114
    def process(self, next_char, context):
 
115
        if _whitespace_match(next_char):
 
116
            return None
 
117
        elif next_char in context.allowed_quote_chars:
 
118
            return _Quotes(next_char, self)
 
119
        elif next_char == u'\\':
 
120
            return _Backslash(self)
 
121
        else:
 
122
            context.token.append(next_char)
 
123
            return self
 
124
 
 
125
 
 
126
class Splitter(object):
 
127
    def __init__(self, command_line, single_quotes_allowed):
 
128
        self.seq = _PushbackSequence(command_line)
 
129
        self.allowed_quote_chars = u'"'
 
130
        if single_quotes_allowed:
 
131
            self.allowed_quote_chars += u"'"
 
132
 
 
133
    def __iter__(self):
 
134
        return self
 
135
 
 
136
    def next(self):
 
137
        quoted, token = self._get_token()
 
138
        if token is None:
 
139
            raise StopIteration
 
140
        return quoted, token
 
141
 
 
142
    def _get_token(self):
 
143
        self.quoted = False
 
144
        self.token = []
 
145
        state = _Whitespace()
 
146
        for next_char in self.seq:
 
147
            state = state.process(next_char, self)
 
148
            if state is None:
 
149
                break
 
150
        if not state is None and not getattr(state, 'finish', None) is None:
 
151
            state.finish(self)
 
152
        result = u''.join(self.token)
 
153
        if not self.quoted and result == '':
 
154
            result = None
 
155
        return self.quoted, result
 
156
 
 
157
 
 
158
def split(unsplit, single_quotes_allowed=True):
 
159
    splitter = Splitter(unsplit, single_quotes_allowed=single_quotes_allowed)
 
160
    return [arg for quoted, arg in splitter]