49bb38d619e7ab0e06b7d0fc09169b0fd0a9f7b2 — Simon Ser 2 months ago 2ee0faf
Introduce job_set_foreground
5 files changed, 32 insertions(+), 7 deletions(-)

M include/mrsh/shell.h
M include/shell/job.h
M shell/job.c
M shell/task/command_process.c
M shell/task/task.c
M include/mrsh/shell.h => include/mrsh/shell.h +1 -0
@@ 98,6 98,7 @@ pid_t pgid;
  	struct termios term_modes;
  	struct mrsh_array jobs; // struct mrsh_job *
+ 	struct mrsh_job *foreground_job;
  };
  
  void mrsh_function_destroy(struct mrsh_function *fn);

M include/shell/job.h => include/shell/job.h +3 -0
@@ 4,6 4,7 @@ #include <mrsh/array.h>
  #include <stdbool.h>
  #include <sys/types.h>
+ #include <termios.h>
  
  struct mrsh_state;
  struct process;


@@ 14,6 15,7 @@ */
  struct mrsh_job {
  	pid_t pgid;
+ 	struct termios term_modes;
  	struct mrsh_state *state;
  	struct mrsh_array processes; // struct process *
  };


@@ 22,6 24,7 @@ void job_destroy(struct mrsh_job *job);
  void job_add_process(struct mrsh_job *job, struct process *proc);
  bool job_terminated(struct mrsh_job *job);
+ void job_set_foreground(struct mrsh_job *job, bool foreground);
  
  bool init_job_child_process(struct mrsh_state *state);
  void update_job(struct mrsh_state *state, pid_t pid, int stat);

M shell/job.c => shell/job.c +23 -0
@@ 94,6 94,10 @@ return;
  	}
  
+ 	if (job->state->foreground_job == job) {
+ 		job_set_foreground(job, false);
+ 	}
+ 
  	struct mrsh_state *state = job->state;
  	for (size_t i = 0; i < state->jobs.len; ++i) {
  		if (state->jobs.data[i] == job) {


@@ 123,6 127,25 @@ return true;
  }
  
+ void job_set_foreground(struct mrsh_job *job, bool foreground) {
+ 	struct mrsh_state *state = job->state;
+ 
+ 	if (foreground && state->foreground_job != job) {
+ 		assert(state->foreground_job == NULL);
+ 		tcsetpgrp(state->fd, job->pgid);
+ 		state->foreground_job = job;
+ 	}
+ 
+ 	if (!foreground && state->foreground_job == job) {
+ 		// Put the shell back in the foreground
+ 		tcsetpgrp(state->fd, state->pgid);
+ 		// Restore the shell’s terminal modes
+ 		tcgetattr(state->fd, &job->term_modes);
+ 		tcsetattr(state->fd, TCSADRAIN, &state->term_modes);
+ 		state->foreground_job = NULL;
+ 	}
+ }
+ 
  bool init_job_child_process(struct mrsh_state *state) {
  	if (!state->job_control) {
  		return true;

M shell/task/command_process.c => shell/task/command_process.c +2 -2
@@ 43,7 43,7 @@ } else if (pid == 0) {
  		struct mrsh_job *job = put_into_process_group(ctx, getpid());
  		if (ctx->state->interactive && !ctx->background) {
- 			tcsetpgrp(ctx->state->fd, job->pgid);
+ 			job_set_foreground(job, true);
  		}
  		init_job_child_process(ctx->state);
  


@@ 95,7 95,7 @@   	struct mrsh_job *job = put_into_process_group(ctx, pid);
  	if (ctx->state->interactive && !ctx->background) {
- 		tcsetpgrp(ctx->state->fd, job->pgid);
+ 		job_set_foreground(job, true);
  	}
  
  	tc->process = process_create(ctx->state, pid);

M shell/task/task.c => shell/task/task.c +3 -5
@@ 53,11 53,9 @@ ctx->state->exit = ret;
  			}
  
- 			// Put the shell back in the foreground
- 			tcsetpgrp(ctx->state->fd, ctx->state->pgid);
- 			// Restore the shell’s terminal modes
- 			// tcgetattr(ctx->state->fd, &job->term_modes); // TODO
- 			tcsetattr(ctx->state->fd, TCSADRAIN, &ctx->state->term_modes);
+ 			if (ctx->state->foreground_job != NULL) {
+ 				job_set_foreground(ctx->state->foreground_job, false);
+ 			}
  
  			destroy_finished_jobs(ctx->state);