#include #include #include #include #include #include #include #include "array.h" #include "prompt_utils.h" int parse_line(char const *line, char ***parts, size_t *part_count); // returns the return code of the executed program int exec_command(const char *path, char *const argv[], unsigned timeout); int main(void) { chdir("."); setvbuf(stdout, NULL, _IONBF, 0); char const *const original_wd = get_current_dir_name(); char const *prompt = relative_path(original_wd, original_wd); bool done = false; while (!done) { char *line = NULL; size_t cap = 0; __ssize_t length = 0; printf("%s > ", prompt); if ((length = getline(&line, &cap, stdin)) < 0) { fprintf(stderr, "Failed to read from STDIN"); exit(-1); } if (strspn(line, " \n\t") == strlen(line)) { continue; } line[length - 1] = '\0'; // cut the line feed char **arguments = NULL; size_t argument_count; parse_line(line, &arguments, &argument_count); if (strcmp(arguments[0], "cd") == 0) { if (arrayLen(arguments) != 3) { fprintf(stderr, "usage: cd "); goto clean; } int ret = chdir(arguments[1]); if (ret) printf("[%i] ", ret); free((void *)prompt); char const *current_wd = get_current_dir_name(); prompt = relative_path(original_wd, current_wd); free((void *)current_wd); } else if (strcmp(arguments[0], "exit") == 0) { done = true; } else { int ret = exec_command(arguments[0], arguments, 0); if (ret) printf("[%i] ", ret); } clean: free((void *)line); while (arrayLen(arguments) > 0) { char *tmp = arrayPop(arguments); if (tmp) arrayRelease(tmp); } arrayRelease(arguments); } free((void *)original_wd); free((void *)prompt); } int parse_line(char const *line, char ***parts, size_t *part_count) { char *part; char **local_parts; if (arrayInit(part) != 0 || arrayInit(local_parts) != 0) { fprintf(stderr, "Failed to prepare new part / parts array whilst parsing line"); return -1; } for (size_t i = 0; i < strlen(line) + 1; ++i) { char c = line[i]; if (c == ' ' || c == '\0') { if (arrayLen(part) == 0) continue; arrayPush(part) = '\0'; arrayPush(local_parts) = part; if (c == '\0') { arrayPush(local_parts) = NULL; break; } else { arrayInit(part); } } else { arrayPush(part) = c; } } *part_count = arrayLen(local_parts); *parts = local_parts; return 0; } void print_prompt() { size_t length = 1024; char *buffer = malloc(length * sizeof(char)); getcwd(buffer, length); if (buffer == NULL) { printf(".> "); } else { printf("%s > ", buffer); } } int exec_command(const char *path, char *const argv[], unsigned timeout) { timeout = timeout ^ timeout; int pid; int pipefd[2]; int status; char buf[512]; pipe(pipefd); if ((pid = fork()) == 0) { close(pipefd[0]); dup2(pipefd[1], 1); // includes close(1); close(pipefd[1]); execvp(path, argv); fprintf(stderr, "could not execute \"%s\"\n", path); fflush(stderr); exit(-1); } if (pid < 0) { fprintf(stderr, "no fork\n"); exit(-2); } close(pipefd[1]); __ssize_t length = 0; while ((length = read(pipefd[0], buf, 10)) > 0) { buf[length] = '\0'; fprintf(stdout, "%s", buf); fflush(stdout); } waitpid(pid, &status, 0); close(pipefd[0]); return WEXITSTATUS(status); }