@@ -8,7 +8,7 @@
from core.util import log
def LooksLikeGlob ():
def LooksLikeGlob (s ):
"""
TODO : Reference lib/glob / glob_pattern functions in bash
grep glob_pattern lib/glob/*
@@ -21,7 +21,21 @@ def LooksLikeGlob():
Still need this for slow path / fast path of prefix/suffix/patsub ops.
"""
pass
left_bracket = False
i = 0
n = len (s)
while i < n:
c = s[i]
if c == ' \\ ' :
i += 1
elif c == ' *' or c == ' ?' :
return True
elif c == ' [' :
left_bracket = True
elif c == ' ]' and left_bracket:
return True
i += 1
return False
# Glob Helpers for WordParts.
@@ -41,10 +55,15 @@ def GlobEscape(s):
return escaped
# TODO : Can probably get rid of this, as long as you save the original word.
def _GlobUnescape (s ): # used by cmd_exec
"""
If there is no glob match, just unescape the string.
""" Remove glob escaping from a string.
Used when there is no glob match.
TODO : Can probably get rid of this, as long as you save the original word.
Complicated example: 'a*b'*.py, which will be escaped to a\*b*.py. So in
word_eval _JoinElideEscape and EvalWordToString you have to build two
'parallel' strings -- one escaped and one not.
"""
unescaped = ' '
i = 0
@@ -67,52 +86,52 @@ def _GlobUnescape(s): # used by cmd_exec
class Globber :
def __init__ (self , exec_opts ):
# TODO : separate into set_opts.glob_opts, and sh_opts.glob_opts? Only if
# other shels use the same options as bash though.
self .exec_opts = exec_opts
# NOTE : Bash also respects the GLOBIGNORE variable, but no other shells do.
# Could a default GLOBIGNORE to ignore flags on the file system be part of
# the security solution? It doesn't seem totally sound.
self .noglob = False # set -f
# NOTE : Bash also respects the GLOBIGNORE variable, but no other shells
# do. Could a default GLOBIGNORE to ignore flags on the file system be
# part of the security solution? It doesn't seem totally sound.
# shopt: why the difference? No command line switch I guess.
self .dotglob = False # dotfiles are matched
self .failglob = False # no matches is an error
self .globstar = False # ** for directories
# globasciiranges - ascii or unicode char classes (unicode by default)
# nocaseglob
self .nullglob = False # no matches evaluates to empty, otherwise
# extglob: the !() syntax
# TODO : Figure out which ones are in other shells, and only support those?
# - Include globstar since I use it, and zsh has it.
def Expand (self , arg ):
# TODO : Only try to glob if there are any glob metacharacters.
# Or maybe it is a conservative "avoid glob" heuristic?
#
# Non-glob but with glob characters:
# echo ][
# echo [] # empty
# echo []LICENSE # empty
# echo [L]ICENSE # this one is good
# So yeah you need to test the validity somehow.
""" Given a string that could be a glob, return a list of strings."""
# e.g. don't glob 'echo' because it doesn't look like a glob
if not LooksLikeGlob(arg):
u = _GlobUnescape(arg)
return [u]
if self .exec_opts.noglob:
return [arg]
try :
# g = glob.glob(arg) # Bad Python glob
# PROBLEM: / is significant and can't be escaped! Hav eto avoid globbing it.
# PROBLEM: / is significant and can't be escaped! Have to avoid
# globbing it.
g = libc.glob(arg)
except Exception as e:
# - [C\-D] is invalid in Python? Regex compilation error.
# - [:punct:] not supported
print (" Error expanding glob %r : %s " % (arg, e))
raise
# print('G ', arg, g)
# log('glob %r -> %r ', arg, g)
# log('Globbing %s', arg)
if g:
return g
else :
u = _GlobUnescape(arg)
return [u]
else : # Nothing matched
if self .exec_opts.failglob:
# TODO : Make the command return status 1.
raise NotImplementedError
if self .exec_opts.nullglob:
return []
else :
# Return the original string
u = _GlobUnescape(arg)
return [u]
0 comments on commit
2b43fd5