Browse Source

Added environment vars substitution support

Ivan Arkhipov 4 years ago
parent
commit
adb96532b6
6 changed files with 200 additions and 17 deletions
  1. 5 0
      esh_deinit.c
  2. 2 0
      esh_deinit.h
  3. 92 11
      esh_main_loop.c
  4. 5 5
      esh_main_loop.h
  5. 1 1
      esh_misc.c
  6. 95 0
      string_misc.h

+ 5 - 0
esh_deinit.c

@@ -1,5 +1,10 @@
 #include "esh_deinit.h"
 
+void EShExit(int exit_code) {
+	EShDeinit();
+	exit(exit_code);
+}
+
 void EShDeinit() {
 	EShSaveConfigFile();
 	EShSaveHistoryFile();

+ 2 - 0
esh_deinit.h

@@ -3,6 +3,8 @@
 #ifndef ESH_DEINIT_H
 #define ESH_DEINIT_H
 
+void EShExit(int exit_code);
+
 void EShDeinit();
 
 void EShDeinitInfo();

+ 92 - 11
esh_main_loop.c

@@ -4,6 +4,8 @@
 #include "esh_init.h"
 #include "esh_deinit.h"
 
+#include "string_misc.h"
+
 void EShRunLoop() {
     struct termios orig_term_attr;
     struct termios new_term_attr;
@@ -147,7 +149,6 @@ void EShRunLoop() {
 				continue;
 			}
 
-
 			if (input_char == 3) {
 				// Ctrl + c
 				printf("\n");
@@ -218,6 +219,16 @@ EShJob* EShParseCommandIntoJobs(char* command, int* jobs_num) {
 				jobs[*jobs_num].job_start_condition = PREVIOUS_EXIT_FAILED;
 			}
 
+			if (delimiter == BIT_AND) {
+				printf(ANSI_COLOR_RED "\nESh note: running processes in background is still not available, selected job will be running in foreground :(\n" ANSI_COLOR_RESET);
+				fflush(stdout);
+			}
+
+			if (delimiter == BIT_OR) {
+				printf(ANSI_COLOR_RED "\nESh note: running processes through pipes is still not available, you will need to enter data manually :(\n" ANSI_COLOR_RESET);
+				fflush(stdout);
+			}
+
 			// TODO: delimiter == BIT_OR and BIT_AND
 			
 			++(*jobs_num);
@@ -263,6 +274,10 @@ void EShSplitJobCommand(EShJob* job, char delim) {
 		job->command_tokens[job->command_tokens_num - 1][current_token_length] = job->command[i];
 		++current_token_length;
 	}
+
+	for (int i = 0; i < job->command_tokens_num; ++i) {
+		EShSubstituteShellValuesArgument(&job->command_tokens[i]);
+	}
 }
 
 void EShExecuteJobs(int jobs_num, EShJob* jobs_list) {
@@ -275,8 +290,44 @@ void EShSetJobCommandType(EShJob* job) {
 
 }
 
-void EShRunJob(EShJob* job) {
+int EShRunJob(EShJob* job) {
+	if (EShIsInnerJob(job)) {
+		EShProcessInnerJob(job);
+	} else {
+		EShProcessExecJob(job);
+	}
 	// TODO: PIPES INIT & BG PROCESS SUPPORT
+}
+
+int EShIsInnerJob(EShJob* job) {
+	return strcmp(job->command_tokens[0], "cd") == 0 ||
+		   strcmp(job->command_tokens[0], "exit") == 0;
+
+   // TODO: jobs, bg, fg (!)
+}
+
+int EShProcessInnerJob(EShJob* job) {
+	if (strcmp(job->command_tokens[0], "cd") == 0) {
+
+		if (job->command_tokens_num < 2) {
+			printf(ANSI_COLOR_RED "Esh: cannot change directory, no directory specified.\n" ANSI_COLOR_RESET, job->command);
+			fflush(stdout);
+		}
+
+		chdir(job->command_tokens[1]);
+		getcwd(esh_info_global->current_working_dir, PATH_MAX);
+		EShOptimiseCurrentWorkingDirectory();
+		EShUpdateInviteMessage();
+		return 0;
+	}
+
+	if (strcmp(job->command_tokens[0], "exit") == 0) {
+		EShExit(0);
+		return 0; // Actually, no need in it.
+	}
+}
+
+int EShProcessExecJob(EShJob* job) {
 	int pid = fork();
 	if (pid == 0) {
 		for (int i = job->command_tokens_num; i < esh_info_global->max_command_tokens; ++i) {
@@ -285,7 +336,8 @@ void EShRunJob(EShJob* job) {
 		}
 
 		execvp(job->command_tokens[0], job->command_tokens);
-		printf("Esh: run command %s failed.\n", job->command);
+		printf(ANSI_COLOR_RED "Esh: run command %s failed.\n" ANSI_COLOR_RESET, job->command);
+		fflush(stdout);
 		exit(1); // execlp failed
 	} else {
 		waitpid(pid, NULL, 0);
@@ -293,20 +345,49 @@ void EShRunJob(EShJob* job) {
 	}
 }
 
-int EmptyCommand(const char* command) {
 
-}
+void EShSubstituteShellValuesArgument(char** arg) {
+ 	// Processing tilda
+	// char* tilda_pos;
+	// while ((tilda_pos = strchr(arg, '~')) != NULL) {
+	// 	for (int i = strlen(arg); i > (tilda_pos - arg); --i) {
+	// 		arg[i + strlen(esh_info_global->user_data->pw_dir)] = arg[i];
+	// 	}
+	// 	memcpy(tilda_pos, esh_info_global->user_data->pw_dir, strlen(esh_info_global->user_data->pw_dir));
+	// }
 
-int InnerCommand(const char* command) {
+	char* new_str = *arg;
+	new_str = repl_str(new_str, "~", esh_info_global->user_data->pw_dir);
 
-}
+	// Processing system variables
+	
+	char* envvar_begin = new_str - 1;
+	while ((envvar_begin = strchr(envvar_begin + 1, '%')) != NULL) {
+		char* envvar_end = strchr(envvar_begin + 1, '%');
+		if (envvar_end == NULL)
+			break;
 
-void EShProcessInnerJob(const char* command) {
+		char envvar_name[1024 * 1024];
+		memset(envvar_name, 0, 1024 * 1024);
+		memcpy(envvar_name, envvar_begin + 1, (envvar_end - envvar_begin - 1));
 
-}
+		char* envvar_value = getenv(envvar_name);
 
-void EShProcessExecJob(const char* command) {
-	
+		if (envvar_value == NULL) {
+			continue;
+		}
+
+		char envvar_name_overed[1024 * 1024];
+		memset(envvar_name_overed, 0, 1024 * 1024);
+		strcat(envvar_name_overed, "%");
+		strcat(envvar_name_overed, envvar_name);
+		strcat(envvar_name_overed, "%");
+
+		new_str = repl_str(new_str, envvar_name_overed, envvar_value);
+	}
+
+	free(*arg);
+	*arg = new_str;
 }
 
 void EShPrintJobsDebugInfo(const char* command, EShJob* jobs, int jobs_num) {

+ 5 - 5
esh_main_loop.h

@@ -15,15 +15,15 @@ void EShExecuteJobs(int jobs_num, EShJob* jobs_list);
 
 void EShSetJobCommandType(EShJob* job);
 
-void EShRunJob(EShJob* job);
+int EShRunJob(EShJob* job); // returns exit code of job
 
-int EmptyCommand(const char* command);
+int EShIsInnerJob(EShJob* job);
 
-int InnerCommand(const char* command);
+int EShProcessInnerJob(EShJob* job);
 
-void EShProcessInnerJob(const char* command);
+int EShProcessExecJob(EShJob* job);
 
-void EShProcessExecJob(const char* command);
+void EShSubstituteShellValuesArgument(char** arg);
 
 void EShPrintJobsDebugInfo(const char* command, EShJob* jobs, int jobs_num);
 

+ 1 - 1
esh_misc.c

@@ -51,7 +51,7 @@ int EShIsShellLetter(char c) { // TODO: Russian symbols
 		   (c >= '0' && c <= '9') || 
 		   (c >= ' ' && c <= '/') ||
 		   (c >= ':' && c <= '?') || 
-		   (c == '|');
+		   (c == '|') || (c == '\\') || (c == '~');
 } 
 
 ESH_JOB_DELIMITER EshIsJobDelimiter(char* c) {

+ 95 - 0
string_misc.h

@@ -0,0 +1,95 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#ifndef STRING_MISC_H
+#define STRING_MISC_H
+
+#if (__STDC_VERSION__ >= 199901L)
+#include <stdint.h>
+#endif
+
+char *repl_str(const char *str, const char *from, const char *to) {
+	/* Adjust each of the below values to suit your needs. */
+
+	/* Increment positions cache size initially by this number. */
+	size_t cache_sz_inc = 16;
+	/* Thereafter, each time capacity needs to be increased,
+	 * multiply the increment by this factor. */
+	const size_t cache_sz_inc_factor = 3;
+	/* But never increment capacity by more than this number. */
+	const size_t cache_sz_inc_max = 1048576;
+
+	char *pret, *ret = NULL;
+	const char *pstr2, *pstr = str;
+	size_t i, count = 0;
+	#if (__STDC_VERSION__ >= 199901L)
+	uintptr_t *pos_cache_tmp, *pos_cache = NULL;
+	#else
+	ptrdiff_t *pos_cache_tmp, *pos_cache = NULL;
+	#endif
+	size_t cache_sz = 0;
+	size_t cpylen, orglen, retlen, tolen, fromlen = strlen(from);
+
+	/* Find all matches and cache their positions. */
+	while ((pstr2 = strstr(pstr, from)) != NULL) {
+		count++;
+
+		/* Increase the cache size when necessary. */
+		if (cache_sz < count) {
+			cache_sz += cache_sz_inc;
+			pos_cache_tmp = realloc(pos_cache, sizeof(*pos_cache) * cache_sz);
+			if (pos_cache_tmp == NULL) {
+				goto end_repl_str;
+			} else pos_cache = pos_cache_tmp;
+			cache_sz_inc *= cache_sz_inc_factor;
+			if (cache_sz_inc > cache_sz_inc_max) {
+				cache_sz_inc = cache_sz_inc_max;
+			}
+		}
+
+		pos_cache[count-1] = pstr2 - str;
+		pstr = pstr2 + fromlen;
+	}
+
+	orglen = pstr - str + strlen(pstr);
+
+	/* Allocate memory for the post-replacement string. */
+	if (count > 0) {
+		tolen = strlen(to);
+		retlen = orglen + (tolen - fromlen) * count;
+	} else	retlen = orglen;
+	ret = malloc(retlen + 1);
+	if (ret == NULL) {
+		goto end_repl_str;
+	}
+
+	if (count == 0) {
+		/* If no matches, then just duplicate the string. */
+		strcpy(ret, str);
+	} else {
+		/* Otherwise, duplicate the string whilst performing
+		 * the replacements using the position cache. */
+		pret = ret;
+		memcpy(pret, str, pos_cache[0]);
+		pret += pos_cache[0];
+		for (i = 0; i < count; i++) {
+			memcpy(pret, to, tolen);
+			pret += tolen;
+			pstr = str + pos_cache[i] + fromlen;
+			cpylen = (i == count-1 ? orglen : pos_cache[i+1]) - pos_cache[i] - fromlen;
+			memcpy(pret, pstr, cpylen);
+			pret += cpylen;
+		}
+		ret[retlen] = '\0';
+	}
+
+end_repl_str:
+	/* Free the cache and return the post-replacement string,
+	 * which will be NULL in the event of an error. */
+	free(pos_cache);
+	return ret;
+}
+
+
+#endif