~ubuntu-branches/ubuntu/hardy/gnue-common/hardy

« back to all changes in this revision

Viewing changes to src/external/shellwords.py

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Mitchell
  • Date: 2005-03-09 11:06:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050309110631-8gvvn39q7tjz1kj6
Tags: upstream-0.5.14
ImportĀ upstreamĀ versionĀ 0.5.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""shellwords.py
 
2
 
 
3
Parse a string into words like a (POSIX) shell does.
 
4
 
 
5
License: Python Software Foundation License
 
6
         http://www.opensource.org/licenses/PythonSoftFoundation.html
 
7
 
 
8
This module parses a string into words according to the parings-rules
 
9
of a POSIX shell. These parsing rules are (quoted after 'man bash'):
 
10
 
 
11
1) Words are split at whitespace charakters; these are Space, Tab,
 
12
   Newline, Carriage-Return, Vertival-Tab (0B) and Form-Feet (0C).
 
13
 
 
14
   NB: Quotes do _not_ separate words! Thus
 
15
        "My"Fancy"Computer"
 
16
   will be parsed into a single word:
 
17
        MyFancyComputer
 
18
 
 
19
2) A non-quoted backslash (\) is the escape character. It preserves
 
20
   the literal value of the next character that follows.
 
21
 
 
22
3) Enclosing characters in single quotes preserves the literal value
 
23
   of each character within the quotes. A single quote may not occur
 
24
   between single quotes, even when preceded by a backslash.
 
25
 
 
26
   This means: baskslash (\) has no special meaning within single
 
27
   quotes. All charakters within single quotes are taken as-is.
 
28
 
 
29
4) Enclosing characters in double quotes preserves the literal value
 
30
   of all characters within the quotes, with the exception of \. The
 
31
   backslash retains its special meaning only when followed " or \. A
 
32
   double quote may be quoted within double quotes by preceding it
 
33
   with a backslash.
 
34
 
 
35
http://www.crazy-compilers.com/py-lib/#shellwords
 
36
 
 
37
""" # " emacs happy
 
38
 
 
39
__author__ = "Hartmut Goebel <h.goebel@crazy-compilers.com>"
 
40
__version__ = "0.2"
 
41
__copyright__ = "(C) Copyright 2002 by Hartmut Goebel"
 
42
__license__ = "Python Software Foundation License"
 
43
__url__ = 'http://www.crazy-compilers.com/py-lib/#shellwords'
 
44
 
 
45
 
 
46
from types import ListType, TupleType
 
47
import re
 
48
 
 
49
__all__ = ['shellwords', 'EOFError', 'UnmatchedQuoteError',
 
50
           'UnmatchedSingleQuoteError', 'UnmatchedDoubleQuoteError']
 
51
 
 
52
## Semantics:
 
53
## w/o   quotes: \ escapes everything
 
54
## w/i d-quotes: \ escapes only q-quotes and back-slash
 
55
## w/i s-quotes: no escaping is done at all
 
56
 
 
57
re_dquote  = re.compile(r'"(([^"\\]|\\.)*)"')
 
58
re_squote  = re.compile(r"'(.*?)'")
 
59
re_escaped = re.compile(r'\\(.)')
 
60
re_esc_quote = re.compile(r'\\([\\"])')
 
61
re_outside = re.compile(r"""([^\s\\'"]+)""") # " emacs happy
 
62
 
 
63
 
 
64
class EOFError(ValueError):
 
65
    def __init__(self, line):
 
66
        self.line = line
 
67
class UnmatchedQuoteError(EOFError): pass
 
68
class UnmatchedSingleQuoteError(UnmatchedQuoteError):
 
69
    def __str__(self):
 
70
        return "Unmatched single quote: %s" % self.line
 
71
class UnmatchedDoubleQuoteError(UnmatchedQuoteError):
 
72
    def __str__(self):
 
73
        return "Unmatched double quote: %s" % self.line
 
74
 
 
75
 
 
76
class Arg:
 
77
    """
 
78
    Simple helper class for a string-like type which
 
79
    distinguishs between 'empty' and 'undefined'.
 
80
    """
 
81
    def __init__(self):
 
82
        self.arg = None
 
83
 
 
84
    def __ne__(self, other): return self.arg != other
 
85
    #def __eq__(self, other): return self.arg == other  # unused
 
86
    #def __repr__(self):      return repr(self.arg)     # unused
 
87
    def __str__(self):       return str(self.arg)
 
88
 
 
89
    def append(self, text):
 
90
        if self.arg is None: self.arg = text
 
91
        else:                self.arg += text
 
92
        
 
93
 
 
94
def shellwords(line):
 
95
    arg_list = []
 
96
    i = 0; start = 0; arg = Arg()
 
97
    while i < len(line):
 
98
        c = line[i]
 
99
        if c == '"': # handle double quote:
 
100
            match = re_dquote.match(line, i)
 
101
            if not match:
 
102
                raise UnmatchedDoubleQuoteError(line)
 
103
            i = match.end()
 
104
            snippet = match.group(1)
 
105
            arg.append( re_esc_quote.sub(r'\1', snippet))
 
106
 
 
107
        elif c == "'": # handle single quote:
 
108
            match = re_squote.match(line, i)
 
109
            if not match:
 
110
                raise UnmatchedSingleQuoteError(line)
 
111
            i = match.end()
 
112
            arg.append(match.group(1))
 
113
            # there is _no_ escape-charakter within single quotes!
 
114
 
 
115
        elif c == "\\": # handle backslash = escape-charakter
 
116
            match = re_escaped.match(line, i)
 
117
            if not match:
 
118
                raise EOFError(line)
 
119
            i = match.end()
 
120
            arg.append(match.group(1))
 
121
 
 
122
        elif c.isspace(): # handle whitespace
 
123
            if arg != None:
 
124
                arg_list.append(str(arg))
 
125
            arg = Arg()
 
126
            while i < len(line) and line[i].isspace():
 
127
                i += 1
 
128
        else:
 
129
            match = re_outside.match(line, i)
 
130
            assert match
 
131
            i = match.end()
 
132
            arg.append(match.group())
 
133
 
 
134
    if arg != None: arg_list.append(str(arg))
 
135
 
 
136
    return arg_list