diff --git a/ce/interp.c b/ce/interp.c index c20a00d..15d916e 100644 --- a/ce/interp.c +++ b/ce/interp.c @@ -370,7 +370,7 @@ static void cmd_write_proc (void* arg) { } } -static void execute_cmd (struct ast_cmd* cmd, struct context* context) { +static void execute_cmd (struct ast_cmd* cmd, struct context* context, bool run_bg) { if (strcmp (cmd->name, "echo") == 0) { echo (context, cmd->args, cmd->arg_count); } else if (strcmp (cmd->name, "help") == 0) { @@ -444,18 +444,25 @@ static void execute_cmd (struct ast_cmd* cmd, struct context* context) { i++; } - struct cmd_write_proc_ctx wpctx = {.pgid = pgid, .cancel_pid = pid}; + if (run_bg) { + exec_partial_fini (pid); - struct process_data* write_pdata = process_spawn (&cmd_write_proc, (void*)&wpctx); - struct process_data* collect_pdata = process_spawn (&cmd_collect_proc, (void*)(uintptr_t)pgid); + cprintf (context, "started background process: PID %d\n", pid); + } else { + struct cmd_write_proc_ctx wpctx = {.pgid = pgid, .cancel_pid = pid}; - exec_partial_fini (pid); - wait_for_pid (pid); + struct process_data* write_pdata = process_spawn (&cmd_write_proc, (void*)&wpctx); + struct process_data* collect_pdata = + process_spawn (&cmd_collect_proc, (void*)(uintptr_t)pgid); - kill (write_pdata->pid); - process_data_free (write_pdata); - kill (collect_pdata->pid); - process_data_free (collect_pdata); + exec_partial_fini (pid); + wait_for_pid (pid); + + kill (write_pdata->pid); + process_data_free (write_pdata); + kill (collect_pdata->pid); + process_data_free (collect_pdata); + } } } @@ -507,24 +514,27 @@ static void execute_redir (struct ast_redir* redir, struct context* context) { filewriter_fini (&fw); } -void execute (struct ast_node* root, struct context* context) { +void execute (struct ast_node* root, struct context* context, bool run_bg) { struct context subcontext; memset (&subcontext, 0, sizeof (subcontext)); switch (root->class) { case AST_NODE_CLASS_CMD: - execute_cmd (&root->u.cmd, context); + execute_cmd (&root->u.cmd, context, run_bg); break; case AST_NODE_CLASS_SUBSHELL: - execute (root->u.subshell.inner, &subcontext); + execute (root->u.subshell.inner, &subcontext, run_bg); break; case AST_NODE_CLASS_SEQ: - execute (root->u.seq.left, context); - execute (root->u.seq.right, context); + execute (root->u.seq.left, context, run_bg); + execute (root->u.seq.right, context, run_bg); break; case AST_NODE_CLASS_REDIR: - execute (root->u.redir.source, &subcontext); + execute (root->u.redir.source, &subcontext, run_bg); execute_redir (&root->u.redir, &subcontext); break; + case AST_NODE_CLASS_RUN_BG: + execute (root->u.run_bg.expr, context, true); + break; } } diff --git a/ce/interp.h b/ce/interp.h index cf4500f..d00829b 100644 --- a/ce/interp.h +++ b/ce/interp.h @@ -5,7 +5,7 @@ #include "parser.h" #include -void execute (struct ast_node* root, struct context* context); +void execute (struct ast_node* root, struct context* context, bool run_bg); bool interp_is_running (void); diff --git a/ce/parser.c b/ce/parser.c index c89766b..6dc1c45 100644 --- a/ce/parser.c +++ b/ce/parser.c @@ -13,6 +13,7 @@ static struct parse_rule parse_rules[] = { [TOKEN_CLASS_CPAREN] = {NULL, NULL, PREC_NONE}, [TOKEN_CLASS_SEMICOLON] = {NULL, &semicolon_led, PREC_SEQ}, [TOKEN_CLASS_REDIR] = {NULL, &redir_led, PREC_REDIR}, + [TOKEN_CLASS_AMPERSAND] = {NULL, &run_bg_led, PREC_RUN_BG}, }; static struct token* get_token (struct list_node_link* link) { @@ -114,6 +115,16 @@ struct ast_node* redir_led (struct parser* parser, struct token* token, struct a return node; } +struct ast_node* run_bg_led (struct parser* parser, struct token* token, struct ast_node* left) { + (void)token; + + struct ast_node* node = arena_malloc (&arena, sizeof (*node)); + node->class = AST_NODE_CLASS_RUN_BG; + node->u.run_bg.expr = left; + + return node; +} + void tokenize (struct list_node_link** tokens, const char* text) { const char* p = text; @@ -123,7 +134,7 @@ void tokenize (struct list_node_link** tokens, const char* text) { continue; } - if (*p == '(' || *p == ')' || *p == ';' || *p == '>') { + if (*p == '(' || *p == ')' || *p == ';' || *p == '>' || *p == '&') { struct token* token = arena_malloc (&arena, sizeof (*token)); memset (token, 0, sizeof (*token)); @@ -136,6 +147,8 @@ void tokenize (struct list_node_link** tokens, const char* text) { token->class = TOKEN_CLASS_SEMICOLON; else if (*p == '>') token->class = TOKEN_CLASS_REDIR; + else if (*p == '&') + token->class = TOKEN_CLASS_AMPERSAND; list_append (*tokens, &token->tokens_link); p++; @@ -174,7 +187,7 @@ void parse_and_execute (struct list_node_link* tokens) { if (root != NULL) { struct context context; memset (&context, 0, sizeof (context)); - execute (root, &context); + execute (root, &context, false); if (context.strbuf.items != NULL) mprintf ("%.*s", (int)context.strbuf.count, context.strbuf.items); diff --git a/ce/parser.h b/ce/parser.h index 6019ab6..15e0826 100644 --- a/ce/parser.h +++ b/ce/parser.h @@ -11,6 +11,7 @@ #define TOKEN_CLASS_WORD 2 #define TOKEN_CLASS_SEMICOLON 3 #define TOKEN_CLASS_REDIR 4 +#define TOKEN_CLASS_AMPERSAND 5 struct token { struct list_node_link tokens_link; @@ -22,11 +23,13 @@ struct token { #define PREC_LOWEST 1 #define PREC_SEQ 2 #define PREC_REDIR 3 +#define PREC_RUN_BG 4 #define AST_NODE_CLASS_CMD 0 #define AST_NODE_CLASS_SUBSHELL 1 #define AST_NODE_CLASS_SEQ 2 #define AST_NODE_CLASS_REDIR 3 +#define AST_NODE_CLASS_RUN_BG 4 struct ast_node; @@ -50,6 +53,10 @@ struct ast_redir { char* file_path; }; +struct ast_run_bg { + struct ast_node* expr; +}; + struct ast_node { int class; union { @@ -57,6 +64,7 @@ struct ast_node { struct ast_subshell subshell; struct ast_seq seq; struct ast_redir redir; + struct ast_run_bg run_bg; } u; }; @@ -85,6 +93,8 @@ struct ast_node* semicolon_led (struct parser* parser, struct token* token, stru struct ast_node* redir_led (struct parser* parser, struct token* token, struct ast_node* left); +struct ast_node* run_bg_led (struct parser* parser, struct token* token, struct ast_node* left); + void tokenize (struct list_node_link** tokens, const char* text); void parse_and_execute (struct list_node_link* tokens);