Shell: Add append operator (>>)

Fixes #93.
This commit is contained in:
Robin Burchell 2019-05-26 00:38:11 +02:00 committed by Andreas Kling
parent c6e79bd53a
commit aee99b05a6
Notes: sideshowbarker 2024-07-19 13:56:58 +09:00
3 changed files with 72 additions and 37 deletions

View file

@ -60,7 +60,9 @@ Vector<Subcommand> Parser::parse()
if (ch == '>') { if (ch == '>') {
commit_token(); commit_token();
begin_redirect_write(STDOUT_FILENO); begin_redirect_write(STDOUT_FILENO);
m_state = State::InRedirectionPath;
// Search for another > for append.
m_state = State::InWriteAppendOrRedirectionPath;
break; break;
} }
if (ch == '<') { if (ch == '<') {
@ -79,6 +81,18 @@ Vector<Subcommand> Parser::parse()
} }
m_token.append(ch); m_token.append(ch);
break; break;
case State::InWriteAppendOrRedirectionPath:
if (ch == '>') {
commit_token();
m_state = State::InRedirectionPath;
ASSERT(m_redirections.size());
m_redirections[m_redirections.size() - 1].type = Redirection::FileWriteAppend;
break;
}
// Not another > means that it's probably a path.
m_state = InRedirectionPath;
[[fallthrough]];
case State::InRedirectionPath: case State::InRedirectionPath:
if (ch == '<') { if (ch == '<') {
commit_token(); commit_token();

View file

@ -4,7 +4,7 @@
#include <AK/Vector.h> #include <AK/Vector.h>
struct Redirection { struct Redirection {
enum Type { Pipe, FileWrite, FileRead, Rewire }; enum Type { Pipe, FileWrite, FileWriteAppend, FileRead, Rewire };
Type type; Type type;
int fd { -1 }; int fd { -1 };
int rewire_fd { -1 }; int rewire_fd { -1 };
@ -33,6 +33,7 @@ private:
Free, Free,
InSingleQuotes, InSingleQuotes,
InDoubleQuotes, InDoubleQuotes,
InWriteAppendOrRedirectionPath,
InRedirectionPath, InRedirectionPath,
}; };
State m_state { Free }; State m_state { Free };

View file

@ -233,24 +233,27 @@ static int run_command(const String& cmd)
#ifdef SH_DEBUG #ifdef SH_DEBUG
for (int i = 0; i < subcommands.size(); ++i) { for (int i = 0; i < subcommands.size(); ++i) {
for (int j = 0; j < i; ++j) for (int j = 0; j < i; ++j)
printf(" "); dbgprintf(" ");
for (auto& arg : subcommands[i].args) { for (auto& arg : subcommands[i].args) {
printf("<%s> ", arg.characters()); dbgprintf("<%s> ", arg.characters());
} }
printf("\n"); dbgprintf("\n");
for (auto& redirecton : subcommands[i].redirections) { for (auto& redirecton : subcommands[i].redirections) {
for (int j = 0; j < i; ++j) for (int j = 0; j < i; ++j)
printf(" "); dbgprintf(" ");
printf(" "); dbgprintf(" ");
switch (redirecton.type) { switch (redirecton.type) {
case Redirection::Pipe: case Redirection::Pipe:
printf("Pipe\n"); dbgprintf("Pipe\n");
break; break;
case Redirection::FileRead: case Redirection::FileRead:
printf("fd:%d = FileRead: %s\n", redirecton.fd, redirecton.path.characters()); dbgprintf("fd:%d = FileRead: %s\n", redirecton.fd, redirecton.path.characters());
break; break;
case Redirection::FileWrite: case Redirection::FileWrite:
printf("fd:%d = FileWrite: %s\n", redirecton.fd, redirecton.path.characters()); dbgprintf("fd:%d = FileWrite: %s\n", redirecton.fd, redirecton.path.characters());
break;
case Redirection::FileWriteAppend:
dbgprintf("fd:%d = FileWriteAppend: %s\n", redirecton.fd, redirecton.path.characters());
break; break;
default: default:
break; break;
@ -267,36 +270,53 @@ static int run_command(const String& cmd)
for (int i = 0; i < subcommands.size(); ++i) { for (int i = 0; i < subcommands.size(); ++i) {
auto& subcommand = subcommands[i]; auto& subcommand = subcommands[i];
for (auto& redirection : subcommand.redirections) { for (auto& redirection : subcommand.redirections) {
if (redirection.type == Redirection::Pipe) { switch (redirection.type) {
int pipefd[2]; case Redirection::Pipe: {
int rc = pipe(pipefd); int pipefd[2];
if (rc < 0) { int rc = pipe(pipefd);
perror("pipe"); if (rc < 0) {
return 1; perror("pipe");
return 1;
}
subcommand.redirections.append({ Redirection::Rewire, STDOUT_FILENO, pipefd[1] });
auto& next_command = subcommands[i + 1];
next_command.redirections.append({ Redirection::Rewire, STDIN_FILENO, pipefd[0] });
fds.add(pipefd[0]);
fds.add(pipefd[1]);
break;
} }
subcommand.redirections.append({ Redirection::Rewire, STDOUT_FILENO, pipefd[1] }); case Redirection::FileWriteAppend: {
auto& next_command = subcommands[i + 1]; int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT | O_APPEND, 0666);
next_command.redirections.append({ Redirection::Rewire, STDIN_FILENO, pipefd[0] }); if (fd < 0) {
fds.add(pipefd[0]); perror("open");
fds.add(pipefd[1]); return 1;
} }
if (redirection.type == Redirection::FileWrite) { subcommand.redirections.append({ Redirection::Rewire, redirection.fd, fd });
int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT, 0666); fds.add(fd);
if (fd < 0) { break;
perror("open");
return 1;
} }
subcommand.redirections.append({ Redirection::Rewire, redirection.fd, fd }); case Redirection::FileWrite: {
fds.add(fd); int fd = open(redirection.path.characters(), O_WRONLY | O_CREAT, 0666);
} if (fd < 0) {
if (redirection.type == Redirection::FileRead) { perror("open");
int fd = open(redirection.path.characters(), O_RDONLY); return 1;
if (fd < 0) { }
perror("open"); subcommand.redirections.append({ Redirection::Rewire, redirection.fd, fd });
return 1; fds.add(fd);
break;
} }
subcommand.redirections.append({ Redirection::Rewire, redirection.fd, fd }); case Redirection::FileRead: {
fds.add(fd); int fd = open(redirection.path.characters(), O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
subcommand.redirections.append({ Redirection::Rewire, redirection.fd, fd });
fds.add(fd);
break;
}
case Redirection::Rewire:
break; // ignore
} }
} }
} }