1*cda5da8dSAndroid Build Coastguard Worker"""A lexical analyzer class for simple shell-like syntaxes.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Worker# Module and documentation by Eric S. Raymond, 21 Dec 1998 4*cda5da8dSAndroid Build Coastguard Worker# Input stacking and error message cleanup added by ESR, March 2000 5*cda5da8dSAndroid Build Coastguard Worker# push_source() and pop_source() made explicit by ESR, January 2001. 6*cda5da8dSAndroid Build Coastguard Worker# Posix compliance, split(), string arguments, and 7*cda5da8dSAndroid Build Coastguard Worker# iterator interface by Gustavo Niemeyer, April 2003. 8*cda5da8dSAndroid Build Coastguard Worker# changes to tokenize more like Posix shells by Vinay Sajip, July 2016. 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard Workerimport os 11*cda5da8dSAndroid Build Coastguard Workerimport re 12*cda5da8dSAndroid Build Coastguard Workerimport sys 13*cda5da8dSAndroid Build Coastguard Workerfrom collections import deque 14*cda5da8dSAndroid Build Coastguard Worker 15*cda5da8dSAndroid Build Coastguard Workerfrom io import StringIO 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Worker__all__ = ["shlex", "split", "quote", "join"] 18*cda5da8dSAndroid Build Coastguard Worker 19*cda5da8dSAndroid Build Coastguard Workerclass shlex: 20*cda5da8dSAndroid Build Coastguard Worker "A lexical analyzer class for simple shell-like syntaxes." 21*cda5da8dSAndroid Build Coastguard Worker def __init__(self, instream=None, infile=None, posix=False, 22*cda5da8dSAndroid Build Coastguard Worker punctuation_chars=False): 23*cda5da8dSAndroid Build Coastguard Worker if isinstance(instream, str): 24*cda5da8dSAndroid Build Coastguard Worker instream = StringIO(instream) 25*cda5da8dSAndroid Build Coastguard Worker if instream is not None: 26*cda5da8dSAndroid Build Coastguard Worker self.instream = instream 27*cda5da8dSAndroid Build Coastguard Worker self.infile = infile 28*cda5da8dSAndroid Build Coastguard Worker else: 29*cda5da8dSAndroid Build Coastguard Worker self.instream = sys.stdin 30*cda5da8dSAndroid Build Coastguard Worker self.infile = None 31*cda5da8dSAndroid Build Coastguard Worker self.posix = posix 32*cda5da8dSAndroid Build Coastguard Worker if posix: 33*cda5da8dSAndroid Build Coastguard Worker self.eof = None 34*cda5da8dSAndroid Build Coastguard Worker else: 35*cda5da8dSAndroid Build Coastguard Worker self.eof = '' 36*cda5da8dSAndroid Build Coastguard Worker self.commenters = '#' 37*cda5da8dSAndroid Build Coastguard Worker self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' 38*cda5da8dSAndroid Build Coastguard Worker 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_') 39*cda5da8dSAndroid Build Coastguard Worker if self.posix: 40*cda5da8dSAndroid Build Coastguard Worker self.wordchars += ('ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' 41*cda5da8dSAndroid Build Coastguard Worker 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ') 42*cda5da8dSAndroid Build Coastguard Worker self.whitespace = ' \t\r\n' 43*cda5da8dSAndroid Build Coastguard Worker self.whitespace_split = False 44*cda5da8dSAndroid Build Coastguard Worker self.quotes = '\'"' 45*cda5da8dSAndroid Build Coastguard Worker self.escape = '\\' 46*cda5da8dSAndroid Build Coastguard Worker self.escapedquotes = '"' 47*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 48*cda5da8dSAndroid Build Coastguard Worker self.pushback = deque() 49*cda5da8dSAndroid Build Coastguard Worker self.lineno = 1 50*cda5da8dSAndroid Build Coastguard Worker self.debug = 0 51*cda5da8dSAndroid Build Coastguard Worker self.token = '' 52*cda5da8dSAndroid Build Coastguard Worker self.filestack = deque() 53*cda5da8dSAndroid Build Coastguard Worker self.source = None 54*cda5da8dSAndroid Build Coastguard Worker if not punctuation_chars: 55*cda5da8dSAndroid Build Coastguard Worker punctuation_chars = '' 56*cda5da8dSAndroid Build Coastguard Worker elif punctuation_chars is True: 57*cda5da8dSAndroid Build Coastguard Worker punctuation_chars = '();<>|&' 58*cda5da8dSAndroid Build Coastguard Worker self._punctuation_chars = punctuation_chars 59*cda5da8dSAndroid Build Coastguard Worker if punctuation_chars: 60*cda5da8dSAndroid Build Coastguard Worker # _pushback_chars is a push back queue used by lookahead logic 61*cda5da8dSAndroid Build Coastguard Worker self._pushback_chars = deque() 62*cda5da8dSAndroid Build Coastguard Worker # these chars added because allowed in file names, args, wildcards 63*cda5da8dSAndroid Build Coastguard Worker self.wordchars += '~-./*?=' 64*cda5da8dSAndroid Build Coastguard Worker #remove any punctuation chars from wordchars 65*cda5da8dSAndroid Build Coastguard Worker t = self.wordchars.maketrans(dict.fromkeys(punctuation_chars)) 66*cda5da8dSAndroid Build Coastguard Worker self.wordchars = self.wordchars.translate(t) 67*cda5da8dSAndroid Build Coastguard Worker 68*cda5da8dSAndroid Build Coastguard Worker @property 69*cda5da8dSAndroid Build Coastguard Worker def punctuation_chars(self): 70*cda5da8dSAndroid Build Coastguard Worker return self._punctuation_chars 71*cda5da8dSAndroid Build Coastguard Worker 72*cda5da8dSAndroid Build Coastguard Worker def push_token(self, tok): 73*cda5da8dSAndroid Build Coastguard Worker "Push a token onto the stack popped by the get_token method" 74*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 1: 75*cda5da8dSAndroid Build Coastguard Worker print("shlex: pushing token " + repr(tok)) 76*cda5da8dSAndroid Build Coastguard Worker self.pushback.appendleft(tok) 77*cda5da8dSAndroid Build Coastguard Worker 78*cda5da8dSAndroid Build Coastguard Worker def push_source(self, newstream, newfile=None): 79*cda5da8dSAndroid Build Coastguard Worker "Push an input source onto the lexer's input source stack." 80*cda5da8dSAndroid Build Coastguard Worker if isinstance(newstream, str): 81*cda5da8dSAndroid Build Coastguard Worker newstream = StringIO(newstream) 82*cda5da8dSAndroid Build Coastguard Worker self.filestack.appendleft((self.infile, self.instream, self.lineno)) 83*cda5da8dSAndroid Build Coastguard Worker self.infile = newfile 84*cda5da8dSAndroid Build Coastguard Worker self.instream = newstream 85*cda5da8dSAndroid Build Coastguard Worker self.lineno = 1 86*cda5da8dSAndroid Build Coastguard Worker if self.debug: 87*cda5da8dSAndroid Build Coastguard Worker if newfile is not None: 88*cda5da8dSAndroid Build Coastguard Worker print('shlex: pushing to file %s' % (self.infile,)) 89*cda5da8dSAndroid Build Coastguard Worker else: 90*cda5da8dSAndroid Build Coastguard Worker print('shlex: pushing to stream %s' % (self.instream,)) 91*cda5da8dSAndroid Build Coastguard Worker 92*cda5da8dSAndroid Build Coastguard Worker def pop_source(self): 93*cda5da8dSAndroid Build Coastguard Worker "Pop the input source stack." 94*cda5da8dSAndroid Build Coastguard Worker self.instream.close() 95*cda5da8dSAndroid Build Coastguard Worker (self.infile, self.instream, self.lineno) = self.filestack.popleft() 96*cda5da8dSAndroid Build Coastguard Worker if self.debug: 97*cda5da8dSAndroid Build Coastguard Worker print('shlex: popping to %s, line %d' \ 98*cda5da8dSAndroid Build Coastguard Worker % (self.instream, self.lineno)) 99*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 100*cda5da8dSAndroid Build Coastguard Worker 101*cda5da8dSAndroid Build Coastguard Worker def get_token(self): 102*cda5da8dSAndroid Build Coastguard Worker "Get a token from the input stream (or from stack if it's nonempty)" 103*cda5da8dSAndroid Build Coastguard Worker if self.pushback: 104*cda5da8dSAndroid Build Coastguard Worker tok = self.pushback.popleft() 105*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 1: 106*cda5da8dSAndroid Build Coastguard Worker print("shlex: popping token " + repr(tok)) 107*cda5da8dSAndroid Build Coastguard Worker return tok 108*cda5da8dSAndroid Build Coastguard Worker # No pushback. Get a token. 109*cda5da8dSAndroid Build Coastguard Worker raw = self.read_token() 110*cda5da8dSAndroid Build Coastguard Worker # Handle inclusions 111*cda5da8dSAndroid Build Coastguard Worker if self.source is not None: 112*cda5da8dSAndroid Build Coastguard Worker while raw == self.source: 113*cda5da8dSAndroid Build Coastguard Worker spec = self.sourcehook(self.read_token()) 114*cda5da8dSAndroid Build Coastguard Worker if spec: 115*cda5da8dSAndroid Build Coastguard Worker (newfile, newstream) = spec 116*cda5da8dSAndroid Build Coastguard Worker self.push_source(newstream, newfile) 117*cda5da8dSAndroid Build Coastguard Worker raw = self.get_token() 118*cda5da8dSAndroid Build Coastguard Worker # Maybe we got EOF instead? 119*cda5da8dSAndroid Build Coastguard Worker while raw == self.eof: 120*cda5da8dSAndroid Build Coastguard Worker if not self.filestack: 121*cda5da8dSAndroid Build Coastguard Worker return self.eof 122*cda5da8dSAndroid Build Coastguard Worker else: 123*cda5da8dSAndroid Build Coastguard Worker self.pop_source() 124*cda5da8dSAndroid Build Coastguard Worker raw = self.get_token() 125*cda5da8dSAndroid Build Coastguard Worker # Neither inclusion nor EOF 126*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 1: 127*cda5da8dSAndroid Build Coastguard Worker if raw != self.eof: 128*cda5da8dSAndroid Build Coastguard Worker print("shlex: token=" + repr(raw)) 129*cda5da8dSAndroid Build Coastguard Worker else: 130*cda5da8dSAndroid Build Coastguard Worker print("shlex: token=EOF") 131*cda5da8dSAndroid Build Coastguard Worker return raw 132*cda5da8dSAndroid Build Coastguard Worker 133*cda5da8dSAndroid Build Coastguard Worker def read_token(self): 134*cda5da8dSAndroid Build Coastguard Worker quoted = False 135*cda5da8dSAndroid Build Coastguard Worker escapedstate = ' ' 136*cda5da8dSAndroid Build Coastguard Worker while True: 137*cda5da8dSAndroid Build Coastguard Worker if self.punctuation_chars and self._pushback_chars: 138*cda5da8dSAndroid Build Coastguard Worker nextchar = self._pushback_chars.pop() 139*cda5da8dSAndroid Build Coastguard Worker else: 140*cda5da8dSAndroid Build Coastguard Worker nextchar = self.instream.read(1) 141*cda5da8dSAndroid Build Coastguard Worker if nextchar == '\n': 142*cda5da8dSAndroid Build Coastguard Worker self.lineno += 1 143*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 3: 144*cda5da8dSAndroid Build Coastguard Worker print("shlex: in state %r I see character: %r" % (self.state, 145*cda5da8dSAndroid Build Coastguard Worker nextchar)) 146*cda5da8dSAndroid Build Coastguard Worker if self.state is None: 147*cda5da8dSAndroid Build Coastguard Worker self.token = '' # past end of file 148*cda5da8dSAndroid Build Coastguard Worker break 149*cda5da8dSAndroid Build Coastguard Worker elif self.state == ' ': 150*cda5da8dSAndroid Build Coastguard Worker if not nextchar: 151*cda5da8dSAndroid Build Coastguard Worker self.state = None # end of file 152*cda5da8dSAndroid Build Coastguard Worker break 153*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.whitespace: 154*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 2: 155*cda5da8dSAndroid Build Coastguard Worker print("shlex: I see whitespace in whitespace state") 156*cda5da8dSAndroid Build Coastguard Worker if self.token or (self.posix and quoted): 157*cda5da8dSAndroid Build Coastguard Worker break # emit current token 158*cda5da8dSAndroid Build Coastguard Worker else: 159*cda5da8dSAndroid Build Coastguard Worker continue 160*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.commenters: 161*cda5da8dSAndroid Build Coastguard Worker self.instream.readline() 162*cda5da8dSAndroid Build Coastguard Worker self.lineno += 1 163*cda5da8dSAndroid Build Coastguard Worker elif self.posix and nextchar in self.escape: 164*cda5da8dSAndroid Build Coastguard Worker escapedstate = 'a' 165*cda5da8dSAndroid Build Coastguard Worker self.state = nextchar 166*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.wordchars: 167*cda5da8dSAndroid Build Coastguard Worker self.token = nextchar 168*cda5da8dSAndroid Build Coastguard Worker self.state = 'a' 169*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.punctuation_chars: 170*cda5da8dSAndroid Build Coastguard Worker self.token = nextchar 171*cda5da8dSAndroid Build Coastguard Worker self.state = 'c' 172*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.quotes: 173*cda5da8dSAndroid Build Coastguard Worker if not self.posix: 174*cda5da8dSAndroid Build Coastguard Worker self.token = nextchar 175*cda5da8dSAndroid Build Coastguard Worker self.state = nextchar 176*cda5da8dSAndroid Build Coastguard Worker elif self.whitespace_split: 177*cda5da8dSAndroid Build Coastguard Worker self.token = nextchar 178*cda5da8dSAndroid Build Coastguard Worker self.state = 'a' 179*cda5da8dSAndroid Build Coastguard Worker else: 180*cda5da8dSAndroid Build Coastguard Worker self.token = nextchar 181*cda5da8dSAndroid Build Coastguard Worker if self.token or (self.posix and quoted): 182*cda5da8dSAndroid Build Coastguard Worker break # emit current token 183*cda5da8dSAndroid Build Coastguard Worker else: 184*cda5da8dSAndroid Build Coastguard Worker continue 185*cda5da8dSAndroid Build Coastguard Worker elif self.state in self.quotes: 186*cda5da8dSAndroid Build Coastguard Worker quoted = True 187*cda5da8dSAndroid Build Coastguard Worker if not nextchar: # end of file 188*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 2: 189*cda5da8dSAndroid Build Coastguard Worker print("shlex: I see EOF in quotes state") 190*cda5da8dSAndroid Build Coastguard Worker # XXX what error should be raised here? 191*cda5da8dSAndroid Build Coastguard Worker raise ValueError("No closing quotation") 192*cda5da8dSAndroid Build Coastguard Worker if nextchar == self.state: 193*cda5da8dSAndroid Build Coastguard Worker if not self.posix: 194*cda5da8dSAndroid Build Coastguard Worker self.token += nextchar 195*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 196*cda5da8dSAndroid Build Coastguard Worker break 197*cda5da8dSAndroid Build Coastguard Worker else: 198*cda5da8dSAndroid Build Coastguard Worker self.state = 'a' 199*cda5da8dSAndroid Build Coastguard Worker elif (self.posix and nextchar in self.escape and self.state 200*cda5da8dSAndroid Build Coastguard Worker in self.escapedquotes): 201*cda5da8dSAndroid Build Coastguard Worker escapedstate = self.state 202*cda5da8dSAndroid Build Coastguard Worker self.state = nextchar 203*cda5da8dSAndroid Build Coastguard Worker else: 204*cda5da8dSAndroid Build Coastguard Worker self.token += nextchar 205*cda5da8dSAndroid Build Coastguard Worker elif self.state in self.escape: 206*cda5da8dSAndroid Build Coastguard Worker if not nextchar: # end of file 207*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 2: 208*cda5da8dSAndroid Build Coastguard Worker print("shlex: I see EOF in escape state") 209*cda5da8dSAndroid Build Coastguard Worker # XXX what error should be raised here? 210*cda5da8dSAndroid Build Coastguard Worker raise ValueError("No escaped character") 211*cda5da8dSAndroid Build Coastguard Worker # In posix shells, only the quote itself or the escape 212*cda5da8dSAndroid Build Coastguard Worker # character may be escaped within quotes. 213*cda5da8dSAndroid Build Coastguard Worker if (escapedstate in self.quotes and 214*cda5da8dSAndroid Build Coastguard Worker nextchar != self.state and nextchar != escapedstate): 215*cda5da8dSAndroid Build Coastguard Worker self.token += self.state 216*cda5da8dSAndroid Build Coastguard Worker self.token += nextchar 217*cda5da8dSAndroid Build Coastguard Worker self.state = escapedstate 218*cda5da8dSAndroid Build Coastguard Worker elif self.state in ('a', 'c'): 219*cda5da8dSAndroid Build Coastguard Worker if not nextchar: 220*cda5da8dSAndroid Build Coastguard Worker self.state = None # end of file 221*cda5da8dSAndroid Build Coastguard Worker break 222*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.whitespace: 223*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 2: 224*cda5da8dSAndroid Build Coastguard Worker print("shlex: I see whitespace in word state") 225*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 226*cda5da8dSAndroid Build Coastguard Worker if self.token or (self.posix and quoted): 227*cda5da8dSAndroid Build Coastguard Worker break # emit current token 228*cda5da8dSAndroid Build Coastguard Worker else: 229*cda5da8dSAndroid Build Coastguard Worker continue 230*cda5da8dSAndroid Build Coastguard Worker elif nextchar in self.commenters: 231*cda5da8dSAndroid Build Coastguard Worker self.instream.readline() 232*cda5da8dSAndroid Build Coastguard Worker self.lineno += 1 233*cda5da8dSAndroid Build Coastguard Worker if self.posix: 234*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 235*cda5da8dSAndroid Build Coastguard Worker if self.token or (self.posix and quoted): 236*cda5da8dSAndroid Build Coastguard Worker break # emit current token 237*cda5da8dSAndroid Build Coastguard Worker else: 238*cda5da8dSAndroid Build Coastguard Worker continue 239*cda5da8dSAndroid Build Coastguard Worker elif self.state == 'c': 240*cda5da8dSAndroid Build Coastguard Worker if nextchar in self.punctuation_chars: 241*cda5da8dSAndroid Build Coastguard Worker self.token += nextchar 242*cda5da8dSAndroid Build Coastguard Worker else: 243*cda5da8dSAndroid Build Coastguard Worker if nextchar not in self.whitespace: 244*cda5da8dSAndroid Build Coastguard Worker self._pushback_chars.append(nextchar) 245*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 246*cda5da8dSAndroid Build Coastguard Worker break 247*cda5da8dSAndroid Build Coastguard Worker elif self.posix and nextchar in self.quotes: 248*cda5da8dSAndroid Build Coastguard Worker self.state = nextchar 249*cda5da8dSAndroid Build Coastguard Worker elif self.posix and nextchar in self.escape: 250*cda5da8dSAndroid Build Coastguard Worker escapedstate = 'a' 251*cda5da8dSAndroid Build Coastguard Worker self.state = nextchar 252*cda5da8dSAndroid Build Coastguard Worker elif (nextchar in self.wordchars or nextchar in self.quotes 253*cda5da8dSAndroid Build Coastguard Worker or (self.whitespace_split and 254*cda5da8dSAndroid Build Coastguard Worker nextchar not in self.punctuation_chars)): 255*cda5da8dSAndroid Build Coastguard Worker self.token += nextchar 256*cda5da8dSAndroid Build Coastguard Worker else: 257*cda5da8dSAndroid Build Coastguard Worker if self.punctuation_chars: 258*cda5da8dSAndroid Build Coastguard Worker self._pushback_chars.append(nextchar) 259*cda5da8dSAndroid Build Coastguard Worker else: 260*cda5da8dSAndroid Build Coastguard Worker self.pushback.appendleft(nextchar) 261*cda5da8dSAndroid Build Coastguard Worker if self.debug >= 2: 262*cda5da8dSAndroid Build Coastguard Worker print("shlex: I see punctuation in word state") 263*cda5da8dSAndroid Build Coastguard Worker self.state = ' ' 264*cda5da8dSAndroid Build Coastguard Worker if self.token or (self.posix and quoted): 265*cda5da8dSAndroid Build Coastguard Worker break # emit current token 266*cda5da8dSAndroid Build Coastguard Worker else: 267*cda5da8dSAndroid Build Coastguard Worker continue 268*cda5da8dSAndroid Build Coastguard Worker result = self.token 269*cda5da8dSAndroid Build Coastguard Worker self.token = '' 270*cda5da8dSAndroid Build Coastguard Worker if self.posix and not quoted and result == '': 271*cda5da8dSAndroid Build Coastguard Worker result = None 272*cda5da8dSAndroid Build Coastguard Worker if self.debug > 1: 273*cda5da8dSAndroid Build Coastguard Worker if result: 274*cda5da8dSAndroid Build Coastguard Worker print("shlex: raw token=" + repr(result)) 275*cda5da8dSAndroid Build Coastguard Worker else: 276*cda5da8dSAndroid Build Coastguard Worker print("shlex: raw token=EOF") 277*cda5da8dSAndroid Build Coastguard Worker return result 278*cda5da8dSAndroid Build Coastguard Worker 279*cda5da8dSAndroid Build Coastguard Worker def sourcehook(self, newfile): 280*cda5da8dSAndroid Build Coastguard Worker "Hook called on a filename to be sourced." 281*cda5da8dSAndroid Build Coastguard Worker if newfile[0] == '"': 282*cda5da8dSAndroid Build Coastguard Worker newfile = newfile[1:-1] 283*cda5da8dSAndroid Build Coastguard Worker # This implements cpp-like semantics for relative-path inclusion. 284*cda5da8dSAndroid Build Coastguard Worker if isinstance(self.infile, str) and not os.path.isabs(newfile): 285*cda5da8dSAndroid Build Coastguard Worker newfile = os.path.join(os.path.dirname(self.infile), newfile) 286*cda5da8dSAndroid Build Coastguard Worker return (newfile, open(newfile, "r")) 287*cda5da8dSAndroid Build Coastguard Worker 288*cda5da8dSAndroid Build Coastguard Worker def error_leader(self, infile=None, lineno=None): 289*cda5da8dSAndroid Build Coastguard Worker "Emit a C-compiler-like, Emacs-friendly error-message leader." 290*cda5da8dSAndroid Build Coastguard Worker if infile is None: 291*cda5da8dSAndroid Build Coastguard Worker infile = self.infile 292*cda5da8dSAndroid Build Coastguard Worker if lineno is None: 293*cda5da8dSAndroid Build Coastguard Worker lineno = self.lineno 294*cda5da8dSAndroid Build Coastguard Worker return "\"%s\", line %d: " % (infile, lineno) 295*cda5da8dSAndroid Build Coastguard Worker 296*cda5da8dSAndroid Build Coastguard Worker def __iter__(self): 297*cda5da8dSAndroid Build Coastguard Worker return self 298*cda5da8dSAndroid Build Coastguard Worker 299*cda5da8dSAndroid Build Coastguard Worker def __next__(self): 300*cda5da8dSAndroid Build Coastguard Worker token = self.get_token() 301*cda5da8dSAndroid Build Coastguard Worker if token == self.eof: 302*cda5da8dSAndroid Build Coastguard Worker raise StopIteration 303*cda5da8dSAndroid Build Coastguard Worker return token 304*cda5da8dSAndroid Build Coastguard Worker 305*cda5da8dSAndroid Build Coastguard Workerdef split(s, comments=False, posix=True): 306*cda5da8dSAndroid Build Coastguard Worker """Split the string *s* using shell-like syntax.""" 307*cda5da8dSAndroid Build Coastguard Worker if s is None: 308*cda5da8dSAndroid Build Coastguard Worker import warnings 309*cda5da8dSAndroid Build Coastguard Worker warnings.warn("Passing None for 's' to shlex.split() is deprecated.", 310*cda5da8dSAndroid Build Coastguard Worker DeprecationWarning, stacklevel=2) 311*cda5da8dSAndroid Build Coastguard Worker lex = shlex(s, posix=posix) 312*cda5da8dSAndroid Build Coastguard Worker lex.whitespace_split = True 313*cda5da8dSAndroid Build Coastguard Worker if not comments: 314*cda5da8dSAndroid Build Coastguard Worker lex.commenters = '' 315*cda5da8dSAndroid Build Coastguard Worker return list(lex) 316*cda5da8dSAndroid Build Coastguard Worker 317*cda5da8dSAndroid Build Coastguard Worker 318*cda5da8dSAndroid Build Coastguard Workerdef join(split_command): 319*cda5da8dSAndroid Build Coastguard Worker """Return a shell-escaped string from *split_command*.""" 320*cda5da8dSAndroid Build Coastguard Worker return ' '.join(quote(arg) for arg in split_command) 321*cda5da8dSAndroid Build Coastguard Worker 322*cda5da8dSAndroid Build Coastguard Worker 323*cda5da8dSAndroid Build Coastguard Worker_find_unsafe = re.compile(r'[^\w@%+=:,./-]', re.ASCII).search 324*cda5da8dSAndroid Build Coastguard Worker 325*cda5da8dSAndroid Build Coastguard Workerdef quote(s): 326*cda5da8dSAndroid Build Coastguard Worker """Return a shell-escaped version of the string *s*.""" 327*cda5da8dSAndroid Build Coastguard Worker if not s: 328*cda5da8dSAndroid Build Coastguard Worker return "''" 329*cda5da8dSAndroid Build Coastguard Worker if _find_unsafe(s) is None: 330*cda5da8dSAndroid Build Coastguard Worker return s 331*cda5da8dSAndroid Build Coastguard Worker 332*cda5da8dSAndroid Build Coastguard Worker # use single quotes, and put single quotes into double quotes 333*cda5da8dSAndroid Build Coastguard Worker # the string $'b is then quoted as '$'"'"'b' 334*cda5da8dSAndroid Build Coastguard Worker return "'" + s.replace("'", "'\"'\"'") + "'" 335*cda5da8dSAndroid Build Coastguard Worker 336*cda5da8dSAndroid Build Coastguard Worker 337*cda5da8dSAndroid Build Coastguard Workerdef _print_tokens(lexer): 338*cda5da8dSAndroid Build Coastguard Worker while 1: 339*cda5da8dSAndroid Build Coastguard Worker tt = lexer.get_token() 340*cda5da8dSAndroid Build Coastguard Worker if not tt: 341*cda5da8dSAndroid Build Coastguard Worker break 342*cda5da8dSAndroid Build Coastguard Worker print("Token: " + repr(tt)) 343*cda5da8dSAndroid Build Coastguard Worker 344*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__': 345*cda5da8dSAndroid Build Coastguard Worker if len(sys.argv) == 1: 346*cda5da8dSAndroid Build Coastguard Worker _print_tokens(shlex()) 347*cda5da8dSAndroid Build Coastguard Worker else: 348*cda5da8dSAndroid Build Coastguard Worker fn = sys.argv[1] 349*cda5da8dSAndroid Build Coastguard Worker with open(fn) as f: 350*cda5da8dSAndroid Build Coastguard Worker _print_tokens(shlex(f, fn)) 351