Browse Source

Finished initial command execution functions (NEED IMPL MEMORY CLEAN-UP!!!)

Ivan Arkhipov 4 years ago
parent
commit
2d197b91a0
7 changed files with 166 additions and 16 deletions
  1. 34 2
      esh_init.c
  2. 6 0
      esh_init.h
  3. 97 7
      esh_main_loop.c
  4. 5 1
      esh_main_loop.h
  5. 6 5
      esh_misc.c
  6. 2 0
      esh_misc.h
  7. 16 1
      esh_types.h

+ 34 - 2
esh_init.c

@@ -64,9 +64,9 @@ void EShInitInfo(int argc, char** argv) {
 
 	esh_info_global->max_jobs_number = 64;
 
-	esh_info_global->max_command_length = 4096;
+	esh_info_global->max_command_length = 512;
 
-	esh_info_global->max_command_tokens = 256;
+	esh_info_global->max_command_tokens = 16;
 
 	esh_info_global->max_command_token_size = 256;
 
@@ -175,4 +175,36 @@ void EShProcessHistoryFile() {
     }
 
 	fclose(file);
+}
+
+
+void EShInitJob(EShJob* job) {
+	job->command = malloc(esh_info_global->max_command_length);
+	memset(job->command, 0, esh_info_global->max_command_length);
+
+	job->command_tokens = malloc(esh_info_global->max_command_tokens * sizeof(char*));
+	for (int i = 0; i < esh_info_global->max_command_tokens; ++i) {
+		job->command_tokens[i] = malloc(esh_info_global->max_command_token_size);
+		memset(job->command_tokens[i], 0, esh_info_global->max_command_token_size);
+	}
+	job->command_tokens_num = 0;
+
+	job->command_type = EXEC_CMD;
+	job->job_type = FOREGROUND;
+	job->job_start_condition = NO_CONDITION;
+
+	job->job_pid = -1;
+
+	job->job_stdin = NULL;
+	job->job_stdout = NULL;
+	job->job_stderr = NULL;
+}
+
+
+EShJob* EShMakeJobsList() {
+	EShJob* jobs_list = malloc(esh_info_global->max_jobs_number * sizeof(EShJob));
+	for (int i = 0; i < esh_info_global->max_jobs_number; ++i) {
+		EShInitJob(&jobs_list[i]);
+	} 
+	return jobs_list;
 }

+ 6 - 0
esh_init.h

@@ -1,3 +1,5 @@
+#include "esh_types.h"
+
 #ifndef ESH_INIT_H
 #define ESH_INIT_H
 
@@ -11,4 +13,8 @@ void EShProcessConfigFile();
 
 void EShProcessHistoryFile();
 
+void EShInitJob(EShJob* job);
+
+EShJob* EShMakeJobsList();
+
 #endif // ESH_INIT_H

+ 97 - 7
esh_main_loop.c

@@ -1,12 +1,13 @@
 #include "esh_main_loop.h"
 #include "esh_misc.h"
 #include "esh_history.h"
+#include "esh_init.h"
 
 void EShRunLoop() {
     struct termios orig_term_attr;
     struct termios new_term_attr;
 
-    /* set the terminal to raw mode */
+    /* set the terminal to semi-raw mode */
     tcgetattr(fileno(stdin), &orig_term_attr);
     memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
     new_term_attr.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
@@ -182,9 +183,10 @@ void EShRunLoop() {
 		EShAddCommandToHistory(command);
 		
 		EShJob* jobs;
-		int jobs_num;
+		int jobs_num = 0;
 
-		EShParseCommandIntoJobs(command, &jobs, &jobs_num);
+		jobs = EShParseCommandIntoJobs(command, &jobs_num);
+		// EShPrintJobsDebugInfo(command, jobs, jobs_num);
 		EShExecuteJobs(jobs_num, jobs);
 	}
 
@@ -197,13 +199,80 @@ void EShShowMsg() {
 	printf("%s", esh_info_global->invite_message);
 }
 
-void EShParseCommandIntoJobs(char* command, EShJob** jobs_ptr, int* jobs_num_ptr) {
+EShJob* EShParseCommandIntoJobs(char* command, int* jobs_num) {
+	EShJob* jobs = EShMakeJobsList();
 
+	*jobs_num = 1;
+	int current_job_cmd_length = 0;
+
+	for (int i = 0; i < strlen(command); ++i) {
+		ESH_JOB_DELIMITER delimiter = EshIsJobDelimiter(command + i);
+
+		if (delimiter != NOT_A_DELIMITER) {
+			EShSplitJobCommand(&jobs[*jobs_num - 1], ' ');
+
+			if (delimiter == SEMICOLON) {
+				jobs[*jobs_num].job_start_condition = NO_CONDITION;
+			}
+
+			if (delimiter == LOGIC_AND) {
+				jobs[*jobs_num].job_start_condition = PREVIOUS_EXIT_SUCCESS;
+			}
+
+			if (delimiter == LOGIC_OR) {
+				jobs[*jobs_num].job_start_condition = PREVIOUS_EXIT_FAILED;
+			}
+
+			// TODO: delimiter == BIT_OR and BIT_AND
+			
+			++(*jobs_num);
+			current_job_cmd_length = 0;
+
+			i += EShGetJobDelimiterSize(EshIsJobDelimiter(command + i)) - 1;
+			continue;
+		}
+
+		jobs[*jobs_num - 1].command[current_job_cmd_length] = command[i];
+		++current_job_cmd_length;
+	}
+
+	EShSplitJobCommand(&jobs[*jobs_num - 1], ' ');
+	return jobs;
+}
+
+void EShSplitJobCommand(EShJob* job, char delim) {
+	int token_status = 0; // 0 - token result[result_size] finished
+					      // 1 - token result[result_size] not finished
+	int current_token_length = 0;
+	for (int i = 0; i < strlen(job->command); ++i) {
+		while (job->command[i] == delim && i < strlen(job->command)) {
+			if (token_status == 1) {
+				token_status = 0;
+			}
+			++i;
+		}
+
+		if (i == strlen(job->command)) {
+			if (token_status == 1) {
+				++job->command_tokens_num;
+			}
+			break;
+		}
+
+		if (token_status == 0) {
+			token_status = 1;
+			++job->command_tokens_num;
+			current_token_length = 0;
+		}
+
+		job->command_tokens[job->command_tokens_num - 1][current_token_length] = job->command[i];
+		++current_token_length;
+	}
 }
 
 void EShExecuteJobs(int jobs_num, EShJob* jobs_list) {
 	for (int i = 0;  i < jobs_num; ++i) {
-		EShRunJob(jobs_list[i]);
+		EShRunJob(&jobs_list[i]);
 	}
 }
 
@@ -213,10 +282,14 @@ void EShSetJobCommandType(EShJob* job) {
 
 void EShRunJob(EShJob* job) {
 	// TODO: PIPES INIT & BG PROCESS SUPPORT
-
 	int pid = fork();
 	if (pid == 0) {
-		execvp(job->command[0], job->command);
+		for (int i = job->command_tokens_num; i < esh_info_global->max_command_tokens; ++i) {
+			free(job->command_tokens[i]);
+			job->command_tokens[i] = NULL;
+		}
+
+		execvp(job->command_tokens[0], job->command_tokens);
 		printf("Esh: run command %s failed.\n", job->command);
 		exit(1); // execlp failed
 	} else {
@@ -240,3 +313,20 @@ void EShProcessInnerJob(const char* command) {
 void EShProcessExecJob(const char* command) {
 	
 }
+
+void EShPrintJobsDebugInfo(const char* command, EShJob* jobs, int jobs_num) {
+	printf("\nD: Splitted command (%s) into %d jobs:\n", command, jobs_num);
+	for (int i = 0; i < jobs_num; ++i) {
+		printf("===================\n"
+			   "Job #%d:\n"
+			   "Cmd: %s\n"
+			   "Cmd tokens: %d ", 
+			   i, jobs[i].command, jobs[i].command_tokens_num);
+
+		for (int j = 0; j < jobs[i].command_tokens_num; ++j) {
+			printf("{%s} ", jobs[i].command_tokens[j]);
+		}
+		printf("\n===================\n");
+	}
+	printf("\n");
+}

+ 5 - 1
esh_main_loop.h

@@ -7,7 +7,9 @@ void EShRunLoop();
 
 void EShShowMsg();
 
-void EShParseCommandIntoJobs(char* command);
+EShJob* EShParseCommandIntoJobs(char* command, int* jobs_num);
+
+void EShSplitJobCommand(EShJob* job, char delim);  // splits command into tokens (command arguments)
 
 void EShExecuteJobs(int jobs_num, EShJob* jobs_list);
 
@@ -23,4 +25,6 @@ void EShProcessInnerJob(const char* command);
 
 void EShProcessExecJob(const char* command);
 
+void EShPrintJobsDebugInfo(const char* command, EShJob* jobs, int jobs_num);
+
 #endif // ESH_MAIN_LOOP_H

+ 6 - 5
esh_misc.c

@@ -50,7 +50,8 @@ int EShIsShellLetter(char c) { // TODO: Russian symbols
 		   (c >= 'A' && c <= 'Z') || 
 		   (c >= '0' && c <= '9') || 
 		   (c >= ' ' && c <= '/') ||
-		   (c >= ':' && c <= '?');
+		   (c >= ':' && c <= '?') || 
+		   (c == '|');
 } 
 
 ESH_JOB_DELIMITER EshIsJobDelimiter(char* c) {
@@ -63,14 +64,14 @@ ESH_JOB_DELIMITER EshIsJobDelimiter(char* c) {
     }
 
     if (strstr(c, "&") == c) {
-    	return LOGIC_AND;
+    	return BIT_AND;
     }
 
     if (strstr(c, "|") == c) {
     	return BIT_OR;
     }
 
-    if (strstr(c, ";") == c) {
+    if (strstr(c, ";") == c || strstr(c, "\n") == c) {
     	return SEMICOLON;
     }
 
@@ -82,10 +83,10 @@ int EShGetJobDelimiterSize(ESH_JOB_DELIMITER delim) {
 		return 2;
 	}
 
-	if (delim == BIT_OR || delim == LOGIC_AND || delim == SEMICOLON) {
+	if (delim == BIT_AND || delim == BIT_OR || delim == SEMICOLON) {
 		return 1;
 	}
-	
+
 	return 0;
 }
 

+ 2 - 0
esh_misc.h

@@ -21,4 +21,6 @@ int EShIsShellLetter(char c); // Returns 1 if c is 'good' char (not a command ch
 
 ESH_JOB_DELIMITER EshIsJobDelimiter(char* c);
 
+int EShGetJobDelimiterSize(ESH_JOB_DELIMITER delim);
+
 #endif // ESH_MISC_H

+ 16 - 1
esh_types.h

@@ -29,8 +29,19 @@ typedef enum {
 	PREVIOUS_EXIT_FAILED // ex. commands delimited by '||'
 } ESH_JOB_CONDITION;
 
+typedef enum {
+	LOGIC_AND = 1,
+	LOGIC_OR = 2,
+	SEMICOLON = 3,
+	BIT_AND = 4,
+	BIT_OR = 5,
+	NOT_A_DELIMITER = 0
+} ESH_JOB_DELIMITER;
+
 typedef struct {
-	char** command;
+	char* command;
+	char** command_tokens;
+	int command_tokens_num;
 
 	ESH_COMMAND_TYPE command_type;
 	ESH_JOB_TYPE job_type;
@@ -55,8 +66,12 @@ typedef struct {
 	char* config_file_path; // path to file, containing configurations (changeable via cmd line args)
 	char* history_file_path; // path to file, where entered commands history is stored (changeable via settings/cmd line args)
 	int history_limit; // max lines of commands, which can be stored (changeable via settings/cmd line args)
+	// TODO: set this to max background jobs limit!
 	int max_jobs_number; // max active jobs (foreground & background) limit (changeable via settings/cmd line args)
 	int max_command_length; // max length of single command (changeable via settings/cmd line args)
+	
+	int max_command_tokens; // TODO: max arguments of single command
+	int max_command_token_size; // TODO
 
 	char** history_command_list;
 	int history_command_list_size;