mirror of
https://github.com/RGBCube/serenity
synced 2025-05-23 18:05:08 +00:00
Shell: Parse a pipe sequence inside $(...)
This commit is contained in:
parent
8e078cf4ab
commit
42304d7bf1
4 changed files with 36 additions and 25 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue