FENIX_coreutils/sh.c

129 lines
2.6 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <linux/limits.h>
#include <signal.h>
#include <libgen.h>
#define ARG_SEP " " //Argument separator for commands
#define PROMPT " $ "
char** create_argv(char* command);
int get_argc(char* command);
char* prompt();
int cd(char* path);
int main() {
char** argv; //The command with arguments
char* user_input;
pid_t child_pid;
int stat_loc; //??? (Needed for waitpid)
signal(SIGINT, SIG_IGN); //Tell vsh to ignore SIGINT (^C)
while(1) {
user_input = prompt();
argv = create_argv(user_input);
if(strcmp(argv[0], "cd") == 0) {
if(cd(&user_input[3]) < 0) {
perror(argv[1]);
}
//causes the fork to get skipped
continue;
}
else if(strcmp(argv[0], "exit") == 0 ||
strcmp(argv[0], "quit") == 0) {
exit(0);
}
child_pid = fork();
if(child_pid < 0) {
//If the child couldn't run, assume no memory
perror("Out of memory");
exit(1);
}
else if(child_pid == 0) {
//If we are the child, allow ^C
signal(SIGINT, SIG_DFL);
if(execvp(argv[0], argv) < 0) {
perror(argv[0]);
exit(1);
}
}
else {
waitpid(child_pid, &stat_loc, WUNTRACED);
}
free(user_input);
free(argv);
}
return 0;
}
char** create_argv(char* command) {
int argc = get_argc(command) + 1;
char* temp;
int i = 0;
char** argv = calloc(argc, sizeof(*argv));
if(argv == NULL) {
//If couldn't allocate argv, assume no memory
perror("Out of memory");
exit(1);
}
for(temp = strtok(command, ARG_SEP); temp != NULL;
temp = strtok(NULL, ARG_SEP)) {
argv[i] = temp;
i++;
}
//Set last item in argv to NULL, since execvp requires it
argv[i] = NULL;
return argv;
}
char* prompt() {
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
char* bname = basename(cwd);
char prompt[PATH_MAX + 5] = "";
strcat(prompt, bname);
strcat(prompt, PROMPT);
char* input = calloc(512, sizeof(*input));
if(input == NULL) {
//If input allocate failed, assume no memory
perror("Out of memory");
exit(1);
}
printf("%s", prompt);
fgets(input, 512, stdin);
//Is 512 enough? What about really long commands?
input[strcspn(input, "\r\n")] = '\0';
return input;
}
int get_argc(char* command) {
int argc = 0, word = 0;
char* command_iter = command;
do {
switch(*command_iter) {
case '\0':
case ' ':
case '\t': if(word) { word = 0; argc++; }
default: word = 1;
}
} while(*(command_iter++));
return argc;
}
int cd(char* path) {
return chdir(path);
}