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();
}
}
}