Shell: Parse a pipe sequence inside $(...)

This commit is contained in:
AnotherTest 2020-06-22 00:30:14 +04:30 committed by Andreas Kling
parent 8e078cf4ab
commit 42304d7bf1
4 changed files with 36 additions and 25 deletions

View file

@ -658,7 +658,7 @@ RefPtr<Value> Execute::run(TheExecutionInputType input_value)
auto run_commands = [&](auto& commands) { auto run_commands = [&](auto& commands) {
for (auto& command : commands) { for (auto& command : commands) {
#ifdef EXECUTE_DEBUG #ifdef EXECUTE_DEBUG
dbg() << "Command " << (m_capture_stdout ? "Capturing stdout " : "") << (command.should_wait ? "" : "In background "); dbg() << "Command";
for (auto& arg : command.argv) for (auto& arg : command.argv)
dbg() << "argv: " << arg; dbg() << "argv: " << arg;
for (auto& redir : command.redirections) { for (auto& redir : command.redirections) {
@ -683,7 +683,7 @@ RefPtr<Value> Execute::run(TheExecutionInputType input_value)
} else { } else {
if (command.is_pipe_source) { if (command.is_pipe_source) {
jobs_to_wait_for.append(job); jobs_to_wait_for.append(job);
} else { } else if (command.should_notify_if_in_background) {
if (job) if (job)
job->set_running_in_background(true); job->set_running_in_background(true);
shell->take_back_stdin(); shell->take_back_stdin();
@ -699,31 +699,30 @@ RefPtr<Value> Execute::run(TheExecutionInputType input_value)
dbg() << "Error: cannot pipe(): " << strerror(errno); dbg() << "Error: cannot pipe(): " << strerror(errno);
return create<StringValue>(""); return create<StringValue>("");
} }
auto last_in_commands = commands.take_last(); auto& last_in_commands = commands.last();
last_in_commands.redirections.append(*new FdRedirection(STDOUT_FILENO, pipefd[1], Rewiring::Close::Destination)); last_in_commands.redirections.prepend(*new FdRedirection(STDOUT_FILENO, pipefd[1], Rewiring::Close::Destination));
last_in_commands.should_wait = false; last_in_commands.should_wait = true;
last_in_commands.is_pipe_source = true; last_in_commands.should_notify_if_in_background = false;
last_in_commands.is_pipe_source = false;
Vector<Command> commands;
commands.append(commands);
commands.append(last_in_commands);
run_commands(commands);
auto notifier = Core::Notifier::construct(pipefd[0], Core::Notifier::Read); auto notifier = Core::Notifier::construct(pipefd[0], Core::Notifier::Read);
StringBuilder builder; StringBuilder builder;
notifier->on_ready_to_read = [&] { auto try_read = [&] {
u8 buffer[4096]; u8 buffer[4096];
size_t remaining_size = 4096; size_t remaining_size = 4096;
for (;;) { for (;;) {
if (remaining_size == 0) if (remaining_size == 0)
return; break;
auto read_size = read(pipefd[0], buffer, remaining_size); auto read_size = read(pipefd[0], buffer, remaining_size);
if (read_size < 0) { if (read_size < 0) {
if (errno == EINTR)
continue;
if (errno == 0)
break;
dbg() << "read() failed: " << strerror(errno); dbg() << "read() failed: " << strerror(errno);
return; break;
} }
if (read_size == 0) if (read_size == 0)
break; break;
@ -733,12 +732,20 @@ RefPtr<Value> Execute::run(TheExecutionInputType input_value)
builder.append(StringView { buffer, 4096 - remaining_size }); builder.append(StringView { buffer, 4096 - remaining_size });
}; };
notifier->on_ready_to_read = [&] {
try_read();
};
run_commands(commands);
for (auto job : jobs_to_wait_for) { for (auto job : jobs_to_wait_for) {
shell->block_on_job(job); shell->block_on_job(job);
} }
notifier->on_ready_to_read = nullptr; notifier->on_ready_to_read = nullptr;
try_read();
if (close(pipefd[0]) < 0) { if (close(pipefd[0]) < 0) {
dbg() << "close() failed: " << strerror(errno); dbg() << "close() failed: " << strerror(errno);
} }

View file

@ -124,6 +124,7 @@ struct Command {
Vector<NonnullRefPtr<Redirection>> redirections; Vector<NonnullRefPtr<Redirection>> redirections;
bool should_wait { true }; bool should_wait { true };
bool is_pipe_source { false }; bool is_pipe_source { false };
bool should_notify_if_in_background { true };
}; };
struct HitTestResult { struct HitTestResult {
@ -155,7 +156,7 @@ public:
} }
CommandValue(Vector<String> argv) CommandValue(Vector<String> argv)
: m_command({ move(argv), {}, true, false }) : m_command({ move(argv), {}, true, false, true })
{ {
} }
@ -245,8 +246,6 @@ class SimpleVariableValue final : public Value {
public: public:
virtual Vector<String> resolve_as_list(TheExecutionInputType) override; virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
virtual ~SimpleVariableValue(); virtual ~SimpleVariableValue();
// FIXME: Should override is_list and is_string,
// as it might have different types of values.
SimpleVariableValue(String name) SimpleVariableValue(String name)
: m_name(name) : m_name(name)
{ {
@ -260,8 +259,6 @@ class SpecialVariableValue final : public Value {
public: public:
virtual Vector<String> resolve_as_list(TheExecutionInputType) override; virtual Vector<String> resolve_as_list(TheExecutionInputType) override;
virtual ~SpecialVariableValue(); virtual ~SpecialVariableValue();
// FIXME: Should override is_list and is_string,
// as it might have different types of values.
SpecialVariableValue(char name) SpecialVariableValue(char name)
: m_name(name) : m_name(name)
{ {

View file

@ -633,18 +633,24 @@ RefPtr<AST::Node> Parser::parse_evaluate()
return nullptr; return nullptr;
consume(); consume();
if (peek() == '(') {
consume();
auto inner = parse_pipe_sequence();
if (!inner || !expect(')'))
inner = create<AST::SyntaxError>();
else
inner = create<AST::Execute>(move(inner), true);
return inner;
}
auto inner = parse_expression(); auto inner = parse_expression();
if (!inner) { if (!inner) {
inner = create<AST::SyntaxError>(); inner = create<AST::SyntaxError>();
} else { } else {
if (inner->is_list()) { if (inner->is_list()) {
auto execute_inner = create<AST::Execute>(move(inner)); auto execute_inner = create<AST::Execute>(move(inner), true);
execute_inner->capture_stdout();
inner = execute_inner; inner = execute_inner;
} else { } else {
// Trying to evaluate something other than a list
// FIXME: This bit be dynamic, what do?
auto dyn_inner = create<AST::DynamicEvaluate>(move(inner)); auto dyn_inner = create<AST::DynamicEvaluate>(move(inner));
inner = dyn_inner; inner = dyn_inner;
} }

View file

@ -125,7 +125,8 @@ expression :: evaluate expression?
| comment expession? | comment expession?
| '(' list_expression ')' expression? | '(' list_expression ')' expression?
evaluate :: '$' expression {eval / dynamic resolve} evaluate :: '$' '(' pipe_sequence ')'
| '$' expression {eval / dynamic resolve}
string_composite :: string string_composite? string_composite :: string string_composite?
| variable string_composite? | variable string_composite?