Exemplo n.º 1
0
  def __call__(self, cmd_val):
    # TODO:
    # - How to integrate this with auto-completion?  Have to handle '+'.

    if len(cmd_val.argv) == 1:
      # 'set' without args shows visible variable names and values.  According
      # to POSIX:
      # - the names should be sorted, and 
      # - the code should be suitable for re-input to the shell.  We have a
      #   spec test for this.
      # Also:
      # - autoconf also wants them to fit on ONE LINE.
      # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
      mapping = self.mem.GetAllVars()
      for name in sorted(mapping):
        str_val = mapping[name]
        code_str = '%s=%s' % (name, string_ops.ShellQuoteOneLine(str_val))
        print(code_str)
      return 0

    arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids)
    arg_r.Next()  # skip 'set'
    arg = SET_SPEC.Parse(arg_r)

    # 'set -o' shows options.  This is actually used by autoconf-generated
    # scripts!
    if arg.show_options:
      self.exec_opts.ShowOptions([])
      return 0

    SetExecOpts(self.exec_opts, arg.opt_changes, arg.shopt_changes)
    # Hm do we need saw_double_dash?
    if arg.saw_double_dash or not arg_r.AtEnd():
      self.mem.SetArgv(arg_r.Rest())
    return 0
Exemplo n.º 2
0
    def __call__(self, cmd_val):
        """
    printf: printf [-v var] format [argument ...]
    """
        arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids)
        arg_r.Next()  # skip argv[0]
        arg, _ = PRINTF_SPEC.Parse(arg_r)

        fmt, fmt_spid = arg_r.ReadRequired2('requires a format string')
        varargs, spids = arg_r.Rest2()

        #log('fmt %s', fmt)
        #log('vals %s', vals)

        arena = self.parse_ctx.arena
        if fmt in self.parse_cache:
            parts = self.parse_cache[fmt]
        else:
            line_reader = reader.StringLineReader(fmt, arena)
            # TODO: Make public
            lexer = self.parse_ctx._MakeLexer(line_reader)
            p = _FormatStringParser(lexer)
            arena.PushSource(source.ArgvWord(fmt_spid))
            try:
                parts = p.Parse()
            except error.Parse as e:
                self.errfmt.PrettyPrintError(e)
                return 2  # parse error
            finally:
                arena.PopSource()

            self.parse_cache[fmt] = parts

        if 0:
            print()
            for part in parts:
                part.PrettyPrint()
                print()

        out = []
        arg_index = 0
        num_args = len(varargs)

        while True:
            for part in parts:
                if isinstance(part, printf_part.Literal):
                    token = part.token
                    if token.id == Id.Format_EscapedPercent:
                        s = '%'
                    else:
                        s = word_compile.EvalCStringToken(token.id, token.val)
                    out.append(s)

                elif isinstance(part, printf_part.Percent):
                    try:
                        s = varargs[arg_index]
                        word_spid = spids[arg_index]
                    except IndexError:
                        s = ''
                        word_spid = runtime.NO_SPID

                    typ = part.type.val
                    if typ == 's':
                        if part.precision:
                            precision = int(part.precision.val)
                            s = s[:precision]  # truncate
                    elif typ == 'q':
                        s = string_ops.ShellQuoteOneLine(s)
                    elif typ in 'diouxX':
                        try:
                            d = int(s)
                        except ValueError:
                            if len(s) >= 2 and s[0] in '\'"':
                                # TODO: utf-8 decode s[1:] to be more correct.  Probably
                                # depends on issue #366, a utf-8 library.
                                d = ord(s[1])
                            else:
                                # This works around the fact that in the arg recycling case, you have no spid.
                                if word_spid == runtime.NO_SPID:
                                    self.errfmt.Print(
                                        "printf got invalid number %r for this substitution",
                                        s,
                                        span_id=part.type.span_id)
                                else:
                                    self.errfmt.Print(
                                        "printf got invalid number %r",
                                        s,
                                        span_id=word_spid)

                                return 1

                        if typ in 'di':
                            s = str(d)
                        elif typ in 'ouxX':
                            if d < 0:
                                e_die(
                                    "Can't format negative number %d with %%%s",
                                    d,
                                    typ,
                                    span_id=part.type.span_id)
                            if typ == 'u':
                                s = str(d)
                            elif typ == 'o':
                                s = '%o' % d
                            elif typ == 'x':
                                s = '%x' % d
                            elif typ == 'X':
                                s = '%X' % d
                        else:
                            raise AssertionError

                    else:
                        raise AssertionError

                    if part.width:
                        width = int(part.width.val)
                        if part.flag:
                            flag = part.flag.val
                            if flag == '-':
                                s = s.ljust(width, ' ')
                            elif flag == '0':
                                s = s.rjust(width, '0')
                            else:
                                pass
                        else:
                            s = s.rjust(width, ' ')

                    out.append(s)
                    arg_index += 1

                else:
                    raise AssertionError

            if arg_index >= num_args:
                break
            # Otherwise there are more args.  So cycle through the loop once more to
            # implement the 'arg recycling' behavior.

        result = ''.join(out)
        if arg.v:
            var_name = arg.v

            # Notes:
            # - bash allows a[i] here (as in unset and ${!x}), but we haven't
            # implemented it.
            # - TODO: get the span_id for arg.v!
            if not match.IsValidVarName(var_name):
                raise args.UsageError('got invalid variable name %r' %
                                      var_name)
            state.SetStringDynamic(self.mem, var_name, result)
        else:
            sys.stdout.write(result)
        return 0
Exemplo n.º 3
0
    def __call__(self, arg_vec):
        """
    printf: printf [-v var] format [argument ...]
    """
        arg_r = args.Reader(arg_vec.strs, spids=arg_vec.spids)
        arg_r.Next()  # skip argv[0]
        arg, _ = PRINTF_SPEC.Parse(arg_r)

        fmt, fmt_spid = arg_r.ReadRequired2('requires a format string')
        varargs, spids = arg_r.Rest2()

        #from core.util import log
        #log('fmt %s', fmt)
        #log('vals %s', vals)

        arena = self.parse_ctx.arena
        if fmt in self.parse_cache:
            parts = self.parse_cache[fmt]
        else:
            line_reader = reader.StringLineReader(fmt, arena)
            # TODO: Make public
            lexer = self.parse_ctx._MakeLexer(line_reader)
            p = _FormatStringParser(lexer)
            arena.PushSource(source.ArgvWord(fmt_spid))
            try:
                parts = p.Parse()
            except util.ParseError as e:
                self.errfmt.PrettyPrintError(e)
                return 2  # parse error
            finally:
                arena.PopSource()

            self.parse_cache[fmt] = parts

        if 0:
            print()
            for part in parts:
                part.PrettyPrint()
                print()

        out = []
        arg_index = 0
        num_args = len(varargs)

        while True:
            for part in parts:
                if isinstance(part, printf_part.Literal):
                    token = part.token
                    if token.id == Id.Format_EscapedPercent:
                        s = '%'
                    else:
                        s = word_compile.EvalCStringToken(token.id, token.val)
                    out.append(s)

                elif isinstance(part, printf_part.Percent):
                    try:
                        s = varargs[arg_index]
                        word_spid = spids[arg_index]
                    except IndexError:
                        s = ''
                        word_spid = const.NO_INTEGER

                    typ = part.type.val
                    if typ == 's':
                        pass  # val remains the same
                    elif typ == 'q':
                        s = string_ops.ShellQuoteOneLine(s)
                    elif typ in 'di':
                        try:
                            d = int(s)
                        except ValueError:
                            # This works around the fact that in the arg recycling case, you have no spid.
                            if word_spid == const.NO_INTEGER:
                                self.errfmt.Print(
                                    "printf got invalid number %r for this substitution",
                                    s,
                                    span_id=part.type.span_id)
                            else:
                                self.errfmt.Print(
                                    "printf got invalid number %r",
                                    s,
                                    span_id=word_spid)

                            return 1
                        s = str(d)
                    else:
                        raise AssertionError

                    if part.width:
                        width = int(part.width.val)
                        if part.flag:
                            flag = part.flag.val
                            if flag == '-':
                                s = s.ljust(width, ' ')
                            elif flag == '0':
                                s = s.rjust(width, '0')
                            else:
                                pass
                        else:
                            s = s.rjust(width, ' ')

                    out.append(s)
                    arg_index += 1

                else:
                    raise AssertionError

            if arg_index >= num_args:
                break
            # Otherwise there are more args.  So cycle through the loop once more to
            # implement the 'arg recycling' behavior.

        result = ''.join(out)
        if arg.v:
            var_name = arg.v

            # Notes:
            # - bash allows a[i] here (as in unset and ${!x}), but we haven't
            # implemented it.
            # - TODO: get the span_id for arg.v!
            if not match.IsValidVarName(var_name):
                raise args.UsageError('got invalid variable name %r' %
                                      var_name)
            state.SetStringDynamic(self.mem, var_name, result)
        else:
            sys.stdout.write(result)
        return 0