Beispiel #1
0
  def testLooksLikeGlob(self):
    # The way to test bash behavior is:
    #   $ shopt -s nullglob; argv [    # not a glob
    #   $ shopt -s nullglob; argv []   # is a glob
    #   $ shopt -s nullglob; argv [][  # is a glob
    CASES = [
        (r'[]', True),
        (r'[][', True),
        (r'][', False),  # no balanced pair
        (r'\[]', False),  # no balanced pair
        (r'[', False),  # no balanced pair
        (r']', False),  # no balanced pair
        (r'echo', False),
        (r'status=0', False),

        (r'*', True),
        (r'\*', False),
        (r'\*.sh', False),

        ('\\', False),
        ('*\\', True),

        ('?', True),
    ]
    for pat, expected in CASES:
      self.assertEqual(expected, glob_.LooksLikeGlob(pat),
                       '%s: expected %r' % (pat, expected))
Beispiel #2
0
def DoUnarySuffixOp(s, op, arg):
    """Helper for ${x#prefix} and family."""

    # Fast path for constant strings.
    if not glob_.LooksLikeGlob(arg):
        if op.op_id in (Id.VOp1_Pound, Id.VOp1_DPound):  # const prefix
            if s.startswith(arg):
                return s[len(arg):]
            else:
                return s

        elif op.op_id in (Id.VOp1_Percent, Id.VOp1_DPercent):  # const suffix
            if s.endswith(arg):
                # Mutate it so we preserve the flags.
                return s[:-len(arg)]
            else:
                return s

        else:  # e.g. ^ ^^ , ,,
            raise AssertionError(op.op_id)

    # For patterns, do fnmatch() in a loop.
    #
    # TODO: Check another fast path first?
    #
    # v=aabbccdd
    # echo ${v#*b}  # strip shortest prefix
    #
    # If the whole thing doesn't match '*b*', then no test can succeed.  So we
    # can fail early.  Conversely echo ${v%%c*} and '*c*'.

    n = len(s)
    if op.op_id == Id.VOp1_Pound:  # shortest prefix
        # 'abcd': match 'a', 'ab', 'abc', ...
        for i in xrange(1, n + 1):
            #log('Matching pattern %r with %r', arg, s[:i])
            if libc.fnmatch(arg, s[:i]):
                return s[i:]
        else:
            return s

    elif op.op_id == Id.VOp1_DPound:  # longest prefix
        # 'abcd': match 'abc', 'ab', 'a'
        for i in xrange(n, 0, -1):
            #log('Matching pattern %r with %r', arg, s[:i])
            if libc.fnmatch(arg, s[:i]):
                return s[i:]
        else:
            return s

    elif op.op_id == Id.VOp1_Percent:  # shortest suffix
        # 'abcd': match 'abc', 'ab', 'a'
        for i in xrange(n - 1, -1, -1):
            #log('Matching pattern %r with %r', arg, s[:i])
            if libc.fnmatch(arg, s[i:]):
                return s[:i]
        else:
            return s

    elif op.op_id == Id.VOp1_DPercent:  # longest suffix
        # 'abcd': match 'abc', 'bc', 'c', ...
        for i in xrange(0, n):
            #log('Matching pattern %r with %r', arg, s[:i])
            if libc.fnmatch(arg, s[i:]):
                return s[:i]
        else:
            return s
Beispiel #3
0
def DoUnarySuffixOp(s, op, arg):
  """Helper for ${x#prefix} and family."""

  # Fast path for constant strings.
  if not glob_.LooksLikeGlob(arg):
    if op.op_id in (Id.VOp1_Pound, Id.VOp1_DPound):  # const prefix
      if s.startswith(arg):
        return s[len(arg):]
      else:
        return s

    elif op.op_id in (Id.VOp1_Percent, Id.VOp1_DPercent):  # const suffix
      if s.endswith(arg):
        return s[:-len(arg)]
      else:
        return s

    elif op.op_id == Id.VOp1_Comma:  # Only lowercase the first letter
      if arg != '':
        raise NotImplementedError("%s can't have an argument" % op.op_id)
      return s[0].lower() + s[1:]

    elif op.op_id == Id.VOp1_DComma:
      if arg != '':
        raise NotImplementedError("%s can't have an argument" % op.op_id)
      return s.lower()

    elif op.op_id == Id.VOp1_Caret:  # Only uppercase the first letter
      if arg != '':
        raise NotImplementedError("%s can't have an argument" % op.op_id)
      return s[0].upper() + s[1:]

    elif op.op_id == Id.VOp1_DCaret:
      if arg != '':
        raise NotImplementedError("%s can't have an argument" % op.op_id)
      return s.upper()

    else:  # e.g. ^ ^^ , ,,
      raise AssertionError(op.op_id)

  # For patterns, do fnmatch() in a loop.
  #
  # TODO: The loop needs to iterate over code points, not bytes!
  # - The forward case can probably be handled in a similar manner.
  # - The backward case might be handled by pre-calculating an array of start
  #   positions with _NextUtf8Char.
  #
  # TODO: Another potential fast path:
  #
  # v=aabbccdd
  # echo ${v#*b}  # strip shortest prefix
  #
  # If the whole thing doesn't match '*b*', then no test can succeed.  So we
  # can fail early.  Conversely echo ${v%%c*} and '*c*'.
  #
  # (Although honestly this whole construct is nuts and should be deprecated.)

  n = len(s)
  if op.op_id == Id.VOp1_Pound:  # shortest prefix
    # 'abcd': match 'a', 'ab', 'abc', ...
    for i in xrange(1, n+1):
      #log('Matching pattern %r with %r', arg, s[:i])
      if libc.fnmatch(arg, s[:i]):
        return s[i:]
    else:
      return s

  elif op.op_id == Id.VOp1_DPound:  # longest prefix
    # 'abcd': match 'abc', 'ab', 'a'
    for i in xrange(n, 0, -1):
      #log('Matching pattern %r with %r', arg, s[:i])
      if libc.fnmatch(arg, s[:i]):
        return s[i:]
    else:
      return s

  elif op.op_id == Id.VOp1_Percent:  # shortest suffix
    # 'abcd': match 'abc', 'ab', 'a'
    for i in xrange(n-1, -1, -1):
      #log('Matching pattern %r with %r', arg, s[:i])
      if libc.fnmatch(arg, s[i:]):
        return s[:i]
    else:
      return s

  elif op.op_id == Id.VOp1_DPercent:  # longest suffix
    # 'abcd': match 'abc', 'bc', 'c', ...
    for i in xrange(0, n):
      #log('Matching pattern %r with %r', arg, s[:i])
      if libc.fnmatch(arg, s[i:]):
        return s[:i]
    else:
      return s

  else:
    raise NotImplementedError("Can't use %s with pattern" % op.op_id)