diff --git a/README.md b/README.md index debc311..370297c 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -### SIMPLE SHELL PROJECT \ No newline at end of file +shell +#### SIMPLE SHELL PROJECTS diff --git a/_atoi.c b/_atoi.c new file mode 100644 index 0000000..b42c14d --- /dev/null +++ b/_atoi.c @@ -0,0 +1,30 @@ +#include "shell.h" + +/** + * _atoi - function that convert + * string into integer + * + * @str: to be converted + * Return: converted integer + */ +int _atoi(const char *str) +{ + int number; + int sign; + + sign = 1; + number = 0; + if (*str == '-') + { + sign = -1; + str++; + } + if (*str == '+') + str++; + while (*str) + { + number = number * 10 + (*str - 48); + str++; + } + return (number * sign); +} diff --git a/_cd.c b/_cd.c new file mode 100644 index 0000000..6586b9c --- /dev/null +++ b/_cd.c @@ -0,0 +1,79 @@ +#include "shell.h" + +/** + * _cd_helper - function helper of cd + * that takes key and look it up + * in enviroments variable and change + * directory to it + * + * @key: envs keys + * Return: 0 success otherwise error + */ +int _cd_helper(const char *key) +{ + char *s, buffer[200]; + + getcwd(buffer, 200); + s = _enviroment_management(GET_VALUE, key, NULL); + if (chdir(s) == -1) + { + free(s); + return (errno); + } + _enviroment_management(SET_ENTRY, "OLDPWD", buffer); + free(s); + return (0); +} + +/** + * _cd_helper2 - function that takes + * path as parameter and change + * directory to it + * + * @path: path to change directory to it + * Return: 0 on success ortherwise error + */ +int _cd_helper2(const char *path) +{ + char buffer[200]; + + getcwd(buffer, 200); + if (chdir(path) == -1) + { + perror(_global_states(GET_SHELL_NAME, NULL)); + return (errno); + } + _enviroment_management(SET_ENTRY, "OLDPWD", buffer); + return (0); +} + +/** + * _cd - builtin function cd + * is a function that allows as + * to navigate through out different + * folders (directories) in our operating + * system + * + * @command: struct the stores information + * about passed commands + * Return: (0) success otherwise errors + */ +int _cd(command_t *command) +{ + int len; + + len = _str2dlen(command->arguments + 1); + + if (len >= 1) + { + if (_strcmp("-", command->arguments[1])) + return (_cd_helper("OLDPWD")); + else if (_strcmp("~", command->arguments[1])) + return (_cd_helper("HOME")); + else + return (_cd_helper2(command->arguments[1])); + } + else if (!len) + return (_cd_helper("HOME")); + return (0); +} diff --git a/_clear_entry.c b/_clear_entry.c index 888de5c..dc01ace 100644 --- a/_clear_entry.c +++ b/_clear_entry.c @@ -7,9 +7,9 @@ * * Return: nothing */ -void _clear_entry(void *data) +void _clear_entry(void *data) { - entry_t *entry; + entry_t *entry; entry = data; free(entry->key); diff --git a/_clear_map.c b/_clear_map.c index d7967b1..5fbd583 100644 --- a/_clear_map.c +++ b/_clear_map.c @@ -6,7 +6,7 @@ *@map: map to be freed * Return: nothing */ -void _clear_map(map_t *map) +void _clear_map(map_t *map) { int iterator; diff --git a/_command_functions.c b/_command_functions.c new file mode 100644 index 0000000..c5b2c5f --- /dev/null +++ b/_command_functions.c @@ -0,0 +1,99 @@ +#include "shell.h" + +/** + * _free_command - function that frees command + * + * @data: data to be freed + * Return: Nothing + */ +void _free_command(void *data) +{ + command_t *cmd; + + cmd = data; + _free_split(&cmd->arguments); + free(data); +} + +/** + * _lookup_for_command - function that search + * for given command on the builtins + * as well as in the path + * + * @command: to lookup for + * @type: the type of the command + * Return: proper path or command if it's builtin + */ +char *_lookup_for_command(char *command, command_type_t *type) +{ + if (_builtin_management(GET_BUILTIN, command, NULL)) + { + *type = BUILTINS; + return (_strdup(command)); + } + return (_get_command_from_path(command)); +} +/** + * _init_command - function that initialize our + * command + * + * @tokens: 2d array holds all command arguments + * and it contain command name in the first argument + * Return: allocated command + */ +command_t *_init_command(char **tokens) +{ + command_t *command; + struct stat st; + char *scommand; + + command = malloc(sizeof(command_t)); + if (!command) + return (NULL); + command->type = NOT_FOUND; + scommand = _lookup_for_command(tokens[0], &command->type); + free(tokens[0]); + tokens[0] = scommand; + if (command->type == NOT_FOUND && + !stat(tokens[0], &st)) + command->type = EXTERNAL; + command->arguments = tokens; + command->name = tokens[0]; + return (command); +} +/** + * _handle_command - function that takes line + * and turn into an easy command to work with + * + * @line: to be parsed + * Return: well strucered method + */ +command_t *_handle_command(const char *line) +{ + char *trimmed_line, *command_name; + char **tokens[2]; + int iterator; + + trimmed_line = _trim_white_space(line); + tokens[0] = _split(trimmed_line, " "); + free(trimmed_line); + if (!tokens[0]) + return (NULL); + iterator = 0; + while (tokens[0][iterator]) + { + if (tokens[0][iterator][0] == '$') + { + command_name = _evaluate_enviroment_variable(tokens[0][iterator] + 1); + free(tokens[0][iterator]); + if (command_name) + tokens[0][iterator] = command_name; + else + tokens[0][iterator] = _strdup(""); + } + iterator++; + } + tokens[1] = _trim_2darray(tokens[0]); + _free_split(&tokens[0]); + return (_init_command(tokens[1])); +} diff --git a/_copy.c b/_copy.c index cf33654..13a17a6 100644 --- a/_copy.c +++ b/_copy.c @@ -1,13 +1,13 @@ #include "shell.h" /** - * copy_to_line - function that copy data into dest + * _copy - function that copy data into dest * * @dest: buffer in which the data will be copied * @src: buffer source of the characters * @size: length of data that will be copied into line * Return: dest */ -char *_copy(char *dest, char *src, size_t size) +char *_copy(char *dest, const char *src, size_t size) { size_t iter; diff --git a/_delete_entry.c b/_delete_entry.c new file mode 100644 index 0000000..06d86c3 --- /dev/null +++ b/_delete_entry.c @@ -0,0 +1,43 @@ +#include "shell.h" + +/** + * _delete_entry - function that removes + * entry from hashmap by given key index + * + * @map: map to delete entry from + * @key: string key of the entry + * Return: (0) success, (1) error + */ +int _delete_entry(map_t *map, const char *key) +{ + list_t *list, *tmp; + int backet_index; + entry_t *entry; + + backet_index = _get_hash_code(key); + list = map->backets[backet_index]; + if (!list) + return (0); + entry = list->data; + if (_strcmp(entry->key, key)) + { + map->backets[backet_index] = list->next; + _clear_entry(list->data); + free(list); + return (0); + } + while (list->next) + { + entry = list->next->data; + if (_strcmp(entry->key, key)) + { + tmp = list->next; + list->next = list->next->next; + _clear_entry(tmp->data); + free(tmp); + break; + } + list = list->next; + } + return (0); +} diff --git a/_env.c b/_env.c new file mode 100644 index 0000000..98dce42 --- /dev/null +++ b/_env.c @@ -0,0 +1,27 @@ +#include "shell.h" + +/** + * _env - builtin function that print whatever + * inside our enviroment variables + * + * @command: command_t contains informations + * about the user command + * Return: 0 success, 1 error + */ +int _env(command_t *command) +{ + char **envs, **iterator; + + (void)command; + + iterator = envs = _enviroment_management(CONVERT_INTO_2D, NULL, NULL); + if (!iterator) + return (1); + while (*iterator) + { + _fprint(1, "%s\n", *iterator); + iterator++; + } + _free_split(&envs); + return (0); +} diff --git a/_evaluate_enviroment_variable.c b/_evaluate_enviroment_variable.c new file mode 100644 index 0000000..df2ba6d --- /dev/null +++ b/_evaluate_enviroment_variable.c @@ -0,0 +1,26 @@ +#include "shell.h" + +/** + * _evaluate_enviroment_variable - function + * that takes key and return it's respective + * value + * + * @env_key: key to retrieve it's value from enviroment + * variables + * Return: corresponding value to given key + */ +char *_evaluate_enviroment_variable(char *env_key) +{ + char *value; + int number; + + if (_strcmp(env_key, "?")) + { + number = _status_management(GET_STATUS, 0); + return (_itoa(number)); + } + if (_strcmp(env_key, "$")) + return (_itoa(getpid())); + value = _enviroment_management(GET_VALUE, env_key, NULL); + return (value); +} diff --git a/_exclude_comment.c b/_exclude_comment.c new file mode 100644 index 0000000..2719d66 --- /dev/null +++ b/_exclude_comment.c @@ -0,0 +1,16 @@ +#include "shell.h" + +/** + * _exclude_comment - remove comment from + * line + * + * @line: full line that user entered + * Return: new_line without comment + */ +char *_exclude_comment(const char *line) +{ + int comment_position; + + comment_position = _get_comment_position(line); + return (_strslice(line, 0, comment_position)); +} diff --git a/_execute.c b/_execute.c new file mode 100644 index 0000000..2c9a83c --- /dev/null +++ b/_execute.c @@ -0,0 +1,30 @@ +#include "shell.h" + +/** + * _excute - function that excute commands + * that's not part of builtins + * + * @command: command to be executed + * Return: Nothing(void) + */ +void _excute(command_t *command) +{ + int pid, status; + char **envs; + + pid = fork(); + if (!pid) + { + envs = _enviroment_management(CONVERT_INTO_2D, NULL, NULL); + execve(command->name, command->arguments, envs); + _free_command(command); + _free_split(&envs); + perror(_global_states(GET_SHELL_NAME, NULL)); + exit(errno); + } + else + { + waitpid(pid, &status, 0); + _status_management(UPDATE_STATUS, WEXITSTATUS(status)); + } +} diff --git a/_exit.c b/_exit.c new file mode 100644 index 0000000..efd70e5 --- /dev/null +++ b/_exit.c @@ -0,0 +1,40 @@ +#include "shell.h" + +/** + * __exit - function that exit + * from the program + * + * @command: struct that holds data + * about command + * Return: 0 success, otherwise error + */ +int __exit(command_t *command) +{ + char **iterator; + int len; + + iterator = command->arguments + 1; + len = _str2dlen(iterator); + if (len > 0 && !_isdigit(*iterator)) + { + _fprint(2, "%s: %d: exit: Illegal number: %s\n", + _global_states(GET_SHELL_NAME, NULL), + *((int *)_global_states(GET_LINE_NUMBER, NULL)), + command->arguments[1]); + return (2); + } + else + { + _enviroment_management(CLEAR_ENV, NULL, NULL); + free(_global_states(GET_LINE, NULL)); + if (!len) + { + _free_command(command); + exit(0); + } + len = _atoi(command->arguments[1]); + _free_command(command); + exit(len); + } + return (0); +} diff --git a/_fprint.c b/_fprint.c new file mode 100644 index 0000000..410c648 --- /dev/null +++ b/_fprint.c @@ -0,0 +1,110 @@ +#include "shell.h" + +/** + * _fput_number_helper - function helps to + * print number + * + * @fd: file descriptor of the file that + * the given number will be printed in + * @number: number to be printed + * Return: number of printed digits + */ +int _fput_number_helper(int fd, int number) +{ + int ret; + char c; + + if (number == 0) + return (0); + ret = _fput_number_helper(fd, number / 10); + c = number % 10 + 48; + write(fd, &c, 1); + return (1 + ret); +} + +/** + * _fput_number - function that print + * given number into given file + * + * @fd: file descriptor + * @number: to be printed + * Return: the length of the printed + * characters + */ +int _fput_number(int fd, int number) +{ + int printed; + + printed = 0; + if (!number) + { + write(fd, "0", 1); + return (1); + } + if (number < 0) + { + write(fd, "-", 1); + printed = 1; + number *= -1; + } + return (printed + _fput_number_helper(fd, number)); +} + +/** + * _fputs - function that prints string + * into given file descriptor + * + * @fd: file descriptor + * @s: string to be printed + * Return: number of character printed + */ +int _fputs(int fd, const char *s) +{ + return (write(fd, s, _strlen(s))); +} + +/** + * _fprint - function that allows to + * to print number and string using + * format specifiers + * + * + * @fd: file descriptor + * @format: format to be printed to given fd + * and change place holder to specific values + * Return: number of printed characters + */ +int _fprint(int fd, const char *format, ...) +{ + va_list ap; + int index, printed; + int is_percent; + + va_start(ap, format); + is_percent = 0; + index = 0; + printed = 0; + while (format[index]) + { + if (format[index] == '%') + is_percent = 1; + else + { + if (is_percent) + { + if (format[index] == 'd') + printed += _fput_number(fd, va_arg(ap, int)); + else if (format[index] == 's') + printed += _fputs(fd, va_arg(ap, char *)); + else + printed += write(fd, &format[index - 1], 2); + } + else + printed += write(fd, format + index, 1); + is_percent = 0; + } + index++; + } + va_end(ap); + return (printed); +} diff --git a/_free_list.c b/_free_list.c index 2437c39..e0c3181 100644 --- a/_free_list.c +++ b/_free_list.c @@ -9,7 +9,7 @@ void free_list(list_t *list, void (*free_content)(void *data)) { list_t *current = list; - list_t *next; + list_t *next; while (current != NULL) { diff --git a/_get_command_from_path.c b/_get_command_from_path.c new file mode 100644 index 0000000..ab88ad0 --- /dev/null +++ b/_get_command_from_path.c @@ -0,0 +1,38 @@ +#include "shell.h" + +/** + * _get_command_from_path - function that takes command + * and return it's corresponding path + * + * @command: command to lookup for it's path + * Return: path where command located + */ +char *_get_command_from_path(char *command) +{ + char *proper_command, *path, + **path_2d, **iterator; + struct stat st; + + if (!stat(command, &st)) + return (_strdup(command)); + path = _enviroment_management(GET_VALUE, "PATH", NULL); + if (!path) + return (_strdup(command)); + iterator = path_2d = _split(path, ":"); + free(path); + while (*iterator) + { + path = _strcat(*iterator, "/"); + proper_command = _strcat(path, command); + free(path); + if (!stat(proper_command, &st)) + { + _free_split(&path_2d); + return (proper_command); + } + free(proper_command); + iterator++; + } + _free_split(&path_2d); + return (_strdup(command)); +} diff --git a/_get_hash_code.c b/_get_hash_code.c index 3a8b3e4..3d3be84 100644 --- a/_get_hash_code.c +++ b/_get_hash_code.c @@ -1,12 +1,12 @@ #include "shell.h" /** - * _get_hash_code - calculates the hash code for a given key. - * - * @key: key to be hash - * - * Return: return an integer signify hashed code of the given key‏ - */ + * _get_hash_code - calculates the hash code for a given key. + * + * @key: key to be hash + * + * Return: return an integer signify hashed code of the given key + */ int _get_hash_code(const char *key) { int hash = 0; diff --git a/_isdigit.c b/_isdigit.c new file mode 100644 index 0000000..9f1bb7f --- /dev/null +++ b/_isdigit.c @@ -0,0 +1,24 @@ +#include "shell.h" + +/** + * _isdigit - function that takes a + * string and check wether it's digit or + * not + * + * @s: string to check against + * Return: 1 signify digits, 0 else + */ +int _isdigit(const char *s) +{ + if (!s) + return (0); + if (*s == '-' || *s == '+') + s++; + while (*s) + { + if (*s < '0' || *s > '9') + return (0); + s++; + } + return (1); +} diff --git a/_itoa.c b/_itoa.c new file mode 100644 index 0000000..71ffcfe --- /dev/null +++ b/_itoa.c @@ -0,0 +1,63 @@ +#include "shell.h" + +/** + * _count_number_length - function that + * calculate the length of the given number + * + * @number: to calculate it's length + * Return: length + */ +int _count_number_length(int number) +{ + int len; + + len = 0; + if (number == 0) + return (1); + if (number < 0) + { + len++; + number *= -1; + } + while (number) + { + len++; + number /= 10; + } + return (len); +} + +/** + * _itoa - function convert number int + * string + * + * @number: to be converted + * Return: converted string + */ +char *_itoa(int number) +{ + int len; + char *str_number; + + len = _count_number_length(number); + str_number = malloc(sizeof(char) * (len + 1)); + if (!str_number) + return (NULL); + str_number[len] = 0; + if (!number) + { + str_number[0] = '0'; + return (str_number); + } + if (number < 0) + { + str_number[0] = '-'; + number *= -1; + } + while (number) + { + str_number[--len] = number % 10 + 48; + number /= 10; + } + return (str_number); +} diff --git a/_listlen.c b/_listlen.c new file mode 100644 index 0000000..42848aa --- /dev/null +++ b/_listlen.c @@ -0,0 +1,21 @@ +#include "shell.h" + +/** + * _listlen - function that calculate the + * length of the given linkedlist + * + * @list: to calculate it's length + * Return: length of list + */ +size_t _listlen(const list_t *list) +{ + size_t len; + + len = 0; + while (list) + { + list = list->next; + len++; + } + return (len); +} diff --git a/_main.c b/_main.c new file mode 100644 index 0000000..5119eb3 --- /dev/null +++ b/_main.c @@ -0,0 +1,44 @@ +#include "shell.h" + +/** + * main - entry level function + * + * @ac: number of passed arguments + * @av: arguments + * @env: enviroment variables + * Return: 0 sucess, otherwise error + */ +int main(int ac, char *av[], char **env) +{ + char *line, *no_comment_line; + + (void)ac; + signal(SIGINT, _handle_sigint); + _enviroment_management(INIT_ENV, NULL, NULL); + _feed_enviroment_variable(env); + _builtin_management(SET_BUILTIN, "exit", __exit); + _builtin_management(SET_BUILTIN, "env", _env); + _builtin_management(SET_BUILTIN, "setenv", _setenv); + _builtin_management(SET_BUILTIN, "unsetenv", _unsetenv); + _builtin_management(SET_BUILTIN, "cd", _cd); + _global_states(SET_SHELL_NAME, av[0]); + while (1) + { + _prompt(); + _getline(&line); + if (!line) + { + free(line); + break; + } + no_comment_line = _exclude_comment(line); + free(line); + line = no_comment_line; + _global_states(SET_LINE, line); + _global_states(INCREMENT_LINE_NUMBER, NULL); + _semicolon_handler(line); + free(line); + } + _enviroment_management(CLEAR_ENV, NULL, NULL); + return (0); +} diff --git a/_parsing_error_handler.c b/_parsing_error_handler.c index 8aa5be1..fcbec06 100644 --- a/_parsing_error_handler.c +++ b/_parsing_error_handler.c @@ -12,10 +12,12 @@ int _check_invalid_characters_occurance(char *line) size_t index, iter, iter2; char *invalid_characters[] = { ";;", - "|||"}; + "|||", + ">>>", + "<<"}; index = 0; - while (index < 2) + while (index < 4) { iter = 0; iter2 = 0; @@ -52,7 +54,8 @@ int _parsing_error_handler(char *line) return (0); len = _strlen(line); if (line[0] == ';' || line[0] == '|' || - line[len - 1] == ';' || line[len - 1] == '|') + line[len - 1] == '|' || + line[len - 1] == '>' || line[len - 1] == '<') return (2); len = 0; while (line[len]) diff --git a/_prompt.c b/_prompt.c new file mode 100644 index 0000000..c769cb9 --- /dev/null +++ b/_prompt.c @@ -0,0 +1,16 @@ +#include "shell.h" + +/** + * _prompt - function that asks + * a user to enter a command + * + * Return: Nothing (void) + */ +void _prompt(void) +{ + if (isatty(STDIN_FILENO)) + { + _fprint(1, "%s> ", + _global_states(GET_SHELL_NAME, NULL)); + } +} diff --git a/_semicolon_handler.c b/_semicolon_handler.c new file mode 100644 index 0000000..c71ab3b --- /dev/null +++ b/_semicolon_handler.c @@ -0,0 +1,48 @@ +#include "shell.h" + +/** + * _semicolon_handler - function that splits given + * line bu semicolon and pass the result to be + * handled by other functions + * + * @line: command line to be parsed and executed + * Return: 1 on success or 0 signifying error + */ +int _semicolon_handler(const char *line) +{ + char **semi_commands, **iterator; + command_t *command; + int argument_length; + + iterator = semi_commands = _split(line, ";"); + if (!iterator) + return (1); + while (*iterator) + { + command = _handle_command(*iterator); + if (command->type == NOT_FOUND) + { + _fprint(2, "%s: %d: %s: not found\n", + (char *)_global_states(GET_SHELL_NAME, NULL), + *((int *)_global_states(GET_LINE_NUMBER, NULL)), + command->name); + _status_management(UPDATE_STATUS, 127); + } + else if (command->type == EXTERNAL) + _excute(command); + else + { + _status_management(UPDATE_STATUS, + _builtin_management( + GET_BUILTIN, + command->name, NULL)(command)); + } + argument_length = _str2dlen(command->arguments); + _enviroment_management(SET_ENTRY, "_", + command->arguments[argument_length - 1]); + _free_command(command); + iterator++; + } + _free_split(&semi_commands); + return (0); +} diff --git a/_set_value.c b/_set_value.c index ef7e20b..acc90c1 100644 --- a/_set_value.c +++ b/_set_value.c @@ -9,11 +9,11 @@ *@value: string implies to value of the entry *Return: 0 on error, 1 success */ -int _set_value(map_t *map, const char *key, const char *value) +int _set_value(map_t *map, const char *key, const char *value) { - int backet_index; + int backet_index; list_t *iterator; - entry_t *entry; + entry_t *entry; backet_index = _get_hash_code(key); iterator = map->backets[backet_index]; diff --git a/_setenv.c b/_setenv.c new file mode 100644 index 0000000..9c70777 --- /dev/null +++ b/_setenv.c @@ -0,0 +1,28 @@ +#include "shell.h" + +/** + * _setenv - builtins that helps + * add new entries to our envs + * or update entries from it + * + * @command: struct that stores information + * about current running command + * Return: (0) success otherwise error + */ +int _setenv(command_t *command) +{ + int len; + + len = _str2dlen(command->arguments + 1); + if (len != 2) + { + _fprint(2, "%s: Invalid number of arguments\n", + _global_states(GET_SHELL_NAME, NULL)); + return (1); + } + _enviroment_management( + SET_ENTRY, + command->arguments[1], + command->arguments[2]); + return (0); +} diff --git a/_signals_handler.c b/_signals_handler.c new file mode 100644 index 0000000..e8d65e8 --- /dev/null +++ b/_signals_handler.c @@ -0,0 +1,20 @@ +#include "shell.h" + +/** + * _handle_sigint - function that + * will be called when control-c(SIGINT) + * triggred + * + * @sig: Integer signifying the signal number + * Return: void + */ +void _handle_sigint(int sig) +{ + (void)sig; + fflush(stdin); + if (isatty(STDIN_FILENO)) + { + _fprint(1, "\n%s> ", + _global_states(GET_SHELL_NAME, NULL)); + } +} diff --git a/_split.c b/_split.c index 461aaaa..9c64079 100644 --- a/_split.c +++ b/_split.c @@ -1,5 +1,4 @@ #include "shell.h" -#include /** * check_diameter - functions that look up for next diameter @@ -9,7 +8,7 @@ * Return: 0 if the str doesn't contain diameter, 1 when diameter found * 2 when diameter found in but followed by last character of the diameter */ -int check_diameter(char *str, char *diameter) +int check_diameter(const char *str, const char *diameter) { size_t iter; @@ -31,13 +30,15 @@ int check_diameter(char *str, char *diameter) * @diameter: buffer to look up for * Return: number of backets */ -size_t backet_count(char *line, char *diameter) +size_t backet_count(const char *line, const char *diameter) { size_t counter, index, before, is_diameter; counter = 0; index = 0; before = 0; + if (!*line) + return (0); while (line[index]) { is_diameter = check_diameter(line + index, diameter); @@ -73,7 +74,7 @@ size_t backet_count(char *line, char *diameter) * @diameter: buffer to look up for * Return: position of the next occurance of the diameter */ -size_t get_next_diameter(char *line, char *diameter) +size_t get_next_diameter(const char *line, const char *diameter) { size_t index, before, is_diameter; @@ -102,6 +103,7 @@ size_t get_next_diameter(char *line, char *diameter) } return (index); } + /** * free_backets - function that frees backets * in case of error @@ -132,7 +134,7 @@ void free_backets(char **backets, size_t current_position) * Return: 2d array that ends with NULL * or NULL in case of error */ -char **_split(char *line, char *diameter) +char **_split(const char *line, const char *diameter) { char **backets; size_t backet_length, current_line_position, backet_index; diff --git a/_state_managements.c b/_state_managements.c new file mode 100644 index 0000000..385fbaa --- /dev/null +++ b/_state_managements.c @@ -0,0 +1,122 @@ +#include "shell.h" + +/** + * _status_management - status state management is function that + * allows to access and apply actions to our status globaly + * from any function + * + * @action: action that will be applied to our state + * @new_status: used when updating status + * Return: current status + */ + +int _status_management(status_actions_t action, int new_status) +{ + static int status; + + if (action == UPDATE_STATUS) + status = new_status; + return (status); +} + +/** + * _enviroment_management - function that allows to access + * our global variables anywhere in our program + * and provides us with bunch of action to be applied to our + * map + * + * @action: action that will be applied to our env + * @key: string used when adding new entry or when + * retrieving data + * @value: string used when adding new entry + * Return: different types based on the given action + */ +void *_enviroment_management(enviroment_action_t action, + const char *key, const char *value) +{ + static map_t *map; + + if (action == INIT_ENV) + map = _init_map(); + else if (action == SET_ENTRY) + _set_value(map, key, value); + else if (action == GET_VALUE) + return (_strdup(_get_value(map, key))); + else if (action == GET_KEYS) + return (_get_keys(map)); + else if (action == CONVERT_INTO_2D) + return (_convert_env_into_2d_array()); + else if (action == CLEAR_ENV) + _clear_map(map); + else if (action == DELETE_ENTRY) + _delete_entry(map, key); + return (NULL); +} + +/** + * _builtin_management - function that manages + * builtins inside our application + * + * @action: action that will be applied to our + * builtins state managements + * @name: name of the builtin + * @function: builtin function that will be + * executed later + * Return: (void *) function that associated to + * builtin or NULL + */ +builtins_t _builtin_management(builtin_actions_t action, char *name, + int (*function)(command_t *command)) +{ + static builtin_t builtins[10]; + static int size; + int iter; + + if (action == GET_BUILTIN) + { + iter = 0; + while (iter < size) + { + if (_strcmp(builtins[iter].name, name)) + return (builtins[iter].function); + iter++; + } + } + if (action == SET_BUILTIN) + { + _copy(builtins[size].name, name, _strlen(name)); + builtins[size].function = function; + size++; + } + return (NULL); +} + +/** + * _global_states - state management that holds + * some variables that will be used in different + * places of the applications + * + * @action: actions that will be applied to + * the globals state managements + * @s: string to update string + * Return: (void *) + */ +void *_global_states(globals_action_t action, char *s) +{ + static char *line, *shell_name; + static int line_number; + + if (action == SET_LINE) + line = s; + if (action == SET_SHELL_NAME) + shell_name = s; + if (action == GET_LINE) + return (line); + if (action == GET_SHELL_NAME) + return (shell_name); + if (action == GET_LINE_NUMBER) + return (&line_number); + if (action == INCREMENT_LINE_NUMBER) + line_number++; + return (NULL); +} diff --git a/_str2dlen.c b/_str2dlen.c new file mode 100644 index 0000000..c6280c8 --- /dev/null +++ b/_str2dlen.c @@ -0,0 +1,18 @@ +#include "shell.h" + +/** + * _str2dlen - function that counts + * the length of 2d array + * + * @arr2d: to count it's length + * Return: length of given array + */ +int _str2dlen(char **arr2d) +{ + int len; + + len = 0; + while (arr2d[len]) + len++; + return (len); +} diff --git a/_strcat.c b/_strcat.c new file mode 100644 index 0000000..4b85d25 --- /dev/null +++ b/_strcat.c @@ -0,0 +1,35 @@ +#include "shell.h" + +/** + * _strcat - function that takes 2 string and + * combines them + * + * @str1: first string + * @str2: second string + * Return: the combination of first and second string + * NULL on error case + */ +char *_strcat(const char *str1, const char *str2) +{ + size_t len1, len2, iter; + char *newstr; + + len1 = _strlen(str1); + len2 = _strlen(str2); + newstr = malloc(sizeof(char) * (len1 + len2 + 1)); + if (!newstr) + return (NULL); + iter = 0; + while (iter < len1) + { + newstr[iter] = str1[iter]; + iter++; + } + while (iter - len1 < len2) + { + newstr[iter] = str2[iter - len1]; + iter++; + } + newstr[iter] = 0; + return (newstr); +} diff --git a/_strcmp.c b/_strcmp.c new file mode 100644 index 0000000..687ccea --- /dev/null +++ b/_strcmp.c @@ -0,0 +1,24 @@ +#include "shell.h" + +/** + * _strcmp - function checks wether given strings + * are identical or not + * + * @str1: first string to check against + * @str2: second string to check against + * + * Return: 1 success case, 0 error case + */ +int _strcmp(const char *str1, const char *str2) +{ + if (!str1 || !str2) + return (0); + while (*str1 && *str2 && *str1 == *str2) + { + str1++; + str2++; + } + if (!*str1 && !*str2) + return (1); + return (0); +} diff --git a/_strlen.c b/_strlen.c index 8a7d995..23b7e8c 100644 --- a/_strlen.c +++ b/_strlen.c @@ -5,12 +5,12 @@ * @s: string (characters) * Return: number of characters */ -size_t _strlen(char *s) +size_t _strlen(const char *s) { size_t len; len = 0; - while (s[len]) + while (s && s[len]) len++; return (len); } diff --git a/_strslice.c b/_strslice.c new file mode 100644 index 0000000..4f439ed --- /dev/null +++ b/_strslice.c @@ -0,0 +1,31 @@ +#include "shell.h" + +/** + * _strslice - function that take string + * and return specified part of it + * + * @line: to be sliced + * @start: start position index zero based + * @end: end position index zero based(excluded) + * Return: part of the string + */ +char *_strslice(const char *line, int start, int end) +{ + char *slice; + int len, iter; + + if (start < 0) + start = 0; + len = _strlen(line); + if (len < end || end < 0) + end = len; + slice = malloc(sizeof(char) * (end - start + 1)); + iter = 0; + while (start + iter < end) + { + slice[iter] = line[start + iter]; + iter++; + } + slice[iter] = 0; + return (slice); +} diff --git a/_trim_2darray.c b/_trim_2darray.c new file mode 100644 index 0000000..22c7470 --- /dev/null +++ b/_trim_2darray.c @@ -0,0 +1,53 @@ +#include "shell.h" + +/** + * _count_non_empty_string - function that counts + * number of non empty string inside of 2d array + * + * @arr: 2d array to lookup for number of non empty + * string + * Return: number of non empty strings + */ +int _count_non_empty_string(char **arr) +{ + int len; + + len = 0; + while (*arr) + { + len += (**arr != '\0'); + arr++; + } + return (len); +} + +/** + * _trim_2darray - function takes an array + * and return new one with no empty string + * + * @arr: 2d array to remove non empty strings + * from it + * Return: 2d array without empty strings + */ +char **_trim_2darray(char **arr) +{ + int len; + char **new_arr; + + len = _count_non_empty_string(arr); + new_arr = malloc(sizeof(char *) * (len + 1)); + if (!new_arr) + return (NULL); + new_arr[len] = NULL; + len = 0; + while (*arr) + { + if (**arr) + { + new_arr[len] = _strdup(*arr); + len++; + } + arr++; + } + return (new_arr); +} diff --git a/_trim_white_space.c b/_trim_white_space.c index b181848..3d329d8 100644 --- a/_trim_white_space.c +++ b/_trim_white_space.c @@ -7,7 +7,7 @@ * @end: the end of the line * Return: length */ -size_t _get_length_without_space_dup(char *line, size_t end) +size_t _get_length_without_space_dup(const char *line, size_t end) { size_t start, len; int is_space; @@ -40,7 +40,7 @@ size_t _get_length_without_space_dup(char *line, size_t end) * @end: the end of the string exculding last spaces * Return: new string */ -char *_get_newline_without_space_dup(char *line, size_t end) +char *_get_newline_without_space_dup(const char *line, size_t end) { size_t start, index; int is_space; @@ -50,10 +50,10 @@ char *_get_newline_without_space_dup(char *line, size_t end) is_space = 0; index = 0; newline = malloc(sizeof(char) * - (_get_length_without_space_dup(line, end) + 1)); + (_get_length_without_space_dup(line, end + 1) + 1)); if (!newline) return (NULL); - while (start < end) + while (start <= end) { if (line[start] == ' ' && !is_space) { @@ -80,13 +80,11 @@ char *_get_newline_without_space_dup(char *line, size_t end) * @line: to check against * Return: newline without space duplicates */ -char *_trim_white_space(char *line) +char *_trim_white_space(const char *line) { - size_t left, right, new_length; - int is_space; + size_t left, right; left = 0; - is_space = 0; right = _strlen(line) - 1; while (line[left] == ' ') left++; diff --git a/_unsetenv.c b/_unsetenv.c new file mode 100644 index 0000000..61ab44a --- /dev/null +++ b/_unsetenv.c @@ -0,0 +1,24 @@ +#include "shell.h" + +/** + * _unsetenv - function unset one entry from enviroment + * variable + * + * @command: command that contains information about + * entry that will be delete such as key of the entry + * Return: status code + */ +int _unsetenv(command_t *command) +{ + int len; + + len = _str2dlen(command->arguments); + if (len != 2) + { + _fprint(2, "%s: Invalid number of arguments\n", + _global_states(GET_SHELL_NAME, NULL)); + return (1); + } + _enviroment_management(DELETE_ENTRY, command->arguments[1], NULL); + return (0); +} diff --git a/_utils_functions.c b/_utils_functions.c new file mode 100644 index 0000000..c16bc19 --- /dev/null +++ b/_utils_functions.c @@ -0,0 +1,61 @@ +#include "shell.h" + +/** + * _convert_env_into_2d_array - function that turns + * env into array 2d + * + * Return: array 2d or NULL signifying error + */ +char **_convert_env_into_2d_array(void) +{ + list_t *keys, *iterator; + size_t len_iter; + char **array; + char *tmp[2]; + + iterator = keys = _enviroment_management(GET_KEYS, NULL, NULL); + len_iter = _listlen(keys); + array = malloc(sizeof(char *) * (len_iter + 1)); + if (!array) + { + free_list(keys, free); + return (NULL); + } + array[len_iter] = NULL; + len_iter = 0; + while (iterator) + { + tmp[0] = _strcat(iterator->data, "="); + tmp[1] = _enviroment_management(GET_VALUE, + iterator->data, + NULL); + array[len_iter] = _strcat(tmp[0], tmp[1]); + free(tmp[0]); + free(tmp[1]); + iterator = iterator->next; + len_iter++; + } + free_list(keys, free); + return (array); +} + +/** + * _feed_enviroment_variable - function take whatever + * is inside given 2d enviroment and split by space + * and add it to the global env + * + * @new_env: enviroment as 2d array + * Return: void; + */ +void _feed_enviroment_variable(char **new_env) +{ + char **entry; + + while (*new_env) + { + entry = _split(*new_env, "="); + _enviroment_management(SET_ENTRY, entry[0], entry[1]); + _free_split(&entry); + new_env++; + } +} diff --git a/shell.h b/shell.h index 333bdc6..dd650bd 100644 --- a/shell.h +++ b/shell.h @@ -3,8 +3,14 @@ #include #include +#include +#include #include - +#include +#include +#include +#include +#include #define BUFFER_SIZE 1024 #define BACKET_SIZE 64 @@ -21,6 +27,18 @@ typedef struct entry_s char *value; } entry_t; +/** + * enum status_actions_e - actions that will be applied to + * status state management + * + * @UPDATE_STATUS: action to update status code + * @GET_STATUS: action to retrieve status code + */ +typedef enum status_actions_e +{ + UPDATE_STATUS, + GET_STATUS +} status_actions_t; /** * struct list_s - node of linkedlist @@ -34,6 +52,60 @@ typedef struct list_s struct list_s *next; } list_t; +/** + * enum command_type_e - types of command + * + * @BUILTINS: MEANS THAT COMMAND IS BUILTIN + * @EXTERNAL: MEANS IT's AN EXTERNAL COMMAND + * @NOT_FOUND: MEANS THAT COMMANS IS NOT FOUND + */ +typedef enum command_type_e +{ + BUILTINS, + EXTERNAL, + NOT_FOUND +} command_type_t; +/** + * struct command_s - struct that holds informations + * about command + * + * @name: name of the command + * @arguments: command arguments + * @type: type of the command + */ +typedef struct command_s +{ + char *name; + char **arguments; + command_type_t type; +} command_t; +/** + * struct builtin_s - builtin struct + * that will contain name of builtins + * and it respective function to be + * executed + * + * @name: builtin name + * @function: builtin function + * + */ +typedef struct builtin_s +{ + char name[30]; + int (*function)(command_t *command); +} builtin_t; + +/** + * enum builtin_actions_e - builtin actions + * + * @GET_BUILTIN: action to get builtin function + * @SET_BUILTIN: action to add new_buitin function + */ +typedef enum builtin_actions_e +{ + GET_BUILTIN, + SET_BUILTIN +} builtin_actions_t; /** * struct map_s - defines a structure for a hash table * @@ -42,27 +114,118 @@ typedef struct list_s */ typedef struct map_s { - list_t *backets[BACKET_SIZE]; -} map_t; + list_t *backets[BACKET_SIZE]; +} map_t; + +/** + * enum enviroment_action_e - actions that will be applied to + * global enviroment + * + * @INIT_ENV: TO INITIALIZE ENVIROMENT VARIABLE + * @SET_ENTRY: TO ADD NEW ENTRY TO ENVIROMENT VARIABLE + * @GET_VALUE: TO RETRIEVE VALUE FROM ENVIROMENT VARIABLE + * @GET_KEYS: TO GET ALL KEY THAT STORED INSIDE ENV VARIABLE + * @CONVERT_INTO_2D: RETURNS 2D ARRAY CONTAINING ALL ENVIRONEMENT + * VARIBALES (env) + * @CLEAR_ENV: TO FREE AND CLEAR EVERYTHING INSIDE OF OUR + * @DELETE_ENTRY: USED TO DELETE ENTRY FROM ENVIROMENT VARIABLE + * ENV + */ +typedef enum enviroment_action_e +{ + INIT_ENV, + SET_ENTRY, + GET_VALUE, + GET_KEYS, + DELETE_ENTRY, + CONVERT_INTO_2D, + CLEAR_ENV +} enviroment_action_t; + +/** + * enum globals_action_e - actions to be applied to + * some global states or variables + * + * @GET_LINE: action that allows to + * get line + * @GET_LINE_NUMBER: action that allows to get + * current line number + * @GET_SHELL_NAME: action that allows us to + * get shell name + * @SET_LINE: action that allow us to the line + * @SET_SHELL_NAME: action allow us to set + * shell name + * @INCREMENT_LINE_NUMBER: action to increment + * line number by one + */ +typedef enum globals_action_e +{ + GET_LINE, + GET_LINE_NUMBER, + GET_SHELL_NAME, + SET_LINE, + SET_SHELL_NAME, + INCREMENT_LINE_NUMBER +} globals_action_t; + +typedef int (*builtins_t)(command_t *); -char *_copy(char *dest, char *src, size_t size); +char *_copy(char *dest, const char *src, size_t size); void *_realloc(void *old_buffer, size_t old_size, size_t new_size); ssize_t _getline(char **line); -char *_trim_white_space(char *line); +char *_trim_white_space(const char *line); int _parsing_error_handler(char *line); -size_t _strlen(char *s); +size_t _strlen(const char *s); void _free_split(char ***backets); -char **_split(char *line, char *diameter); +char **_split(const char *line, const char *diameter); list_t *add_to_list(list_t **lst, void *data); void *pop_from_list(list_t **list); +size_t _listlen(const list_t *list); void free_list(list_t *list, void (*free_content)(void *data)); -char *_strdup(const char *str); +int _strcmp(const char *str1, const char *str2); +char *_strdup(const char *str); int _get_hash_code(const char *key); map_t *_init_map(void); -int _set_value(map_t *map, const char *key, const char *value); -char *_get_value(const map_t *map, const char *key); -void _clear_entry(void *data); -void _clear_map(map_t *map); -list_t *_get_keys(const map_t *map); +int _set_value(map_t *map, const char *key, const char *value); +char *_get_value(const map_t *map, const char *key); +void _clear_entry(void *data); +void _clear_map(map_t *map); +list_t *_get_keys(const map_t *map); +int _delete_entry(map_t *map, const char *key); +command_t *_init_command(char **tokens); +void _free_command(void *data); +command_t *_handle_command(const char *line); +int _semicolon_handler(const char *line); +list_t *_pipe_handler(const char *line); +int _handle_pipe_execution(list_t *pipes, int previous_stdin); +int _status_management(status_actions_t action, int new_status); +void _handle_sigint(int sig); +void *_enviroment_management(enviroment_action_t action, + const char *key, const char *value); +int _status_management(status_actions_t action, int new_status); +char **_convert_env_into_2d_array(void); +void _feed_enviroment_variable(char **new_env); +char *_get_command_from_path(char *command); +char *_strslice(const char *line, int start, int end); +char *_strcat(const char *str1, const char *str2); +char *_itoa(int number); +char *_evaluate_enviroment_variable(char *env_key); +char **_trim_2darray(char **arr); +int _env(command_t *command); +int _isdigit(const char *s); +int _str2dlen(char **arr2d); +int _atoi(const char *str); +int __exit(command_t *command); +builtins_t _builtin_management(builtin_actions_t action, char *name, + int (*function)(command_t *command)); +void _excute(command_t *command); +int _setenv(command_t *command); +int _unsetenv(command_t *command); +int _fprint(int fd, const char *format, ...); +void *_global_states(globals_action_t action, char *s); +int _cd(command_t *command); +void _handle_sigint(int sig); +void _prompt(void); int _get_comment_position(const char *line); +char *_exclude_comment(const char *line); #endif diff --git a/tests/_fprint_test.c b/tests/_fprint_test.c new file mode 100644 index 0000000..626d163 --- /dev/null +++ b/tests/_fprint_test.c @@ -0,0 +1,11 @@ +#include "../shell.h" + +int main(void) +{ + _fprint(1, "hello world\n"); + _fprint(1, "Hello %s\n", "Mohamed"); + _fprint(1, "Hello I'm %s and I'm %d\n", "Med", 25); + _fprint(1, "negative %d\n", -330); + _fprint(1, "zero %d\n", 0); + return (0); +} diff --git a/tests/_split_test.c b/tests/_split_test.c index 3483852..adee109 100644 --- a/tests/_split_test.c +++ b/tests/_split_test.c @@ -3,7 +3,7 @@ int main(void) { - char **s = _split("hello||world|again|and&&again&&", "&&"); + char **s = _split("echo hello world > file | ls -la ns; echo hello world | hi mmm", "|"); char **v = s; while (*v) { diff --git a/tests/_stat.c b/tests/_stat.c new file mode 100644 index 0000000..b09ed9b --- /dev/null +++ b/tests/_stat.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +char *_combine_path(const char *s1, const char *s2) +{ + size_t len1, len2; + size_t iterator; + char *new_string; + + len1 = strlen(s1); + len2 = strlen(s2); + new_string = malloc(sizeof(char) * (len1 + len2 + 2)); + if (!new_string) + return (NULL); + iterator = 0; + while (iterator < len1) + { + new_string[iterator] = s1[iterator]; + iterator++; + } + new_string[iterator] = '/'; + iterator++; + while (iterator - len1 - 1 < len2) + { + new_string[iterator] = s2[iterator - len1 - 1]; + iterator++; + } + new_string[iterator] = 0; + return (new_string); +} + +int main(void) +{ + struct stat s; + + char *str = _combine_path("/bin", "ls"); + printf("%s\n", str); + free(str); + // printf("is command exist %d\n", stat("/bin/s", &s)); + return (0); +} diff --git a/tests/_test_list.c b/tests/_test_list.c new file mode 100644 index 0000000..f16a69e --- /dev/null +++ b/tests/_test_list.c @@ -0,0 +1,38 @@ +#include "../shell.h" +#include + +void free_int(void *data) +{ + free(data); +} + +int main() +{ + list_t *my_list = NULL; + + int *num1 = (int *)malloc(sizeof(int)); + *num1 = 10; + add_to_list(&my_list, num1); + + int *num2 = (int *)malloc(sizeof(int)); + *num2 = 20; + add_to_list(&my_list, num2); + + int *num3 = (int *)malloc(sizeof(int)); + *num3 = 30; + add_to_list(&my_list, num3); + + int *num4 = malloc(sizeof(int)); + *num4 = 40; + add_to_list(&my_list, num4); + printf("List elements:\n"); + while (my_list != NULL) + { + int *num = (int *)pop_from_list(&my_list); + printf("%d\n", *num); + free(num); + } + + free_list(my_list, free_int); + return 0; +} diff --git a/tests/_test_signals.c b/tests/_test_signals.c new file mode 100644 index 0000000..b7c4db2 --- /dev/null +++ b/tests/_test_signals.c @@ -0,0 +1,18 @@ +#include +#include + +void _handle_signal(int sig) +{ + (void)sig; + + write(1, "CTRL-C\n", 7); +} + +int main(void) +{ + signal(SIGINT, _handle_signal); + while (1) + { + sleep(1); + } +} diff --git a/tests/fc b/tests/fc new file mode 100644 index 0000000..e69de29 diff --git a/tests/file b/tests/file index fb2d91c..82b86fa 100644 --- a/tests/file +++ b/tests/file @@ -1,21 +1,2 @@ -Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia, -molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum -numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium -optio, eaque rerum! Provident similique accusantium nemo autem. Veritatis -obcaecati tenetur iure eius earum ut molestias architecto voluptate aliquam -nihil, eveniet aliquid culpa officia aut! Impedit sit sunt quaerat, odit, -tenetur error, harum nesciunt ipsum debitis quas aliquid. Reprehenderit, -quia. Quo neque error repudiandae fuga? Ipsa laudantium molestias eos -sapiente officiis modi at sunt excepturi expedita sint? Sed quibusdam -recusandae alias error harum maxime adipisci amet laborum. Perspiciatis -minima nesciunt dolorem! Officiis iure rerum voluptates a cumque velit -quibusdam sed amet tempora. Sit laborum ab, eius fugit doloribus tenetur -fugiat, temporibus enim commodi iusto libero magni deleniti quod quam -consequuntur! Commodi minima excepturi repudiandae velit hic maxime -doloremque. Quaerat provident commodi consectetur veniam similique ad -earum omnis ipsum saepe, voluptas, hic voluptates pariatur est explicabo -fugiat, dolorum eligendi quam cupiditate excepturi mollitia maiores labore -suscipit quas? Nulla, placeat. Voluptatem quaerat non architecto ab laudantium -modi minima sunt esse temporibus sint culpa, recusandae aliquam numquam -totam ratione voluptas quod exercitationem fuga. Possimus quis earum veniam -quasi aliquam eligendi, placeat qui corporis! +/bin/ls -la | /bin/cat +/bin/echo hello wolrd \ No newline at end of file diff --git a/tests/getline_test.c b/tests/getline_test.c index d51cc96..bbaa822 100644 --- a/tests/getline_test.c +++ b/tests/getline_test.c @@ -12,7 +12,7 @@ int main(void) ret = _getline(&line); if (!line) break; - printf("%s\n", line); + printf("-> %s\n", line); free(line); } return (0);