aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-09-16 11:28:14 +0000
committer_ov4 <ov4@ov4.org>2026-09-16 11:28:14 +0000
commite489a2db5a1e56e66f6df12642ad8cfd988d4b30 (patch)
treeaafcb1d962e9ce24ddccf00aff82d0ed0804fc4c /src
parent165ead4adbf8494db82f7be35c6f8d52ac47ebef (diff)
implement subshell, and fix vector operator[] unvalid index
Diffstat (limited to 'src')
-rw-r--r--src/eval.cc88
-rw-r--r--src/lexer/ast.cc9
-rw-r--r--src/lexer/token.cc28
-rw-r--r--src/main.cc4
4 files changed, 106 insertions, 23 deletions
diff --git a/src/eval.cc b/src/eval.cc
index 0192ab7..6d16cf7 100644
--- a/src/eval.cc
+++ b/src/eval.cc
@@ -30,7 +30,7 @@ extern char **environ;
namespace ov4
{
-int eval_exe(string s, bool is_aync)
+int eval_exe(const string &s, bool is_aync)
{
loggerln("eval_exe: receive {}", s);
@@ -69,10 +69,13 @@ int eval_exe(string s, bool is_aync)
sigprocmask(SIG_SETMASK, &prev, nullptr);
- // program inside execve may use SIGTTIN/SIGTTOU so just restore in child
+ // program inside execve may use SIGTTIN/SIGTTOU
+ // so just restore in child
sigprocmask(SIG_UNBLOCK, &block_io, nullptr);
execve(cmd_c, argv, environ);
+ // execve: if success, never returns
+
wrap_eliminator(cmdline);
cout << cmdline << flush;
switch (errno)
@@ -135,12 +138,85 @@ int eval_exe(string s, bool is_aync)
return 0;
}
-int eval_tree_cd(size_t i, const T_lexer &lexer_instance)
+int eval_subshell(size_t i, const T_lexer &lexer_instance)
+{
+ println("eval_tree_cd: processing subshell");
+
+ // TODO: implement async
+ bool is_aync = false;
+
+ char cmdline[] = "subshell";
+
+ // block_io signals can stop shell
+ // when child is at foreground, parent shell is at background
+ sigprocmask(SIG_BLOCK, &block_io, nullptr);
+
+ sigset_t prev;
+ block_all(&prev);
+
+ shell_pgid = getpgid(0);
+ pid_t pid = fork();
+
+ if (pid == 0) // child
+ {
+ setpgid(0, 0);
+ if (!is_aync) // foreground
+ tcsetpgrp(tty_fd, getpgrp());
+
+ sigprocmask(SIG_SETMASK, &prev, nullptr);
+
+ // program inside execve may use SIGTTIN/SIGTTOU
+ // so just restore in child
+ sigprocmask(SIG_UNBLOCK, &block_io, nullptr);
+ eval_tree_cd(i, lexer_instance, true);
+ exit(0);
+ }
+
+ // parent
+
+ exit_required_pid = pid;
+
+ if (!is_aync) // foreground
+ {
+ addjob(pid, FG, cmdline);
+ sigset_t prev_with_sigchld_blocked = prev;
+ sigaddset(&prev_with_sigchld_blocked, SIGCHLD);
+ sigprocmask(SIG_SETMASK, &prev_with_sigchld_blocked, NULL);
+ waitfg(pid);
+ sigprocmask(SIG_SETMASK, &prev, NULL);
+
+ return exit_code;
+ }
+ else // background
+ {
+ addjob(pid, BG, cmdline);
+ sigprocmask(SIG_SETMASK, &prev, NULL);
+ cout << "[" << pid2jid(pid) << "] (" << pid << ") " << cmdline;
+
+ // POSIX:
+ // async command returns 0 immediately
+ // TODO: recurring async
+ return 0;
+ }
+}
+
+int eval_tree_cd(size_t i, const T_lexer &lexer_instance, bool inside_subshell)
{
// TODO: async
int ret = -1;
+ println("eval_tree_cd: processing {} subshell {}", i, (lexer_instance.ast[i].subshell ? "TRUE" : "FALSE"));
+
+ // if it's a subshell, and current AST's subshell status is not subshell
+ // (subshell should be forkerd already, then set inside_subshell = true)
+ // fork itself
+ if (lexer_instance.ast[i].subshell && !inside_subshell)
+ {
+ eval_subshell(i, lexer_instance);
+ return 0;
+ }
+
if (lexer_instance.ast[i].token_type == TEXT)
{
ret = eval_exe(lexer_instance.ast[i].command_text, false);
@@ -149,7 +225,7 @@ int eval_tree_cd(size_t i, const T_lexer &lexer_instance)
if (lexer_instance.ast[i].left != string::npos)
{
- ret = eval_tree_cd(lexer_instance.ast[i].left, lexer_instance);
+ ret = eval_tree_cd(lexer_instance.ast[i].left, lexer_instance, false);
}
if (lexer_instance.ast[i].right != string::npos)
@@ -157,7 +233,7 @@ int eval_tree_cd(size_t i, const T_lexer &lexer_instance)
if (lexer_instance.ast[i].token_type == LOGIC_AND && ret != 0) return ret;
if (lexer_instance.ast[i].token_type == LOGIC_OR && ret == 0) return ret;
- ret = eval_tree_cd(lexer_instance.ast[i].right, lexer_instance);
+ ret = eval_tree_cd(lexer_instance.ast[i].right, lexer_instance, false);
}
return ret;
}
@@ -190,7 +266,7 @@ void eval(char *cmdline)
return;
}
- eval_tree_cd(0, lexer_instance);
+ eval_tree_cd(0, lexer_instance, false);
return;
}
diff --git a/src/lexer/ast.cc b/src/lexer/ast.cc
index 292728b..da96c6f 100644
--- a/src/lexer/ast.cc
+++ b/src/lexer/ast.cc
@@ -65,10 +65,11 @@ void T_lexer::parse(size_t cmd_begin, size_t cmd_end, size_t ast_vec)
// if it's fully inside bracket
// then it's subshell
- loggerln("parse: left token type: {}, right: {}",
- magic_enum::enum_name(token[cmd_begin].token_type),
- magic_enum::enum_name(token[cmd_end-1].token_type));
- if (token[cmd_begin].token_type == LEFT_BRACKET && token[cmd_end-1].token_type == RIGHT_BRACKET)
+ if (cmd_begin != cmd_end)
+ loggerln("parse: left token type: {}, right: {}",
+ magic_enum::enum_name(token[cmd_begin].token_type),
+ magic_enum::enum_name(token[cmd_end-1].token_type));
+ if (cmd_begin != cmd_end && token[cmd_begin].token_type == LEFT_BRACKET && token[cmd_end-1].token_type == RIGHT_BRACKET)
{
ast[ast_vec].subshell = true;
loggerln("parse: detect subshell {}", ast_vec);
diff --git a/src/lexer/token.cc b/src/lexer/token.cc
index 317b456..ab9f263 100644
--- a/src/lexer/token.cc
+++ b/src/lexer/token.cc
@@ -12,6 +12,8 @@
using namespace std; // remove this
+constexpr bool TOKEN_DEBUG = false;
+
namespace ov4
{
@@ -43,7 +45,7 @@ void T_lexer::bracket_depth_changer(char c, int &bracket_depth)
if (c == '(')
{
bracket_depth++;
- loggerln("changed depth: {}", bracket_depth);
+ if constexpr (TOKEN_DEBUG) loggerln("changed depth: {}", bracket_depth);
return;
}
if (c == ')')
@@ -64,7 +66,7 @@ void T_lexer::bracket_depth_changer(char c, int &bracket_depth)
*/
bool T_lexer::token_continue(const string &s, char next)
{
- loggerln("token_continue: receiving {} {}", s, next);
+ if constexpr (TOKEN_DEBUG) loggerln("token_continue: receiving {} {}", s, next);
// s is empty, so next can be part of the token
if (s.size() == 0) return true;
@@ -95,7 +97,7 @@ bool T_lexer::token_continue(const string &s, char next)
}
else
{
- loggerln("symbol not found in map");
+ if constexpr (TOKEN_DEBUG) loggerln("symbol not found in map");
return false;
}
}
@@ -108,16 +110,16 @@ void T_lexer::token_push(const string &push_s, int bracket_depth, bool force_tex
string trimmed = trim(push_s);
if (trimmed == "") return;
- loggerln("finding {} in map", trimmed);
+ if constexpr (TOKEN_DEBUG) loggerln("finding {} in map", trimmed);
if (symbol_property.contains(trimmed) && !force_text) // symbol
{
- loggerln("token_push: adding symbol");
+ if constexpr (TOKEN_DEBUG) loggerln("token_push: adding symbol");
tmp.token_type = symbol_property.at(trimmed).enum_type;
}
else
{
- loggerln("token_push: adding text");
+ if constexpr (TOKEN_DEBUG) loggerln("token_push: adding text");
if (force_text)
trimmed = trim(trimmed, "\'\"");
tmp.token_type = TEXT;
@@ -145,32 +147,32 @@ int T_lexer::tokenizer(const string &s)
prev_str += c;
- loggerln("---");
- loggerln("prev_str .{}. next char {}", prev_str, s[i+1]);
+ if constexpr (TOKEN_DEBUG) loggerln("---");
+ if constexpr (TOKEN_DEBUG) loggerln("prev_str .{}. next char {}", prev_str, s[i+1]);
if (c == '\'' || c == '\"')
{
- loggerln("quotation");
+ if constexpr (TOKEN_DEBUG) loggerln("quotation");
// turn on GUARD
if (guard == GUARD_OFF)
{
guard = (c == '\'') ? GUARD_STRONG : GUARD_WEAK;
- loggerln("set guard {}", (c == '\'') ? "GUARD_STRONG" : "GUARD_WEAK");
+ if constexpr (TOKEN_DEBUG) loggerln("set guard {}", (c == '\'') ? "GUARD_STRONG" : "GUARD_WEAK");
continue;
}
// turn off
else if (guard == GUARD_STRONG && c == '\'')
{
guard = GUARD_OFF;
- loggerln("quitting strong guard");
+ if constexpr (TOKEN_DEBUG) loggerln("quitting strong guard");
force_text = true;
}
//turn off
else if (guard == GUARD_WEAK && c == '\"')
{
guard = GUARD_OFF;
- loggerln("quitting weak guard");
+ if constexpr (TOKEN_DEBUG) loggerln("quitting weak guard");
force_text = true;
} else
continue;
@@ -178,7 +180,7 @@ int T_lexer::tokenizer(const string &s)
// not quotation mark
else if ((guard == GUARD_STRONG || guard == GUARD_WEAK))
{
- loggerln("tokenizer: guarded, continue");
+ if constexpr (TOKEN_DEBUG) loggerln("tokenizer: guarded, continue");
continue;
}
diff --git a/src/main.cc b/src/main.cc
index a884f78..088b4ca 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -75,7 +75,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
exit(0);
}
+
/* Evaluate the command line */
+ // trim \n
+ if(cmdline[strlen(cmdline)-1] == '\n')
+ cmdline[strlen(cmdline)-1] = '\0';
eval(cmdline);
fflush(stdout);
fflush(stdout);