private Result doCall()

in gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Pipe.java [240:487]


    private Result doCall()
    {
        // The errChannel will be used to print errors to the error stream
        // Before the command is actually executed (i.e. during the initialization,
        // including the redirection processing), it will be the original error stream.
        // This value may be modified by redirections and the redirected error stream
        // will be effective just before actually running the command.
        WritableByteChannel errChannel = (WritableByteChannel) streams[2];

        ThreadIO threadIo = closure.session().threadIO();

        try
        {
            List<Token> tokens = statement.redirections();
            for (int i = 0; i < tokens.size(); i++)
            {
                Token t = tokens.get(i);
                Matcher m;
                if ((m = Pattern.compile("(?:([0-9])?|(&)?)>(>)?").matcher(t)).matches())
                {
                    int fd;
                    if (m.group(1) != null)
                    {
                        fd = Integer.parseInt(m.group(1));
                    }
                    else if (m.group(2) != null)
                    {
                        fd = -1; // both 1 and 2
                    }
                    else
                    {
                        fd = 1;
                    }
                    boolean append = m.group(3) != null;
                    Set<StandardOpenOption> options = new HashSet<>();
                    options.add(StandardOpenOption.WRITE);
                    options.add(StandardOpenOption.CREATE);
                    options.add(append ? StandardOpenOption.APPEND : StandardOpenOption.TRUNCATE_EXISTING);
                    Token tok = tokens.get(++i);
                    Object val = Expander.expand(tok, closure);
                    for (Path p : toPaths(val))
                    {
                        p = closure.session().redirect(p, WRITE);
                        Channel ch = Files.newByteChannel(p, options);
                        if (fd >= 0)
                        {
                            setStream(ch, fd, WRITE);
                        }
                        else
                        {
                            setStream(ch, 1, WRITE);
                            setStream(ch, 2, WRITE);
                        }
                    }
                }
                else if ((m = Pattern.compile("([0-9])?>&([0-9])").matcher(t)).matches())
                {
                    int fd0 = 1;
                    if (m.group(1) != null)
                    {
                        fd0 = Integer.parseInt(m.group(1));
                    }
                    int fd1 = Integer.parseInt(m.group(2));
                    if (streams[fd0] != null && toclose[fd0])
                    {
                        streams[fd0].close();
                    }
                    // If the stream has to be closed, close it when both streams are closed
                    if (toclose[fd1])
                    {
                        Channel channel = streams[fd1];
                        AtomicInteger references = new AtomicInteger();
                        streams[fd0] = new RefByteChannel(channel, references);
                        streams[fd1] = new RefByteChannel(channel, references);
                        toclose[fd0] = true;
                    }
                    else
                    {
                        streams[fd0] = streams[fd1];
                        toclose[fd0] = false;
                    }
                }
                else if ((m = Pattern.compile("([0-9])?<(>)?").matcher(t)).matches())
                {
                    int fd = 0;
                    if (m.group(1) != null)
                    {
                        fd = Integer.parseInt(m.group(1));
                    }
                    boolean output = m.group(2) != null;
                    Set<StandardOpenOption> options = new HashSet<>();
                    options.add(StandardOpenOption.READ);
                    if (output)
                    {
                        options.add(StandardOpenOption.WRITE);
                        options.add(StandardOpenOption.CREATE);
                    }
                    Token tok = tokens.get(++i);
                    Object val = Expander.expand(tok, closure);
                    for (Path p : toPaths(val))
                    {
                        p = closure.session().redirect(p, READ + (output ? WRITE : 0));
                        Channel ch = Files.newByteChannel(p, options);
                        setStream(ch, fd, READ + (output ? WRITE : 0));
                    }
                }
                else if ((m = Pattern.compile("<<-?").matcher(t)).matches())
                {
                    final Token hereDoc = tokens.get(++i);
                    final boolean stripLeadingTabs = t.charAt(t.length() - 1) == '-';
                    InputStream doc = new InputStream()
                    {
                        final byte[] bytes = hereDoc.toString().getBytes();
                        int index = 0;
                        boolean nl = true;
                        @Override
                        public int read() {
                            if (nl && stripLeadingTabs)
                            {
                                while (index < bytes.length && bytes[index] == '\t')
                                {
                                    index++;
                                }
                            }
                            if (index < bytes.length)
                            {
                                int ch = bytes[index++];
                                nl = ch == '\n';
                                return ch;
                            }
                            return -1;
                        }
                    };
                    Channel ch = Channels.newChannel(doc);
                    setStream(ch, 0, READ);
                }
                else if (Token.eq("<<<", t))
                {
                    Token word = tokens.get(++i);
                    Object val = Expander.expand("\"" + word + "\"", closure);
                    String str = val != null ? String.valueOf(val) : "";
                    Channel ch = Channels.newChannel(new ByteArrayInputStream(str.getBytes()));
                    setStream(ch, 0, READ);
                }
            }

            for (int i = 0; i < streams.length; i++) {
                streams[i] = wrap(streams[i]);
            }

            // Create streams
            in = Channels.newInputStream((ReadableByteChannel) streams[0]);
            out = new PrintStream(Channels.newOutputStream((WritableByteChannel) streams[1]), true);
            err = new PrintStream(Channels.newOutputStream((WritableByteChannel) streams[2]), true);
            // Change the error stream to the redirected one, now that
            // the command is about to be executed.
            errChannel = (WritableByteChannel) streams[2];

            if (threadIo != null)
            {
                threadIo.setStreams(in, out, err);
            }

            Pipe previous = setCurrentPipe(this);
            try
            {
                Object result;
                // Very special case for empty statements with redirection
                if (statement.tokens().isEmpty() && toclose[0])
                {
                    ByteBuffer bb = ByteBuffer.allocate(1024);
                    while (((ReadableByteChannel) streams[0]).read(bb) >= 0 || bb.position() != 0)
                    {
                        bb.flip();
                        ((WritableByteChannel) streams[1]).write(bb);
                        bb.compact();
                    }
                    result = null;
                }
                else
                {
                    result = closure.execute(statement);
                }
                // If an error has been set
                if (error != 0)
                {
                    return new Result(error);
                }
                // We don't print the result if we're at the end of the pipe
                if (result != null && !endOfPipe && !Boolean.FALSE.equals(closure.session().get(".FormatPipe")))
                {
                    out.println(closure.session().format(result, Converter.INSPECT));
                }
                return new Result(result);

            }
            finally
            {
                setCurrentPipe(previous);
            }
        }
        catch (Exception e)
        {
            if (!endOfPipe)
            {
                String msg = "gogo: " + e.getClass().getSimpleName() + ": " + e.getMessage() + "\n";
                try
                {
                    errChannel.write(ByteBuffer.wrap(msg.getBytes()));
                }
                catch (IOException ioe)
                {
                    e.addSuppressed(ioe);
                }
            }
            return new Result(e);
        }
        finally
        {
            if (out != null)
            {
                out.flush();
            }
            if (err != null)
            {
                err.flush();
            }
            if (threadIo != null)
            {
                threadIo.close();
            }

            try
            {
                for (int i = 0; i < 10; i++)
                {
                    if (toclose[i] && streams[i] != null)
                    {
                        streams[i].close();
                    }
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }