#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_COMMAND_LENGTH 510
#define MAX_ARGUMENTS 10
typedef struct {
char *name;
char *value;
} CommandVariable;
CommandVariable *command_variables = NULL;
int num_command_variables = 0;
int total_commands = 0;
int total_args = 0;
void add_command_variable(const char *name, const char *value) {
CommandVariable *new_variable = (CommandVariable *) malloc(sizeof(CommandVariable));
new_variable->name = strdup(name);
new_variable->value = strdup(value);
command_variables = (CommandVariable *) realloc(command_variables, (num_command_variables + 1) * sizeof(CommandVariable));
command_variables[num_command_variables++] = *new_variable;
free(new_variable);
}
void replaceSubstring(char *str, const char *oldSubstr, const char *newSubstr) {
int i, j, k;
int oldSubstrLen = strlen(oldSubstr);
int newSubstrLen = strlen(newSubstr);
int strLen = strlen(str);
int replaced = 0;
// Loop through the string
for (i = 0; i <= strLen - oldSubstrLen && !replaced; ) {
j = 0;
// Check if current substring matches oldSubstr
while (j < oldSubstrLen && str[i + j] == oldSubstr[j]) {
j++;
}
// If oldSubstr is found, replace it with newSubstr
if (j == oldSubstrLen) {
// Allocate memory for the new string with enough space for newSubstr
char *newStr = (char *)malloc((strLen - oldSubstrLen + newSubstrLen + 1) * sizeof(char));
if (newStr == NULL) {
// Handle memory allocation error
printf("Error: Memory allocation failed\n");
return;
}
// Copy the original string up to the replaced substring to newStr
strncpy(newStr, str, i);
newStr[i] = '\0'; // Null-terminate the new string
// Concatenate newSubstr to newStr
strcat(newStr, newSubstr);
// Concatenate the rest of the original string after the replaced substring to newStr
strcat(newStr, str + i + oldSubstrLen);
// Copy the new string back to the original string
strcpy(str, newStr);
// Free memory allocated for newStr
free(newStr);
replaced = 1;
} else {
// Move the pointer i to the next character
i++;
}
}
}
void execute_command(char *command) {
char *arguments[MAX_ARGUMENTS + 1]; // extra slot for NULL pointer
int arg_count = 0;
char *outer_delim = ";";
char *inner_delim = " ";
char *outer_token, *inner_token, *outer_saveptr, *inner_saveptr;
outer_token = strtok_r(command, outer_delim, &outer_saveptr);
while (outer_token != NULL) {
total_commands++;
char name1[MAX_COMMAND_LENGTH];
char value1[MAX_COMMAND_LENGTH];
if (sscanf(outer_token, "%[^=]=%[^\n]", name1, value1) == 2) {
add_command_variable(name1, value1);
outer_token = strtok_r(NULL, outer_delim, &outer_saveptr);
continue;
}
char *key = outer_token;
while((key = strchr(key, '$')) != NULL){
int i ;
int j = -1;
int len = 0;
for(i =0; i<num_command_variables;i++) {
char *help = key+1;
char *str = command_variables[i].name;
if (strstr(help, str) != NULL || strcmp(help, str) == 0) {
//shell> va=emanuel; var=malloul ; echo "$va $var"
if (len < strlen(command_variables[i].name)) {
len = strlen(command_variables[i].name);
j = i;
}
}
}
if (j != -1) {
char s[strlen(command_variables[j].name) + 3 + 1]; // +1 for null terminator
strcpy(s, "$");
strcat(s, command_variables[j].name);
replaceSubstring(outer_token, s, command_variables[j].value);
key = outer_token;
}
}
inner_token = strtok_r(outer_token, inner_delim, &inner_saveptr);
while (inner_token != NULL) {
total_args++;
if(arg_count > MAX_ARGUMENTS){
printf("Too many arguments\n");
total_args = total_args - arg_count; //total legal amount of commands and args
total_commands--;
outer_token = strtok_r(NULL, outer_delim, &outer_saveptr);
continue;
}
if(inner_token[0]=='"' ){
char *s = malloc(strlen(inner_token)+1);
strcpy(s, inner_token+1);
if(strchr(s,'"')){
s[strlen(s)-1] = '\0';
arguments[arg_count] = s;
}else {
inner_token = strtok_r(NULL, inner_delim, &inner_saveptr);
while (inner_token != NULL) {
s = realloc(s, strlen(s) + strlen(inner_token) + 2);
strcat(s, " ");
strcat(s, inner_token);
inner_token = strtok_r(NULL, inner_delim, &inner_saveptr);
}
s[strlen(s) - 1] = '\0';
arguments[arg_count] = s;
}
}else {
arguments[arg_count] = inner_token;
}
arg_count++;
inner_token = strtok_r(NULL, inner_delim, &inner_saveptr);
}
if (arg_count > 0) {
arguments[arg_count] = NULL; // NULL-terminate the argument list
pid_t pid = fork();
if (pid < 0) {
printf("Failed to fork\n");
return;
} else if (pid == 0) {
// child process
execvp(arguments[0], arguments);
printf("Failed to execute %s\n", arguments[0]);
exit(1);
} else {
// parent process
int status;
waitpid(pid, &status, 0);
}
}
arg_count = 0 ;
//fork
outer_token = strtok_r(NULL, outer_delim, &outer_saveptr);
}
}
int main(){
char command[MAX_COMMAND_LENGTH + 1];
int consecutive_enter_count = 0;
while (consecutive_enter_count < 3) {
printf("#cmd:%d|#args:%d@current dir> ",total_commands,total_args);
fflush(stdout); // flush stdout to ensure prompt is displayed
if (fgets(command, sizeof(command), stdin) == NULL) {
break; // error reading input
}
size_t len = strlen(command);
if (len == 0) {
consecutive_enter_count++;
} else if (command[len - 1] == '\n') {
command[len - 1] = '\0';
if (strlen(command) == 0) {
consecutive_enter_count++;
}else if (strcmp(command, "cd") == 0) {
printf("cd is not supported\n");
} else {
execute_command(command);
consecutive_enter_count =0;
}
} else {
// command too long
printf("Command too long\n");
while (fgets(command, sizeof(command), stdin) != NULL && command[strlen(command) - 1] != '\n') {
// flush remaining characters from input buffer
}
}
// check if consecutive enters count has reached 3
if (consecutive_enter_count == 3) {
break;
}
}
return 0;
}
发送此命令时
va=emanuel; var=malloul ; echo "$va $var"
预期输出为:
emanuel malloul
我的结果是:
emanuel emanuelr
Failed to execute manuelr
我总结了这个原因:Failed to execute manuelr”是delimeters similarity的问题。
文字背后的原因是:
emanuel emanuelr
是由于行:
if (strstr(help, str) != NULL || strcmp(help, str) == 0) {
当
str
是 var
和 help
是 var
时,由于未知原因未输入 if.
我已尽力解决这些问题,但没有成功。如果有人可以提供帮助,我们将不胜感激。