Ejemplo n.º 1
0
    def Matches(self, comp):
        # TODO: Delete COMPREPLY here?  It doesn't seem to be defined in bash by
        # default.
        argv, comp_words = comp.GetApiInput()

        state.SetGlobalArray(self.ex.mem, 'COMP_WORDS', comp_words)
        state.SetGlobalString(self.ex.mem, 'COMP_CWORD', str(comp.index))
        state.SetGlobalString(self.ex.mem, 'COMP_LINE', comp.line)
        state.SetGlobalString(self.ex.mem, 'COMP_POINT', str(comp.end))

        self.log('Running completion function %r with arguments %s',
                 self.func.name, argv)

        status = self.ex.RunFuncForCompletion(self.func, argv)
        if status == 124:
            self.log('Got status 124 from %r', self.func.name)
            raise _RetryCompletion()

        # Lame: COMP_REPLY would follow the naming convention!
        val = state.GetGlobal(self.ex.mem, 'COMPREPLY')
        if val.tag == value_e.Undef:
            util.error('Ran function %s but COMPREPLY was not defined',
                       self.func.name)
            return []

        if val.tag != value_e.StrArray:
            log('ERROR: COMPREPLY should be an array, got %s', val)
            return []
        self.log('COMPREPLY %s', val)

        # Return this all at once so we don't have a generator.  COMPREPLY happens
        # all at once anyway.
        return val.strs
Ejemplo n.º 2
0
def ExecExternalProgram(argv, environ):
    """Execute a program and exit this process.

  Called by:
  ls /
  exec ls /
  ( ls / )
  """
    # TODO: If there is an error, like the file isn't executable, then we should
    # exit, and the parent will reap it.  Should it capture stderr?
    try:
        os_.execvpe(argv[0], argv, environ)
    except OSError as e:
        util.error('%r: %s', argv[0], posix.strerror(e.errno))
        # POSIX mentions 126 and 127 for two specific errors.  The rest are
        # unspecified.
        #
        # http://pubs.opengroup.org/onlinepubs/9699919799.2016edition/utilities/V3_chap02.html#tag_18_08_02

        if e.errno == errno.EACCES:
            status = 126
        elif e.errno == errno.ENOENT:
            status = 127  # e.g. command not found should be 127.
        else:
            # dash uses 2, but we use that for parse errors.  This seems to be
            # consistent with mksh and zsh.
            status = 127

        sys.exit(status)
Ejemplo n.º 3
0
  def _Source(self, argv):
    try:
      path = argv[0]
    except IndexError:
      # TODO: Should point to the source statement that failed.
      util.error('source: missing required argument')
      return 1

    try:
      f = self.fd_state.Open(path)  # Shell can't use descriptors 3-9
    except OSError as e:
      # TODO: Should point to the source statement that failed.
      util.error('source %r failed: %s', path, os.strerror(e.errno))
      return 1

    try:
      line_reader = reader.FileLineReader(f, self.arena)
      _, c_parser = parse_lib.MakeParser(line_reader, self.arena)
      self.mem.PushSource(argv[1:])
      try:
        status = self._EvalHelper(c_parser, path)
        return status
      finally:
        self.mem.PopSource()

    except _ControlFlow as e:
      if e.IsReturn():
        return e.StatusCode()
      else:
        raise
    finally:
      f.close()
Ejemplo n.º 4
0
def _GetOpts(spec, argv, optind):
    optarg = ''  # not set by default

    try:
        current = argv[optind - 1]  # 1-based indexing
    except IndexError:
        return 1, '?', optarg, optind

    if not current.startswith('-'):  # The next arg doesn't look like a flag.
        return 1, '?', optarg, optind

    # It looks like an argument.  Stop iteration by returning 1.
    if current not in spec:  # Invalid flag
        optind += 1
        return 0, '?', optarg, optind

    optind += 1
    opt_char = current[-1]

    needs_arg = spec[current]
    if needs_arg:
        try:
            optarg = argv[optind - 1]  # 1-based indexing
        except IndexError:
            util.error('getopts: option %r requires an argument', current)
            # Hm doesn't cause status 1?
            return 0, '?', optarg, optind

        optind += 1

    return 0, opt_char, optarg, optind
Ejemplo n.º 5
0
def Alias(argv, aliases):
    if not argv:
        for name in sorted(aliases):
            alias_exp = aliases[name]
            # This is somewhat like bash, except we use %r for ''.
            print('alias %s=%r' % (name, alias_exp))
        return 0

    status = 0
    for arg in argv:
        parts = arg.split('=', 1)
        if len(parts) == 1:  # if we get a plain word without, print alias
            name = parts[0]
            alias_exp = aliases.get(name)
            if alias_exp is None:
                util.error('alias %r is not defined', name)  # TODO: error?
                status = 1
            else:
                print('alias %s=%r' % (name, alias_exp))
        else:
            name, alias_exp = parts
            aliases[name] = alias_exp

    #print(argv)
    #log('AFTER ALIAS %s', aliases)
    return status
Ejemplo n.º 6
0
def Help(argv, loader):
    # TODO: Need $VERSION inside all pages?
    try:
        topic = argv[0]
    except IndexError:
        topic = 'help'

    if topic == 'toc':
        # Just show the raw source.
        f = loader.open('doc/osh-quick-ref-toc.txt')
    else:
        try:
            section_id = osh_help.TOPIC_LOOKUP[topic]
        except KeyError:
            util.error('No help topics match %r', topic)
            return 1
        else:
            try:
                f = loader.open('_devbuild/osh-quick-ref/%s' % section_id)
            except IOError as e:
                util.error(str(e))
                raise AssertionError('Should have found %r' % section_id)

    for line in f:
        sys.stdout.write(line)
    f.close()
    return 0
Ejemplo n.º 7
0
def _GetOpts(spec, mem, optind):
    optarg = ''  # not set by default

    v2 = mem.GetArgNum(optind)
    if v2.tag == value_e.Undef:  # No more arguments.
        return 1, '?', optarg, optind
    assert v2.tag == value_e.Str

    current = v2.s

    if not current.startswith('-'):  # The next arg doesn't look like a flag.
        return 1, '?', optarg, optind

    # It looks like an argument.  Stop iteration by returning 1.
    if current not in spec:  # Invalid flag
        optind += 1
        return 0, '?', optarg, optind

    optind += 1
    opt_char = current[-1]

    needs_arg = spec[current]
    if needs_arg:
        v3 = mem.GetArgNum(optind)
        if v3.tag == value_e.Undef:
            util.error('getopts: option %r requires an argument', current)
            # Hm doesn't cause status 1?
            return 0, '?', optarg, optind
        assert v3.tag == value_e.Str

        optarg = v3.s
        optind += 1

    return 0, opt_char, optarg, optind
Ejemplo n.º 8
0
  def _PushDup(self, fd1, fd2):
    """
    Save fd2 and dup fd1 onto fd2.
    """
    #log('---- _PushDup %s %s\n', fd1, fd2)
    try:
      fcntl.fcntl(fd2, fcntl.F_DUPFD, self.next_fd)
    except IOError as e:
      # Example program that causes this error: exec 4>&1.  Descriptor 4 isn't
      # open.
      # This seems to be ignored in dash too in savefd()?
      if e.errno != errno.EBADF:
        raise
    else:
      os.close(fd2)
      fcntl.fcntl(self.next_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)

    #log('==== dup %s %s\n' % (fd1, fd2))
    try:
      os.dup2(fd1, fd2)
    except OSError as e:
      # bash/dash give this error too, e.g. for 'echo hi 1>&3'
      util.error('%d: %s', fd1, os.strerror(e.errno))
      # Restore and return error
      os.dup2(self.next_fd, fd2)
      os.close(self.next_fd)
      # Undo it
      return False

    # Oh this is wrong?
    #os.close(fd1)

    self.cur_frame.saved.append((self.next_fd, fd2))
    self.next_fd += 1
    return True
Ejemplo n.º 9
0
  def _EvalRedirect(self, n):
    fd = REDIR_DEFAULT_FD[n.op_id] if n.fd == const.NO_INTEGER else n.fd
    if n.tag == redir_e.Redir:
      redir_type = REDIR_ARG_TYPES[n.op_id]  # could be static in the LST?

      if redir_type == redir_arg_type_e.Path:
        # NOTE: no globbing.  You can write to a file called '*.py'.
        val = self.word_ev.EvalWordToString(n.arg_word)
        if val.tag != value_e.Str:  # TODO: This error never fires
          util.error("Redirect filename must be a string, got %s", val)
          return None
        filename = val.s
        if not filename:
          # Whether this is fatal depends on errexit.
          util.error("Redirect filename can't be empty")
          return None

        return runtime.PathRedirect(n.op_id, fd, filename)

      elif redir_type == redir_arg_type_e.Desc:  # e.g. 1>&2
        val = self.word_ev.EvalWordToString(n.arg_word)
        if val.tag != value_e.Str:  # TODO: This error never fires
          util.error("Redirect descriptor should be a string, got %s", val)
          return None
        t = val.s
        if not t:
          util.error("Redirect descriptor can't be empty")
          return None
        try:
          target_fd = int(t)
        except ValueError:
          util.error(
              "Redirect descriptor should look like an integer, got %s", val)
          return None

        return runtime.DescRedirect(n.op_id, fd, target_fd)

      elif redir_type == redir_arg_type_e.Here:  # here word
        # TODO: decay should be controlled by an option
        val = self.word_ev.EvalWordToString(n.arg_word, decay=True)
        if val.tag != value_e.Str:   # TODO: This error never fires
          util.warn("Here word body should be a string, got %s", val)
          return None
        # NOTE: bash and mksh both add \n
        return runtime.HereRedirect(fd, val.s + '\n')
      else:
        raise AssertionError('Unknown redirect op')

    elif n.tag == redir_e.HereDoc:
      # TODO: decay shoudl be controlled by an option
      val = self.word_ev.EvalWordToString(n.body, decay=True)
      if val.tag != value_e.Str:   # TODO: This error never fires
        util.warn("Here doc body should be a string, got %s", val)
        return None
      return runtime.HereRedirect(fd, val.s)

    else:
      raise AssertionError('Unknown redirect type')
Ejemplo n.º 10
0
 def RunFuncForCompletion(self, func_node, argv):
   try:
     status = self._RunFunc(func_node, argv)
   except util.FatalRuntimeError as e:
     ui.PrettyPrintError(e, self.arena, sys.stderr)
     status = e.exit_status if e.exit_status is not None else 1
   except _ControlFlow as e:
      # shouldn't be able to exit the shell from a completion hook!
     util.error('Attempted to exit from completion hook.')
     status = 1
   return status
Ejemplo n.º 11
0
  def _EvalRedirect(self, n):
    fd = REDIR_DEFAULT_FD[n.op.id] if n.fd == const.NO_INTEGER else n.fd
    if n.tag == redir_e.Redir:
      redir_type = REDIR_ARG_TYPES[n.op.id]  # could be static in the LST?

      if redir_type == redir_arg_type_e.Path:
        # NOTE: no globbing.  You can write to a file called '*.py'.
        val = self.word_ev.EvalWordToString(n.arg_word)
        if val.tag != value_e.Str:  # TODO: This error never fires
          util.error("Redirect filename must be a string, got %s", val)
          return None
        filename = val.s
        if not filename:
          # Whether this is fatal depends on errexit.
          util.error("Redirect filename can't be empty")
          return None

        return redirect.PathRedirect(n.op.id, fd, filename)

      elif redir_type == redir_arg_type_e.Desc:  # e.g. 1>&2
        val = self.word_ev.EvalWordToString(n.arg_word)
        if val.tag != value_e.Str:  # TODO: This error never fires
          util.error("Redirect descriptor should be a string, got %s", val)
          return None
        t = val.s
        if not t:
          util.error("Redirect descriptor can't be empty")
          return None
        try:
          target_fd = int(t)
        except ValueError:
          util.error(
              "Redirect descriptor should look like an integer, got %s", val)
          return None

        return redirect.DescRedirect(n.op.id, fd, target_fd)

      elif redir_type == redir_arg_type_e.Here:  # here word
        val = self.word_ev.EvalWordToString(n.arg_word)
        assert val.tag == value_e.Str, val
        # NOTE: bash and mksh both add \n
        return redirect.HereRedirect(fd, val.s + '\n')
      else:
        raise AssertionError('Unknown redirect op')

    elif n.tag == redir_e.HereDoc:
      # HACK: Wrap it in a word to evaluate.
      w = osh_word.CompoundWord(n.stdin_parts)
      val = self.word_ev.EvalWordToString(w)
      assert val.tag == value_e.Str, val
      return redirect.HereRedirect(fd, val.s)

    else:
      raise AssertionError('Unknown redirect type')
Ejemplo n.º 12
0
def main(argv):
    arg, i = SPEC.Parse(argv)
    if not arg.f:
        util.error("-f must be passed")
        return 1
    for path in argv[i:]:
        res = libc.realpath(path)
        if res is None:
            return 1
        print(res)
    return 0
Ejemplo n.º 13
0
def UnAlias(argv, aliases):
    if not argv:
        raise args.UsageError('unalias NAME...')

    status = 0
    for name in argv:
        try:
            del aliases[name]
        except KeyError:
            util.error('alias %r is not defined', name)
            status = 1
    return status
Ejemplo n.º 14
0
    def Exec(self, argv, environ):
        """Execute a program and exit this process.

    Called by:
    ls /
    exec ls /
    ( ls / )
    """
        if self.hijack_shebang:
            try:
                f = self.fd_state.Open(argv[0])
            except OSError as e:
                pass
            else:
                try:
                    line = f.read(40)
                    if (line.startswith('#!/bin/sh')
                            or line.startswith('#!/bin/bash')
                            or line.startswith('#!/usr/bin/env bash')):
                        self.debug_f.log('Hijacked: %s with %s', argv,
                                         self.hijack_shebang)
                        argv = [self.hijack_shebang] + argv
                    else:
                        #self.debug_f.log('Not hijacking %s (%r)', argv, line)
                        pass
                finally:
                    f.close()

        # TODO: If there is an error, like the file isn't executable, then we should
        # exit, and the parent will reap it.  Should it capture stderr?
        try:
            os_.execvpe(argv[0], argv, environ)
        except OSError as e:
            # TODO: Run with /bin/sh when ENOEXEC error (noshebang).  Because all
            # shells do it.

            util.error('%r: %s', argv[0], posix.strerror(e.errno))
            # POSIX mentions 126 and 127 for two specific errors.  The rest are
            # unspecified.
            #
            # http://pubs.opengroup.org/onlinepubs/9699919799.2016edition/utilities/V3_chap02.html#tag_18_08_02

            if e.errno == errno.EACCES:
                status = 126
            elif e.errno == errno.ENOENT:
                status = 127  # e.g. command not found should be 127.
            else:
                # dash uses 2, but we use that for parse errors.  This seems to be
                # consistent with mksh and zsh.
                status = 127

            sys.exit(status)  # raises SystemExit
Ejemplo n.º 15
0
def Exit(argv):
    if len(argv) > 1:
        util.error('exit: too many arguments')
        return 1
    try:
        code = int(argv[0])
    except IndexError:
        code = 0
    except ValueError as e:
        print("Invalid argument %r" % argv[0], file=sys.stderr)
        code = 1  # Runtime Error
    # TODO: Should this be turned into our own SystemExit exception?
    sys.exit(code)
Ejemplo n.º 16
0
def Shift(argv, mem):
    if len(argv) > 1:
        util.error('shift: too many arguments')
        return 1
    try:
        n = int(argv[0])
    except IndexError:
        n = 1
    except ValueError:
        print("Invalid shift argument %r" % argv[1], file=sys.stderr)
        return 1  # runtime error

    return mem.Shift(n)
Ejemplo n.º 17
0
    def __call__(self, argv):
        arg_r = args.Reader(argv)
        arg = COMPOPT_SPEC.Parse(arg_r)

        if not self.comp_state.currently_completing:
            # bash checks this.
            util.error(
                'compopt: not currently executing a completion function')
            return 1

        self.comp_state.dynamic_opts.update(arg.opt_changes)
        #log('compopt: %s', arg)
        #log('compopt %s', base_opts)
        return 0
Ejemplo n.º 18
0
    def Matches(self, comp):
        # Have to clear the response every time.  TODO: Reuse the object?
        state.SetGlobalArray(self.ex.mem, 'COMPREPLY', [])

        # New completions should use COMP_ARGV, a construct specific to OSH>
        state.SetGlobalArray(self.ex.mem, 'COMP_ARGV', comp.partial_argv)

        # Old completions may use COMP_WORDS.  It is split by : and = to emulate
        # bash's behavior.
        # More commonly, they will call _init_completion and use the 'words' output
        # of that, ignoring COMP_WORDS.
        comp_words = []
        for a in comp.partial_argv:
            AdjustArg(a, [':', '='], comp_words)
        if comp.index == -1:  # cmopgen
            comp_cword = comp.index
        else:
            comp_cword = len(comp_words) - 1  # weird invariant

        state.SetGlobalArray(self.ex.mem, 'COMP_WORDS', comp_words)
        state.SetGlobalString(self.ex.mem, 'COMP_CWORD', str(comp_cword))
        state.SetGlobalString(self.ex.mem, 'COMP_LINE', comp.line)
        state.SetGlobalString(self.ex.mem, 'COMP_POINT', str(comp.end))

        argv = [comp.first, comp.to_complete, comp.prev]
        self.log('Running completion function %r with arguments %s',
                 self.func.name, argv)

        status = self.ex.RunFuncForCompletion(self.func, argv)
        if status == 124:
            self.log('Got status 124 from %r', self.func.name)
            raise _RetryCompletion()

        # Read the response.  We set it above, so this error would only happen if
        # the user unset it.
        # NOTE: 'COMP_REPLY' would follow the naming convention!
        val = state.GetGlobal(self.ex.mem, 'COMPREPLY')
        if val.tag == value_e.Undef:
            util.error('Ran function %s but COMPREPLY was not defined',
                       self.func.name)
            return []

        if val.tag != value_e.StrArray:
            log('ERROR: COMPREPLY should be an array, got %s', val)
            return []
        self.log('COMPREPLY %s', val)

        # Return this all at once so we don't have a generator.  COMPREPLY happens
        # all at once anyway.
        return val.strs
Ejemplo n.º 19
0
def Popd(argv, home_dir, dir_stack):
    dest_dir = dir_stack.Pop()
    if dest_dir is None:
        util.error('popd: directory stack is empty')
        return 1

    try:
        posix.chdir(dest_dir)
    except OSError as e:
        util.error("popd: %r: %s", dest_dir, posix.strerror(e.errno))
        return 1

    _PrintDirStack(dir_stack, SINGLE_LINE, home_dir)
    return 0
Ejemplo n.º 20
0
def Popd(argv, mem, dir_stack):
    dest_dir = dir_stack.Pop()
    if dest_dir is None:
        util.error('popd: directory stack is empty')
        return 1

    try:
        posix.chdir(dest_dir)
    except OSError as e:
        util.error("popd: %r: %s", dest_dir, posix.strerror(e.errno))
        return 1

    _PrintDirStack(dir_stack, SINGLE_LINE, mem.GetVar('HOME'))
    state.SetGlobalString(mem, 'PWD', dest_dir)
    return 0
Ejemplo n.º 21
0
 def _EvalHelper(self, c_parser, source_name):
   self.arena.PushSource(source_name)
   try:
     node = c_parser.ParseWholeFile()
     # NOTE: We could model a parse error as an exception, like Python, so we
     # get a traceback.  (This won't be applicable for a static module system.)
     if not node:
       util.error('Parse error in %r:', source_name)
       err = c_parser.Error()
       ui.PrintErrorStack(err, self.arena, sys.stderr)
       return 1
     status = self._Execute(node)
     return status
   finally:
     self.arena.PopSource()
Ejemplo n.º 22
0
 def _Source(self, argv):
   try:
     path = argv[0]
   except IndexError:
     # TODO: Should point to the source statement that failed.
     util.error('source: missing required argument')
     return 1
   try:
     with open(path) as f:
       line_reader = reader.FileLineReader(f, self.arena)
       _, c_parser = parse_lib.MakeParser(line_reader, self.arena)
       return self._EvalHelper(c_parser, path)
   except IOError as e:
     # TODO: Should point to the source statement that failed.
     util.error('source %r failed: %s', path, os.strerror(e.errno))
     return 1
Ejemplo n.º 23
0
    def __call__(self, argv):
        arg_r = args.Reader(argv)
        arg = COMPOPT_SPEC.Parse(arg_r)

        if not self.comp_state.currently_completing:
            # bash checks this.
            util.error(
                'compopt: not currently executing a completion function')
            return 1

        for name, b in arg.opt_changes:
            #log('setting %s = %s', name, b)
            self.comp_state.current_opts.Set(name, b)
        #log('compopt: %s', arg)
        #log('compopt %s', comp_opts)
        return 0
Ejemplo n.º 24
0
 def _SetOption(self, opt_name, b):
     """Private version for synchronizing from SHELLOPTS."""
     assert '_' not in opt_name
     if opt_name not in _SET_OPTION_NAMES:
         raise args.UsageError('Invalid option %r' % opt_name)
     if opt_name == 'errexit':
         self.errexit.Set(b)
     elif opt_name in ('vi', 'emacs'):
         if self.readline:
             self.readline.parse_and_bind("set editing-mode " + opt_name)
         else:
             # TODO error message copied from 'cmd_exec.py'; refactor?
             util.error('Oil was not built with readline/completion.')
     else:
         # strict-control-flow -> strict_control_flow
         opt_name = opt_name.replace('-', '_')
         setattr(self, opt_name, b)
Ejemplo n.º 25
0
def Repr(argv, mem):
    """Given a list of variable names, print their values.

  'repr a' is a lot easier to type than 'argv.py "${a[@]}"'.
  """
    status = 0
    for name in argv:
        if not match.IsValidVarName(name):
            util.error('%r is not a valid variable name', name)
            return 1

        # TODO: Should we print flags too?
        val = mem.GetVar(name)
        if val.tag == value_e.Undef:
            print('%r is not defined' % name)
            status = 1
        else:
            print('%s = %s' % (name, val))
    return status
Ejemplo n.º 26
0
    def _PushDup(self, fd1, fd2):
        """Save fd2, and dup fd1 onto fd2.

    Mutates self.cur_frame.saved.

    Returns:
      success Bool
    """
        new_fd = self._NextFreeFileDescriptor()
        #log('---- _PushDup %s %s', fd1, fd2)
        need_restore = True
        try:
            #log('DUPFD %s %s', fd2, self.next_fd)
            fcntl.fcntl(fd2, fcntl.F_DUPFD, new_fd)
        except IOError as e:
            # Example program that causes this error: exec 4>&1.  Descriptor 4 isn't
            # open.
            # This seems to be ignored in dash too in savefd()?
            if e.errno == errno.EBADF:
                #log('ERROR %s', e)
                need_restore = False
            else:
                raise
        else:
            posix.close(fd2)
            fcntl.fcntl(new_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)

        #log('==== dup %s %s\n' % (fd1, fd2))
        try:
            posix.dup2(fd1, fd2)
        except OSError as e:
            # bash/dash give this error too, e.g. for 'echo hi 1>&3'
            util.error('%d: %s', fd1, posix.strerror(e.errno))
            # Restore and return error
            posix.dup2(new_fd, fd2)
            posix.close(new_fd)
            # Undo it
            return False

        if need_restore:
            self.cur_frame.saved.append((new_fd, fd2))
        return True
Ejemplo n.º 27
0
  def ParseTrapCode(self, code_str):
    """
    Returns:
      A node, or None if the code is invalid.
    """
    line_reader = reader.StringLineReader(code_str, self.arena)
    _, c_parser = parse_lib.MakeParser(line_reader, self.arena)

    source_name = '<trap string>'
    self.arena.PushSource(source_name)
    try:
      node = c_parser.ParseWholeFile()
      if not node:
        util.error('Parse error in %r:', source_name)
        err = c_parser.Error()
        ui.PrintErrorStack(err, self.arena, sys.stderr)
        return None
    finally:
      self.arena.PopSource()

    return node
Ejemplo n.º 28
0
  def _Source(self, argv):
    try:
      path = argv[0]
    except IndexError:
      # TODO: Should point to the source statement that failed.
      util.error('source: missing required argument')
      return 1

    try:
      f = self.fd_state.Open(path)  # Shell can't use descriptors 3-9
    except OSError as e:
      # TODO: Should point to the source statement that failed.
      util.error('source %r failed: %s', path, posix.strerror(e.errno))
      return 1

    try:
      line_reader = reader.FileLineReader(f, self.arena)
      _, c_parser = self.parse_ctx.MakeParser(line_reader)

      # A sourced module CAN have a new arguments array, but it always shares
      # the same variable scope as the caller.  The caller could be at either a
      # global or a local scope.
      source_argv = argv[1:]
      self.mem.PushSource(path, source_argv)
      try:
        status = self._EvalHelper(c_parser, path)
      finally:
        self.mem.PopSource(source_argv)

      return status

    except _ControlFlow as e:
      if e.IsReturn():
        return e.StatusCode()
      else:
        raise
    finally:
      f.close()
Ejemplo n.º 29
0
def Cd(argv, mem, dir_stack):
    arg, i = CD_SPEC.Parse(argv)
    # TODO: error checking, etc.
    # TODO: ensure that if multiple flags are provided, the *last* one overrides
    # the others.

    try:
        dest_dir = argv[i]
    except IndexError:
        val = mem.GetVar('HOME')
        if val.tag == value_e.Undef:
            util.error("$HOME isn't defined")
            return 1
        elif val.tag == value_e.Str:
            dest_dir = val.s
        elif val.tag == value_e.StrArray:
            util.error("$HOME shouldn't be an array.")
            return 1

    if dest_dir == '-':
        old = mem.GetVar('OLDPWD', scope_e.GlobalOnly)
        if old.tag == value_e.Undef:
            log('OLDPWD not set')
            return 1
        elif old.tag == value_e.Str:
            dest_dir = old.s
            print(dest_dir)  # Shells print the directory
        elif old.tag == value_e.StrArray:
            # TODO: Prevent the user from setting OLDPWD to array (or maybe they
            # can't even set it at all.)
            raise AssertionError('Invalid OLDPWD')

    pwd = mem.GetVar('PWD')
    assert pwd.tag == value_e.Str, pwd  # TODO: Need a general scheme to avoid

    # Calculate new directory, chdir() to it, then set PWD to it.  NOTE: We can't
    # call posix.getcwd() because it can raise OSError if the directory was
    # removed (ENOENT.)
    abspath = os_path.join(pwd.s, dest_dir)  # make it absolute, for cd ..
    if arg.P:
        # -P means resolve symbolic links, then process '..'
        real_dest_dir = libc.realpath(abspath)
    else:
        # -L means process '..' first.  This just does string manipulation.  (But
        # realpath afterward isn't correct?)
        real_dest_dir = os_path.normpath(abspath)

    try:
        posix.chdir(real_dest_dir)
    except OSError as e:
        # TODO: Add line number, etc.
        util.error("cd %r: %s", real_dest_dir, posix.strerror(e.errno))
        return 1

    state.ExportGlobalString(mem, 'OLDPWD', pwd.s)
    state.ExportGlobalString(mem, 'PWD', real_dest_dir)
    dir_stack.Reset()  # for pushd/popd/dirs
    return 0
Ejemplo n.º 30
0
  def ParseTrapCode(self, code_str):
    """
    Returns:
      A node, or None if the code is invalid.
    """
    line_reader = reader.StringLineReader(code_str, self.arena)
    _, c_parser = self.parse_ctx.MakeParser(line_reader)

    source_name = '<trap string>'
    self.arena.PushSource(source_name)

    try:
      try:
        node = main_loop.ParseWholeFile(c_parser)
      except util.ParseError as e:
        util.error('Parse error in %r:', source_name)
        ui.PrettyPrintError(e, self.arena, sys.stderr)
        return None

    finally:
      self.arena.PopSource()

    return node