/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: Gordon Tyler
  • Date: 2010-02-02 04:37:56 UTC
  • mto: (5037.3.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5046.
  • Revision ID: gordon@doxxx.net-20100202043756-nkub38sw5v80zx7o
Moved UnicodeShlex, etc. to a new module, bzrlib.cmdline, and renamed it to Parser.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
"""Unicode-compatible command-line splitter for all platforms."""
 
17
"""Command-line parser for all platforms."""
18
18
 
19
19
import re
20
20
 
26
26
    def __init__(self, orig):
27
27
        self._iter = iter(orig)
28
28
        self._pushback_buffer = []
29
 
 
 
29
        
30
30
    def next(self):
31
31
        if len(self._pushback_buffer) > 0:
32
32
            return self._pushback_buffer.pop()
33
33
        else:
34
34
            return self._iter.next()
35
 
 
 
35
    
36
36
    def pushback(self, char):
37
37
        self._pushback_buffer.append(char)
38
 
 
 
38
        
39
39
    def __iter__(self):
40
40
        return self
41
41
 
42
42
 
43
43
class _Whitespace(object):
44
 
    def process(self, next_char, context):
 
44
    def process(self, next_char, seq, context):
45
45
        if _whitespace_match(next_char):
46
46
            if len(context.token) > 0:
47
47
                return None
48
48
            else:
49
49
                return self
50
 
        elif next_char in context.allowed_quote_chars:
 
50
        elif (next_char == u'"'
 
51
              or (context.single_quotes_allowed and next_char == u"'")):
51
52
            context.quoted = True
52
53
            return _Quotes(next_char, self)
53
54
        elif next_char == u'\\':
62
63
        self.quote_char = quote_char
63
64
        self.exit_state = exit_state
64
65
 
65
 
    def process(self, next_char, context):
 
66
    def process(self, next_char, seq, context):
66
67
        if next_char == u'\\':
67
68
            return _Backslash(self)
68
69
        elif next_char == self.quote_char:
77
78
    def __init__(self, exit_state):
78
79
        self.exit_state = exit_state
79
80
        self.count = 1
80
 
 
81
 
    def process(self, next_char, context):
 
81
        
 
82
    def process(self, next_char, seq, context):
82
83
        if next_char == u'\\':
83
84
            self.count += 1
84
85
            return self
85
 
        elif next_char in context.allowed_quote_chars:
86
 
            # 2N backslashes followed by a quote are N backslashes
 
86
        elif next_char == u'"':
 
87
            # 2N backslashes followed by '"' are N backslashes
87
88
            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
 
89
            # 2N+1 backslashes follwed by '"' are N backslashes followed by '"'
 
90
            # which should not be processed as the start or end of quoted arg
91
91
            if self.count % 2 == 1:
92
 
                # odd number of \ escapes the quote
93
 
                context.token.append(next_char)
 
92
                context.token.append(next_char) # odd number of '\' escapes the '"'
94
93
            else:
95
 
                # let exit_state handle next_char
96
 
                context.seq.pushback(next_char)
 
94
                seq.pushback(next_char) # let exit_state handle next_char
97
95
            self.count = 0
98
96
            return self.exit_state
99
97
        else:
100
 
            # N backslashes not followed by a quote are just N backslashes
 
98
            # N backslashes not followed by '"' are just N backslashes
101
99
            if self.count > 0:
102
100
                context.token.append(u'\\' * self.count)
103
101
                self.count = 0
104
 
            # let exit_state handle next_char
105
 
            context.seq.pushback(next_char)
 
102
            seq.pushback(next_char) # let exit_state handle next_char
106
103
            return self.exit_state
107
 
 
 
104
    
108
105
    def finish(self, context):
109
106
        if self.count > 0:
110
107
            context.token.append(u'\\' * self.count)
111
108
 
112
109
 
113
110
class _Word(object):
114
 
    def process(self, next_char, context):
 
111
    def process(self, next_char, seq, context):
115
112
        if _whitespace_match(next_char):
116
113
            return None
117
 
        elif next_char in context.allowed_quote_chars:
 
114
        elif (next_char == u'"'
 
115
              or (context.single_quotes_allowed and next_char == u"'")):
118
116
            return _Quotes(next_char, self)
119
117
        elif next_char == u'\\':
120
118
            return _Backslash(self)
123
121
            return self
124
122
 
125
123
 
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
 
 
 
124
class Parser(object):
 
125
    def __init__(self, command_line, single_quotes_allowed=False):
 
126
        self._seq = _PushbackSequence(command_line)
 
127
        self.single_quotes_allowed = single_quotes_allowed
 
128
    
133
129
    def __iter__(self):
134
130
        return self
135
 
 
 
131
    
136
132
    def next(self):
137
133
        quoted, token = self._get_token()
138
134
        if token is None:
139
135
            raise StopIteration
140
136
        return quoted, token
141
 
 
 
137
    
142
138
    def _get_token(self):
143
139
        self.quoted = False
144
140
        self.token = []
145
141
        state = _Whitespace()
146
 
        for next_char in self.seq:
147
 
            state = state.process(next_char, self)
 
142
        for next_char in self._seq:
 
143
            state = state.process(next_char, self._seq, self)
148
144
            if state is None:
149
145
                break
150
146
        if not state is None and not getattr(state, 'finish', None) is None:
153
149
        if not self.quoted and result == '':
154
150
            result = None
155
151
        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]