From 217eed697b4345bab9acf4c082311b3428f9baae Mon Sep 17 00:00:00 2001 From: johncoleman83 Date: Mon, 17 Apr 2017 07:10:26 +0000 Subject: [PATCH] made all files contain only 5 functions, updated Makefile, updated README and header to incorporate the file changes --- Makefile | 39 +++-- README.md | 78 ++++----- alias.c | 304 ---------------------------------- aliasA.c | 144 ++++++++++++++++ aliasB.c | 97 +++++++++++ builtin_funcs.c => builtinA.c | 39 ----- builtinB.c | 104 ++++++++++++ environA.c | 89 ++++++++++ environB.c | 126 ++++++++++++++ execfuncs.c => executeA.c | 115 ------------- executeB.c | 115 +++++++++++++ free.c | 4 +- header.h | 6 +- help.c => helpA.c | 42 +++-- helpB.c | 40 +++++ history.c | 18 +- linked_helper.c | 247 --------------------------- parse.c | 224 ------------------------- parseA.c | 123 ++++++++++++++ parseB.c | 82 +++++++++ strings.c | 247 --------------------------- stringsA.c | 116 +++++++++++++ stringsB.c | 64 +++++++ stringsC.c | 122 ++++++++++++++ tokenize.c | 180 ++++++++++++++++++++ tokenizer.c | 179 -------------------- 26 files changed, 1506 insertions(+), 1438 deletions(-) delete mode 100644 alias.c create mode 100644 aliasA.c create mode 100644 aliasB.c rename builtin_funcs.c => builtinA.c (73%) create mode 100644 builtinB.c create mode 100644 environA.c create mode 100644 environB.c rename execfuncs.c => executeA.c (50%) create mode 100644 executeB.c rename help.c => helpA.c (55%) create mode 100644 helpB.c delete mode 100644 linked_helper.c delete mode 100644 parse.c create mode 100644 parseA.c create mode 100644 parseB.c delete mode 100644 strings.c create mode 100644 stringsA.c create mode 100644 stringsB.c create mode 100644 stringsC.c create mode 100644 tokenize.c diff --git a/Makefile b/Makefile index daa975a..6dcf3e3 100644 --- a/Makefile +++ b/Makefile @@ -4,26 +4,35 @@ LIBS= EXENAME=hsh CFILES=\ - strings.c\ + aliasA.c\ + aliasB.c\ + builtinA.c\ + builtinB.c\ + cd.c\ + environA.c\ + environB.c\ + executeA.c\ + executeB.c\ + file_io.c\ + free.c\ getline.c\ + helpA.c\ + helpB.c\ + history.c\ memmalloc.c\ - linked_helper.c\ - execfuncs.c\ - tokenizer.c\ - builtin_funcs.c\ - file_io.c\ - stdlib_funcs.c\ + parseA.c\ + parseB.c\ path.c\ + pipeline.c\ ptree.c\ - parse.c\ - history.c\ + stdlib_funcs.c\ + stringsA.c\ + stringsB.c\ + stringsC.c\ + tokenize.c\ + tokenizer.c\ worker.c\ - pipeline.c\ - write.c\ - free.c\ - alias.c\ - help.c\ - cd.c + write.c GLOBAL_HEADERS=\ header.h diff --git a/README.md b/README.md index 5bef4a3..d7d83ae 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ our blog posting here: ### C language files (`.c`) -* `alias.c` +* `aliasA.c` and `aliasB.c` #### All alias functions @@ -75,13 +75,10 @@ our blog posting here: adds new node (struct from linked list) to alias list -* `builtin_funcs.c` +* `builtinA.c` and `builtinB.c` #### Functions to execute builtins - * `int _monalisa(arg_inventory_t *arginv)` - - easter egg * `int _env(arg_inventory_t *arginv)` prints custom environment @@ -114,7 +111,7 @@ our blog posting here: * `char *yellow_brick_road(char **commands, env_t *envlist)` * `env_t *fetch_node(env_t *head, char *var)` -* `execfuncs.c` +* `executeA.c` and `executeB.c` #### functions to execute input commands @@ -122,6 +119,35 @@ our blog posting here: * `pid_t execute(arg_inventory_t *arginv)` * `int exec_builtins(arg_inventory_t *arginv)` * `pid_t exec_path(char *command, arg_inventory_t *arginv)` + * `void safe_dup2(int new_fd, int old_fd)` + * `int redirect_output(arg_inventory_t *arginv, int close_dup)` + * `void redirect_input(arg_inventory_t *arginv)` + +* `environA.c` and `environB.c` + + #### custom environmental variables list, add variables, and change variables + + * `env_t *env_list(void)` + + initializes custom enviromental variable list + * `char **separate_string(char *string)` + + separates a string at the first '=' sign into 2 strings of a `char **` type + * `unsigned int link_count(env_t *head)` + + counts number of nodes in environ + * `char **zelda_to_ganondorf(env_t *head)` + + converts linked list into `char **` type + * `env_t *add_node_env(env_t **head, char *var, char *val)` + + adds new node (struct of linked list) to custom environmental variable list + * `int modify_node_env(env_t **head, char *new_var, char *new_val)` + + modifies a node from custom environmental variable list (environ) + * `int remove_node_env(env_t **head, char *var)` + + removes a node from env list * `file_io.c` @@ -162,7 +188,7 @@ our blog posting here: checks the st_mode that the shell is being executed from either from terminal or pipe -* `help.c` +* `helpA.c` and `helpB.c` #### functions to print help information on each function These functions write the help builtins help text to stdout. Each function is named after the help text that it writes. @@ -198,32 +224,6 @@ our blog posting here: used in the initialization function, this function copies old history into current history linked list -* `linked_helper.c` - - #### custom environmental variables list, add variables, and change variables - - * `env_t *env_list(void)` - - initializes custom enviromental variable list - * `char **separate_string(char *string)` - - separates a string at the first '=' sign into 2 strings of a `char **` type - * `unsigned int link_count(env_t *head)` - - counts number of nodes in environ - * `char **zelda_to_ganondorf(env_t *head)` - - converts linked list into `char **` type - * `env_t *add_node_env(env_t **head, char *var, char *val)` - - adds new node (struct of linked list) to custom environmental variable list - * `int modify_node_env(env_t **head, char *new_var, char *new_val)` - - modifies a node from custom environmental variable list (environ) - * `int remove_node_env(env_t **head, char *var)` - - removes a node from env list - * `main.c` #### main function and arguments inventory function @@ -249,7 +249,7 @@ our blog posting here: reallocates new memory, used for buffer for large inputs -* `parse.c` +* `parseA.c` and `parseB.c #### functions working with parser: @@ -293,7 +293,7 @@ our blog posting here: replicates standard library -* `strings.c` +* `stringsA.c`, `stringsB.c` and `stringsC.c` #### functions contianed in this file: @@ -309,8 +309,9 @@ our blog posting here: * `char *_strcat(char *dest, char *src)` * `char *int_to_str(unsigned int n)` * `char *_str_replace(char *string, unsigned int start, unsigned int end, char *rep)` + * `void replace_str(char **old_str, char *new_str, int i, int j, int flg)` -* `tokenizer.c` +* `tokenize.c` and `tokenizer.c` #### functions contianed in this file: @@ -319,12 +320,13 @@ our blog posting here: * `int dump_token(tokens_t *tokens)` * `const char *dump_get_token_descr(int token_id)` * `int is_redirection(int token_id)` + * `void init_tokens(tokens_t *tokens, int length)` * `worker.c` #### functions contianed in this file: -* `int worker_execute_core(arg_inventory_t *arginv)` +* `int worker_execute_core(arg_inventory_t *arginv)` * `int worker_execute(arg_inventory_t *arginv)` * `write.c` @@ -358,3 +360,5 @@ David John Coleman II - http://www.davidjohncoleman.com/ ## License Public Domain, no copyright protection + +_special thanks to monalisa_ \ No newline at end of file diff --git a/alias.c b/alias.c deleted file mode 100644 index a935106..0000000 --- a/alias.c +++ /dev/null @@ -1,304 +0,0 @@ -#include "header.h" -/** - * alias_list - builtin func to set alias list - * - * Return: 0 on success - */ -alias_t *alias_list(void) -{ - alias_t *head; - - head = NULL; - - return (head); -} - -/** - * _alias - builtin func to set alias - * @arginv: arguments inventory - * - * Return: 0 on success - */ -int _alias(arg_inventory_t *arginv) -{ - char *input, **combo, **commands; - - commands = (char **)arginv->commands; - - if (commands[1] == NULL) - { - write_alias(arginv->alias); - return (EXT_SUCCESS); - } - else if (commands[2] != NULL) - { - perror("alias: too many arguments."); - return (-1); - } - - input = commands[1]; - - combo = separate_string(input); - - if (modify_node_alias(&arginv->alias, combo[0], combo[1]) == EXT_FAILURE) - { - add_node_alias(&arginv->alias, combo[0], combo[1]); - } - return (EXT_SUCCESS); -} - -/** - * _unalias - builtin func to unset alias - * @arginv: arguments inventory - * - * Return: 0 on success - */ -int _unalias(arg_inventory_t *arginv) -{ - char **commands; - - commands = (char **)arginv->commands; - - if (commands[1] == NULL) - { - perror("unalias: missing arguments."); - return (-1); - } - - if (commands[2] != NULL) - { - perror("unalias: too many arguments."); - return (-1); - } - - if (remove_node_alias(&arginv->alias, commands[1]) == EXT_SUCCESS) - return (EXT_SUCCESS); - - return (EXT_FAILURE); -} - -/** - * add_node_alias - builtin func to set alias - * @head: head of alias list - * @alias: alias ot add - * @command: actual command equivalent to alias - * - * Return: 0 on success - */ - -alias_t *add_node_alias(alias_t **head, char *alias, char *command) -{ - alias_t *new_node, *temp; - - new_node = malloc(sizeof(alias_t)); - if (new_node == NULL) - return (NULL); - - new_node->alias = _strdup(alias); - new_node->command = _strdup(command); - new_node->next = NULL; - - if (!*head) - *head = new_node; - else - { - temp = *head; - - while (temp->next) - temp = temp->next; - - temp->next = new_node; - } - - return (new_node); -} - -/** - * modify_node_alias - checks to see if node exists, and modifies it if so. - * @head: beginning of linked list - * @new_var: variable to modify - * @new_val: new string to be modified to found node - * - * Return: pointer to new node or NULL if fail - */ -int modify_node_alias(alias_t **head, char *new_var, char *new_val) -{ - alias_t *temp; - - temp = *head; - - while (temp) - { - if (_strcmp(temp->alias, new_var) == 0) - { - free(temp->command); - temp->command = _strdup(new_val); - - return (EXT_SUCCESS); - } - temp = temp->next; - } - - return (EXT_FAILURE); -} - - -/** - * remove_node_alias - removes node from linked list - * @head: beginning of linked list - * @var: var of node to be removed from linked list - * - * Return: pointer to new node or NULL - */ -int remove_node_alias(alias_t **head, char *var) -{ - alias_t *copy_head = *head, *temp = *head; - - if (head == NULL) - return (EXT_FAILURE); - copy_head = NULL; - while (temp) - { - if (_strcmp(temp->alias, var) == 0) - { - if (copy_head) - copy_head->next = temp->next; - else - *head = temp->next; - - free(temp->alias); - free(temp->command); - free(temp); - - return (EXT_SUCCESS); - } - copy_head = temp; - temp = temp->next; - } - - return (EXT_FAILURE); -} - - -/** - * write_alias - function to write alias list to stdout for testing - * @head: head of alias list - * - * Return: chars written - */ -int write_alias(alias_t *head) -{ - int i = 0; - alias_t *temp = head; - - while (temp) - { - write(STDOUT_FILENO, temp->alias, _strlen(temp->alias)); - write(STDOUT_FILENO, "=\"", 2); - write(STDOUT_FILENO, temp->command, _strlen(temp->command)); - write(STDOUT_FILENO, "\"\n", 2); - - temp = temp->next; - i++; - - } - - return (i); -} - -/** - * save_alias - saves alias definitions to file - * @arginv: arguments inventory - * - * Return: 0 success, 1 failure - */ -int save_alias(arg_inventory_t *arginv) -{ - char *file = ".simple_shell_alias"; - char *buffer; - alias_t *tmp = arginv->alias; - int fd; - - fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666); - close(fd); - - while (tmp) - { - buffer = (char *)safe_malloc(_strlen(tmp->alias) + _strlen(tmp->alias) + 4); - _strcpy(buffer, tmp->alias); - _strcat(buffer, ":"); - _strcat(buffer, tmp->command); - _strcat(buffer, "\n"); - append_text_to_file(file, buffer); - tmp = tmp->next; - } - - return (0); -} - -/** - * load_alias - loads alias definitions from file - * @arginv: arguments inventory - * - * Return: 0 success, 1 failure - */ -int load_alias(arg_inventory_t *arginv) -{ - char *file = ".simple_shell_alias"; - char *buffer, *val; - int fd; - ssize_t count; - size_t sz = BUFSIZE; - - fd = open(file, O_RDONLY); - if (fd == -1) - return (1); - - buffer = (char *)safe_malloc(sz); - - while ((count = _readline(fd, &buffer, &sz)) != 0) - { - while (buffer[count - 1] == '\n') - buffer[count - 1] = '\0'; - - val = buffer; - - while (*val && *val != ':') - val++; - - if (!*val) - break; - - *(val++) = '\0'; - - add_node_alias(&arginv->alias, buffer, val); - } - free(buffer); - close(fd); - return (0); -} - -/** - * fetch_node_alias - fetches a node of a given alias - * @head: head of list - * @var: alias to match of the node to fetch - * - * Return: fetched node or NULL - */ -alias_t *fetch_node_alias(alias_t *head, char *var) -{ - alias_t *tmp; - - tmp = head; - - while (tmp != NULL) - { - if (_strcmp(tmp->alias, var) == 0) - return (tmp); - - tmp = tmp->next; - } - - return (NULL); -} - diff --git a/aliasA.c b/aliasA.c new file mode 100644 index 0000000..cc2ab59 --- /dev/null +++ b/aliasA.c @@ -0,0 +1,144 @@ +#include "header.h" + +/** + * alias_list - builtin func to set alias list + * + * Return: 0 on success + */ +alias_t *alias_list(void) +{ + alias_t *head; + + head = NULL; + + return (head); +} + +/** + * add_node_alias - builtin func to set alias + * @head: head of alias list + * @alias: alias ot add + * @command: actual command equivalent to alias + * + * Return: 0 on success + */ + +alias_t *add_node_alias(alias_t **head, char *alias, char *command) +{ + alias_t *new_node, *temp; + + new_node = malloc(sizeof(alias_t)); + if (new_node == NULL) + return (NULL); + + new_node->alias = _strdup(alias); + new_node->command = _strdup(command); + new_node->next = NULL; + + if (!*head) + *head = new_node; + else + { + temp = *head; + + while (temp->next) + temp = temp->next; + + temp->next = new_node; + } + + return (new_node); +} + +/** + * modify_node_alias - checks to see if node exists, and modifies it if so. + * @head: beginning of linked list + * @new_var: variable to modify + * @new_val: new string to be modified to found node + * + * Return: pointer to new node or NULL if fail + */ +int modify_node_alias(alias_t **head, char *new_var, char *new_val) +{ + alias_t *temp; + + temp = *head; + + while (temp) + { + if (_strcmp(temp->alias, new_var) == 0) + { + free(temp->command); + temp->command = _strdup(new_val); + + return (EXT_SUCCESS); + } + temp = temp->next; + } + + return (EXT_FAILURE); +} + + +/** + * remove_node_alias - removes node from linked list + * @head: beginning of linked list + * @var: var of node to be removed from linked list + * + * Return: pointer to new node or NULL + */ +int remove_node_alias(alias_t **head, char *var) +{ + alias_t *copy_head = *head, *temp = *head; + + if (head == NULL) + return (EXT_FAILURE); + copy_head = NULL; + while (temp) + { + if (_strcmp(temp->alias, var) == 0) + { + if (copy_head) + copy_head->next = temp->next; + else + *head = temp->next; + + free(temp->alias); + free(temp->command); + free(temp); + + return (EXT_SUCCESS); + } + copy_head = temp; + temp = temp->next; + } + + return (EXT_FAILURE); +} + + +/** + * write_alias - function to write alias list to stdout for testing + * @head: head of alias list + * + * Return: chars written + */ +int write_alias(alias_t *head) +{ + int i = 0; + alias_t *temp = head; + + while (temp) + { + write(STDOUT_FILENO, temp->alias, _strlen(temp->alias)); + write(STDOUT_FILENO, "=\"", 2); + write(STDOUT_FILENO, temp->command, _strlen(temp->command)); + write(STDOUT_FILENO, "\"\n", 2); + + temp = temp->next; + i++; + + } + + return (i); +} diff --git a/aliasB.c b/aliasB.c new file mode 100644 index 0000000..042b625 --- /dev/null +++ b/aliasB.c @@ -0,0 +1,97 @@ +#include "header.h" + +/** + * save_alias - saves alias definitions to file + * @arginv: arguments inventory + * + * Return: 0 success, 1 failure + */ +int save_alias(arg_inventory_t *arginv) +{ + char *file = ".simple_shell_alias"; + char *buffer; + alias_t *tmp = arginv->alias; + int fd; + + fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666); + close(fd); + + while (tmp) + { + buffer = (char *)safe_malloc(_strlen(tmp->alias) + _strlen(tmp->alias) + 4); + _strcpy(buffer, tmp->alias); + _strcat(buffer, ":"); + _strcat(buffer, tmp->command); + _strcat(buffer, "\n"); + append_text_to_file(file, buffer); + tmp = tmp->next; + } + + return (0); +} + +/** + * load_alias - loads alias definitions from file + * @arginv: arguments inventory + * + * Return: 0 success, 1 failure + */ +int load_alias(arg_inventory_t *arginv) +{ + char *file = ".simple_shell_alias"; + char *buffer, *val; + int fd; + ssize_t count; + size_t sz = BUFSIZE; + + fd = open(file, O_RDONLY); + if (fd == -1) + return (1); + + buffer = (char *)safe_malloc(sz); + + while ((count = _readline(fd, &buffer, &sz)) != 0) + { + while (buffer[count - 1] == '\n') + buffer[count - 1] = '\0'; + + val = buffer; + + while (*val && *val != ':') + val++; + + if (!*val) + break; + + *(val++) = '\0'; + + add_node_alias(&arginv->alias, buffer, val); + } + free(buffer); + close(fd); + return (0); +} + +/** + * fetch_node_alias - fetches a node of a given alias + * @head: head of list + * @var: alias to match of the node to fetch + * + * Return: fetched node or NULL + */ +alias_t *fetch_node_alias(alias_t *head, char *var) +{ + alias_t *tmp; + + tmp = head; + + while (tmp != NULL) + { + if (_strcmp(tmp->alias, var) == 0) + return (tmp); + + tmp = tmp->next; + } + + return (NULL); +} diff --git a/builtin_funcs.c b/builtinA.c similarity index 73% rename from builtin_funcs.c rename to builtinA.c index 892b3b9..684a2b9 100644 --- a/builtin_funcs.c +++ b/builtinA.c @@ -111,42 +111,3 @@ int _monalisa(arg_inventory_t *arginv) return (EXT_SUCCESS); } - -/** - * the_help - prints mona lisa ascii art - * @arginv: arguments inventory - * - * Return: 0 on success - */ -int the_help(arg_inventory_t *arginv) -{ - char **commands; - int i = 0; - bins_t bins[] = { - {"exit", h_exit}, {"monalisa", h_monalisa}, {"env", h_env}, - {"setenv", h_setenv}, {"unsetenv", h_unsetenv}, - {"history", h_history}, {"cd", h_cd}, {"alias", h_alias}, - {"help", h_help}, - {NULL, NULL} - }; - - - commands = (char **)arginv->commands; - if (commands[2] != NULL) - { - perror("help: too many input commands."); - return (-1); - } - - while (bins[i].function != NULL) - { - if (_strcmp(bins[i].function, commands[1]) == 0) - { - bins[i].help(); - break; - } - i++; - } - - return (EXT_SUCCESS); -} diff --git a/builtinB.c b/builtinB.c new file mode 100644 index 0000000..e82a454 --- /dev/null +++ b/builtinB.c @@ -0,0 +1,104 @@ +#include "header.h" + +/** + * _alias - builtin func to set alias + * @arginv: arguments inventory + * + * Return: 0 on success + */ +int _alias(arg_inventory_t *arginv) +{ + char *input, **combo, **commands; + + commands = (char **)arginv->commands; + + if (commands[1] == NULL) + { + write_alias(arginv->alias); + return (EXT_SUCCESS); + } + else if (commands[2] != NULL) + { + perror("alias: too many arguments."); + return (-1); + } + + input = commands[1]; + + combo = separate_string(input); + + if (modify_node_alias(&arginv->alias, combo[0], combo[1]) == EXT_FAILURE) + { + add_node_alias(&arginv->alias, combo[0], combo[1]); + } + return (EXT_SUCCESS); +} + +/** + * _unalias - builtin func to unset alias + * @arginv: arguments inventory + * + * Return: 0 on success + */ +int _unalias(arg_inventory_t *arginv) +{ + char **commands; + + commands = (char **)arginv->commands; + + if (commands[1] == NULL) + { + perror("unalias: missing arguments."); + return (-1); + } + + if (commands[2] != NULL) + { + perror("unalias: too many arguments."); + return (-1); + } + + if (remove_node_alias(&arginv->alias, commands[1]) == EXT_SUCCESS) + return (EXT_SUCCESS); + + return (EXT_FAILURE); +} + +/** + * the_help - prints mona lisa ascii art + * @arginv: arguments inventory + * + * Return: 0 on success + */ +int the_help(arg_inventory_t *arginv) +{ + char **commands; + int i = 0; + bins_t bins[] = { + {"exit", h_exit}, {"monalisa", h_monalisa}, {"env", h_env}, + {"setenv", h_setenv}, {"unsetenv", h_unsetenv}, + {"history", h_history}, {"cd", h_cd}, {"alias", h_alias}, + {"help", h_help}, + {NULL, NULL} + }; + + + commands = (char **)arginv->commands; + if (commands[2] != NULL) + { + perror("help: too many input commands."); + return (-1); + } + + while (bins[i].function != NULL) + { + if (_strcmp(bins[i].function, commands[1]) == 0) + { + bins[i].help(); + break; + } + i++; + } + + return (EXT_SUCCESS); +} diff --git a/environA.c b/environA.c new file mode 100644 index 0000000..f8f4c1d --- /dev/null +++ b/environA.c @@ -0,0 +1,89 @@ +#include "header.h" + +/** + * link_count - counts number of nodes in linked list + * @head: pointer to head of linked list + * + * Return: number of nodes + */ +unsigned int link_count(env_t *head) +{ + env_t *tmp; + unsigned int count; + + tmp = head; + count = 0; + + while (tmp != NULL) + { + tmp = tmp->next; + count++; + } + + return (count); +} + +/** + * env_list - creates a linked list of all environ variables + * + * Return: head (pointer to first node of linked list of environ variables) + */ +env_t *env_list(void) +{ + int i; + env_t *head; + char **variable; + head = NULL; + + for (i = 0; environ[i] != NULL; i++) + { + variable = separate_string(environ[i]); + if (add_node_env(&head, variable[0], variable[1]) == NULL) + return (NULL); + free(variable[0]); + free(variable[1]); + free(variable); + } + + return (head); +} + +/** + * zelda_to_ganondorf - converts linked list to double pointer + * @head: head pointer to head of linked list + * + * Return: array of pointers, pointing to strings + */ +char **zelda_to_ganondorf(env_t *head) +{ + int i; + unsigned int count, len1, len2, lennew; + char **ganondorf, *var, *val, *new_val; + env_t *tmp; + + count = link_count(head); + ganondorf = malloc(sizeof(char *) * (count + 1)); + + tmp = head; + i = 0; + while (tmp != NULL) + { + var = tmp->var; + val = tmp->val; + len1 = _strlen(var); + len2 = _strlen(val); + + lennew = len1 + len2 + 2; + new_val = safe_malloc(lennew * sizeof(char)); + + _strncat(new_val, var, len1); + _strncat(new_val, "=", 1); + _strncat(new_val, val, len2); + ganondorf[i] = new_val; + tmp = tmp->next; + i++; + } + ganondorf[i] = NULL; + + return (ganondorf); +} diff --git a/environB.c b/environB.c new file mode 100644 index 0000000..1444c02 --- /dev/null +++ b/environB.c @@ -0,0 +1,126 @@ +#include "header.h" + +/** + * add_node_env - adds new node to end of linked list + * @head: beginning of linked list + * @str: new string to be added to linked list + * + * Return: pointer to new node + */ +env_t *add_node_env(env_t **head, char *var, char *val) +{ + env_t *new_node, *temp; + new_node = malloc(sizeof(env_t)); + if (new_node == NULL) + return (NULL); + + new_node->var = _strdup(var); + new_node->val = _strdup(val); + new_node->next = NULL; + + if (!*head) + { + *head = new_node; + } + else + { + temp = *head; + + while (temp->next) + temp = temp->next; + + temp->next = new_node; + } + + return (new_node); +} + +/** + * modify_node_env - checks to see if node exists, and modifies it if so. + * @head: beginning of linked list + * @new_var: variable to modify + * @new_val: new string to be modified to found node + * + * Return: pointer to new node or NULL if fail + */ +int modify_node_env(env_t **head, char *new_var, char *new_val) +{ + env_t *temp; + + temp = *head; + + while (temp) + { + if (_strcmp(temp->var, new_var) == 0) + { + free(temp->val); + temp->val = _strdup(new_val); + + return (EXT_SUCCESS); + } + temp = temp->next; + } + + return (EXT_FAILURE); +} + +/** + * remove_node_env - removes node from linked list + * @head: beginning of linked list + * @var: var of node to be removed from linked list + * + * Return: pointer to new node or NULL + */ +int remove_node_env(env_t **head, char *var) +{ + env_t *copy_head = *head, *temp = *head; + + if (head == NULL) + return (EXT_FAILURE); + + copy_head=NULL; + + while (temp) + { + if (_strcmp(temp->var, var) == 0) + { + if (copy_head) + copy_head->next = temp->next; + else + *head = temp->next; + + free(temp->var); + free(temp->val); + free(temp); + + return (EXT_SUCCESS); + } + copy_head = temp; + temp = temp->next; + } + + return (EXT_FAILURE); +} + +/** + * fetch_node - fetches a node of a given var + * @head: head of list + * @var: value to match of the node to fetch + * + * Return: fetched node or head + */ +env_t *fetch_node(env_t *head, char *var) +{ + env_t *tmp; + tmp = head; + + while (tmp != NULL) + { + if (_strcmp(tmp->var, var) == 0) + return (tmp); + else + tmp = tmp->next; + } + + return (NULL); +} diff --git a/execfuncs.c b/executeA.c similarity index 50% rename from execfuncs.c rename to executeA.c index 0249020..d3a6dbc 100644 --- a/execfuncs.c +++ b/executeA.c @@ -1,99 +1,5 @@ #include "header.h" -/** - * safe_dup2 - make a dup2 and exit if an error is found - * @new_fd: file descriptor to use - * @old_fd: file descriptor to replace - * - */ -void safe_dup2(int new_fd, int old_fd) -{ - if (dup2(new_fd, old_fd) < 0) - { - perror("dup2"); - exit(1); - } -} - -/** - * redirect_output - redirect stdout depending on the pipeline and the redirection token - * @arginv: arguments inventory - * @close_dup: if 1 closes duplicated fd - * - * Return: old stdout file descriptor - */ -int redirect_output(arg_inventory_t *arginv, int close_dup) -{ - int stdout_fd; - int old_stdout; - - /** either a > or a >> */ - if (arginv->io_redir == TOKEN_REWRITE || arginv->io_redir == TOKEN_APPEND) - { - /* it's a > */ - if (arginv->io_redir == TOKEN_REWRITE) - /* create file for write, create and truncate */ - stdout_fd = open(arginv->filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); - /* it's a >> */ - else - /** create file for create and append, does not truncate */ - stdout_fd = open(arginv->filename, O_WRONLY | O_CREAT | O_APPEND, 0666); - - /* save current stdout */ - old_stdout = dup(STDOUT_FILENO); - - /* redirect stdout */ - safe_dup2(stdout_fd, STDOUT_FILENO); - - if (close_dup) - { - close(stdout_fd); - if (arginv->pipeout) - close(arginv->pipeout); - } - } - - else if (arginv->pipeout) - { - /* save current stdout */ - old_stdout = dup(STDOUT_FILENO); - - /* redirect stdout */ - safe_dup2(arginv->pipeout, STDOUT_FILENO); - } - - return (old_stdout); -} - -/** - * redirect_input - redirect stdin depending on the pipeline and the redirection token - * @arginv: arguments inventory - * - */ -void redirect_input(arg_inventory_t *arginv) -{ - int stdin_fd; - - /* it's a < */ - if (arginv->io_redir == TOKEN_CAT) - { - /* open file to read */ - stdin_fd = open(arginv->filename, O_RDONLY); - safe_dup2(stdin_fd, STDIN_FILENO); - - close(stdin_fd); - - if (arginv->pipein) - /* unused file descriptor */ - close(arginv->pipein); - } - else if (arginv->pipein) - { - safe_dup2(arginv->pipein, STDIN_FILENO); - } -} - - /** * exec_builtins - custom function to execute builtin commands * @arginv: arguments inventory @@ -172,27 +78,6 @@ pid_t exec_path(char *command, arg_inventory_t *arginv) return (pid); } -/** - * is_path - checks if input command is part of directory PATH - * @command: a command - * - * Return: 1 if path, 0 if no path - */ -int is_path(char *command) -{ - int i; - - i = 0; - while (command[i] != '\0') - { - if (command[i] == '/') - return (1); - i++; - } - - return (0); -} - /** * execute - completes execution of input commands * @arginv: arguments inventory diff --git a/executeB.c b/executeB.c new file mode 100644 index 0000000..e793cc5 --- /dev/null +++ b/executeB.c @@ -0,0 +1,115 @@ +#include "header.h" + +/** + * safe_dup2 - make a dup2 and exit if an error is found + * @new_fd: file descriptor to use + * @old_fd: file descriptor to replace + * + */ +void safe_dup2(int new_fd, int old_fd) +{ + if (dup2(new_fd, old_fd) < 0) + { + perror("dup2"); + exit(1); + } +} + +/** + * redirect_output - redirect stdout depending on the pipeline and the redirection token + * @arginv: arguments inventory + * @close_dup: if 1 closes duplicated fd + * + * Return: old stdout file descriptor + */ +int redirect_output(arg_inventory_t *arginv, int close_dup) +{ + int stdout_fd; + int old_stdout; + + /** either a > or a >> */ + if (arginv->io_redir == TOKEN_REWRITE || arginv->io_redir == TOKEN_APPEND) + { + /* it's a > */ + if (arginv->io_redir == TOKEN_REWRITE) + /* create file for write, create and truncate */ + stdout_fd = open(arginv->filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); + /* it's a >> */ + else + /** create file for create and append, does not truncate */ + stdout_fd = open(arginv->filename, O_WRONLY | O_CREAT | O_APPEND, 0666); + + /* save current stdout */ + old_stdout = dup(STDOUT_FILENO); + + /* redirect stdout */ + safe_dup2(stdout_fd, STDOUT_FILENO); + + if (close_dup) + { + close(stdout_fd); + if (arginv->pipeout) + close(arginv->pipeout); + } + } + + else if (arginv->pipeout) + { + /* save current stdout */ + old_stdout = dup(STDOUT_FILENO); + + /* redirect stdout */ + safe_dup2(arginv->pipeout, STDOUT_FILENO); + } + + return (old_stdout); +} + +/** + * redirect_input - redirect stdin depending on the pipeline and the redirection token + * @arginv: arguments inventory + * + */ +void redirect_input(arg_inventory_t *arginv) +{ + int stdin_fd; + + /* it's a < */ + if (arginv->io_redir == TOKEN_CAT) + { + /* open file to read */ + stdin_fd = open(arginv->filename, O_RDONLY); + safe_dup2(stdin_fd, STDIN_FILENO); + + close(stdin_fd); + + if (arginv->pipein) + /* unused file descriptor */ + close(arginv->pipein); + } + else if (arginv->pipein) + { + safe_dup2(arginv->pipein, STDIN_FILENO); + } +} + +/** + * is_path - checks if input command is part of directory PATH + * @command: a command + * + * Return: 1 if path, 0 if no path + */ +int is_path(char *command) +{ + int i; + + i = 0; + while (command[i] != '\0') + { + if (command[i] == '/') + return (1); + i++; + } + + return (0); +} diff --git a/free.c b/free.c index 297aec8..6bfef42 100644 --- a/free.c +++ b/free.c @@ -26,7 +26,7 @@ int freeall(arg_inventory_t *arginv) /** * free_alias - function to free all allocated memory - * @head - head of alias + * @head: head of alias * * Return: 0 on success, 1 on failure */ @@ -48,7 +48,7 @@ int free_alias(alias_t *head) /** * free_environ - function to free all allocated memory - * @head - head of custom _environ + * @head: head of custom _environ * * Return: 0 on success, 1 on failure */ diff --git a/header.h b/header.h index beed398..f565193 100644 --- a/header.h +++ b/header.h @@ -48,6 +48,9 @@ ssize_t _readline(int fd,char **buffer, size_t *limit); pid_t execute(arg_inventory_t *arginv); int exec_builtins(arg_inventory_t *arginv); pid_t exec_path(char *command, arg_inventory_t *arginv); +void safe_dup2(int new_fd, int old_fd); +int redirect_output(arg_inventory_t *arginv, int close_dup); +void redirect_input(arg_inventory_t *arginv); /* ---------------tokenizer--------------- */ int delete_tokens(tokens_t *tokens); @@ -55,6 +58,7 @@ int tokenize(tokens_t *tokens, const char *string); int dump_token(tokens_t *tokens); const char *dump_get_token_descr(int token_id); int is_redirection(int token_id); +void init_tokens(tokens_t *tokens, int length); /* -------custom environ------- */ env_t *env_list(void); @@ -89,9 +93,9 @@ int _strncmp(char *s1, char *s2, unsigned int n); int _unsetenv(arg_inventory_t *arginv); char *_strcat(char *dest, char *src); char *int_to_str(unsigned int n); +void replace_str(char **old_str, char *new_str, int i, int j, int flg); char *_str_replace(char *string, unsigned int start, unsigned int end, char *rep); - /* -----custom C std lib----- */ char _isspace(char c); diff --git a/help.c b/helpA.c similarity index 55% rename from help.c rename to helpA.c index 8d2bb97..eb1e659 100644 --- a/help.c +++ b/helpA.c @@ -1,55 +1,51 @@ #include "header.h" +/** + * h_alias - help function to explain how the associated function works + */ void h_alias(void) { _puts("this is a help file:"); _puts("first: goolge your question"); _puts("second: contact developers for help"); } + +/** + * h_cd - help function to explain how the associated function works + */ void h_cd(void) { _puts("this is a help file:"); _puts("first: goolge your question"); _puts("second: contact developers for help"); } + +/** + * h_env - help function to explain how the associated function works + */ void h_env(void) { _puts("this is a help file:"); _puts("first: goolge your question"); _puts("second: contact developers for help"); } + +/** + * h_exit - help function to explain how the associated function works + */ void h_exit(void) { _puts("this is a help file:"); _puts("first: goolge your question"); _puts("second: contact developers for help"); } + +/** + * h_help - help function to explain how the associated function works + */ void h_help(void) { _puts("this is a help file:"); _puts("first: goolge your question"); _puts("second: contact developers for help"); } -void h_history(void) -{ - _puts("this is a help file:"); - _puts("first: goolge your question"); - _puts("second: contact developers for help"); -} -void h_monalisa(void) -{ _puts("this is a help file:"); - _puts("first: goolge your question"); - _puts("second: contact developers for help"); -} -void h_setenv(void) -{ - _puts("this is a help file:"); - _puts("first: goolge your question"); - _puts("second: contact developers for help"); -} -void h_unsetenv(void) -{ - _puts("this is a help file:"); - _puts("first: goolge your question"); - _puts("second: contact developers for help"); -} diff --git a/helpB.c b/helpB.c new file mode 100644 index 0000000..dbc43fe --- /dev/null +++ b/helpB.c @@ -0,0 +1,40 @@ +#include "header.h" + +/** + * h_history - help function to explain how the associated function works + */ +void h_history(void) +{ + _puts("this is a help file:"); + _puts("first: goolge your question"); + _puts("second: contact developers for help"); +} + +/** + * h_monalisa - help function to explain how the associated function works + */ +void h_monalisa(void) +{ _puts("this is a help file:"); + _puts("first: goolge your question"); + _puts("second: contact developers for help"); +} + +/** + * h_setenv - help function to explain how the associated function works + */ +void h_setenv(void) +{ + _puts("this is a help file:"); + _puts("first: goolge your question"); + _puts("second: contact developers for help"); +} + +/** + * h_unsetenv - help function to explain how the associated function works + */ +void h_unsetenv(void) +{ + _puts("this is a help file:"); + _puts("first: goolge your question"); + _puts("second: contact developers for help"); +} diff --git a/history.c b/history.c index ed492d0..4c460bf 100644 --- a/history.c +++ b/history.c @@ -1,7 +1,8 @@ #include "header.h" /** - * history_list - initializes linked list + * history_list - initializes linked list of history from history file in $HOME + * @arginv: arguments inventory * * Return: head (pointer to first node of linked list of environ variables) */ @@ -40,6 +41,13 @@ history_t *history_list(arg_inventory_t *arginv) return (head); } +/** + * init_history - initializes history using history file converted to buffer + * @head: head of linked list of history commands + * @buffer: old history backup converted to string + * + * Return: head (pointer to first node of linked list of environ variables) + */ history_t *init_history(history_t *head, char *buffer) { int marker, sublen, j, i = 0; @@ -68,7 +76,7 @@ history_t *init_history(history_t *head, char *buffer) /** * add_node_history - adds new node to end of linked list of input history - * @arginv: head of history linked list + * @head: head of history linked list * @command: new command * * Return: pointer to new node @@ -108,7 +116,7 @@ history_t *add_node_history(history_t **head, char *command) } /** - * file_history - converts history to string to file + * file_history - converts history to string to file in history file * @arginv: arguments inventory * * Return: 0 success, 1 failure @@ -138,8 +146,8 @@ int file_history(arg_inventory_t *arginv) } /** - * history_to_string - converts history to string - * @history: linked list of history + * history_to_string - converts history linked list to string + * @head: head of linked list of history * * Return: linked list converted to string */ diff --git a/linked_helper.c b/linked_helper.c deleted file mode 100644 index 7d0beb4..0000000 --- a/linked_helper.c +++ /dev/null @@ -1,247 +0,0 @@ -#include "header.h" - -/** - * link_count - counts number of nodes in linked list - * @head: pointer to head of linked list - * - * Return: number of nodes - */ -unsigned int link_count(env_t *head) -{ - env_t *tmp; - unsigned int count; - - tmp = head; - count = 0; - - while (tmp != NULL) - { - tmp = tmp->next; - count++; - } - - return (count); -} - -/** - * add_node_env - adds new node to end of linked list - * @head: beginning of linked list - * @str: new string to be added to linked list - * - * Return: pointer to new node - */ -env_t *add_node_env(env_t **head, char *var, char *val) -{ - env_t *new_node, *temp; - new_node = malloc(sizeof(env_t)); - if (new_node == NULL) - return (NULL); - - new_node->var = _strdup(var); - new_node->val = _strdup(val); - new_node->next = NULL; - - if (!*head) - { - *head = new_node; - } - else - { - temp = *head; - - while (temp->next) - temp = temp->next; - - temp->next = new_node; - } - - return (new_node); -} - -/** - * modify_node_env - checks to see if node exists, and modifies it if so. - * @head: beginning of linked list - * @new_var: variable to modify - * @new_val: new string to be modified to found node - * - * Return: pointer to new node or NULL if fail - */ -int modify_node_env(env_t **head, char *new_var, char *new_val) -{ - env_t *temp; - - temp = *head; - - while (temp) - { - if (_strcmp(temp->var, new_var) == 0) - { - free(temp->val); - temp->val = _strdup(new_val); - - return (EXT_SUCCESS); - } - temp = temp->next; - } - - return (EXT_FAILURE); -} - -/** - * remove_node_env - removes node from linked list - * @head: beginning of linked list - * @var: var of node to be removed from linked list - * - * Return: pointer to new node or NULL - */ -int remove_node_env(env_t **head, char *var) -{ - env_t *copy_head = *head, *temp = *head; - - if (head == NULL) - return (EXT_FAILURE); - - copy_head=NULL; - - while (temp) - { - if (_strcmp(temp->var, var) == 0) - { - if (copy_head) - copy_head->next = temp->next; - else - *head = temp->next; - - free(temp->var); - free(temp->val); - free(temp); - - return (EXT_SUCCESS); - } - copy_head = temp; - temp = temp->next; - } - - return (EXT_FAILURE); -} - -/** - * env_list - creates a linked list of all environ variables - * - * Return: head (pointer to first node of linked list of environ variables) - */ -env_t *env_list(void) -{ - int i; - env_t *head; - char **variable; - head = NULL; - - for (i = 0; environ[i] != NULL; i++) - { - variable = separate_string(environ[i]); - if (add_node_env(&head, variable[0], variable[1]) == NULL) - return (NULL); - free(variable[0]); - free(variable[1]); - free(variable); - } - - return (head); -} - -/** - * separate_string - separates string at first '=' - * @string: one string from environ or alias input - * - * Return: array of 2 strings - */ -char **separate_string(char *string) -{ - char **result, *left, *right; - int i, j, lenleft = 0, lenright = 0; - - while (string[lenleft] != '=') - lenleft++; - left = safe_malloc(sizeof(char) * lenleft + 1); - - for (i = 0; i < lenleft; i++) - left[i] = string[i]; - - i = lenleft + 1; - - while (string[i] != '\0') - lenright++, i++; - right = safe_malloc(sizeof(char) * lenright + 1); - - for (i = lenleft + 1, j = 0; j < lenright; i++, j++) - right[j] = string[i]; - - result = safe_malloc(sizeof(char *) * 3); - result[0] = left, result[1] = right; - - return (result); -} - -/** - * zelda_to_ganondorf - converts linked list to double pointer - * @head: head pointer to head of linked list - * - * Return: array of pointers, pointing to strings - */ -char **zelda_to_ganondorf(env_t *head) -{ - int i; - unsigned int count, len1, len2, lennew; - char **ganondorf, *var, *val, *new_val; - env_t *tmp; - - count = link_count(head); - ganondorf = malloc(sizeof(char *) * (count + 1)); - - tmp = head; - i = 0; - while (tmp != NULL) - { - var = tmp->var; - val = tmp->val; - len1 = _strlen(var); - len2 = _strlen(val); - - lennew = len1 + len2 + 2; - new_val = safe_malloc(lennew * sizeof(char)); - - _strncat(new_val, var, len1); - _strncat(new_val, "=", 1); - _strncat(new_val, val, len2); - ganondorf[i] = new_val; - tmp = tmp->next; - i++; - } - ganondorf[i] = NULL; - - return (ganondorf); -} - -/** - * fetch_node - fetches a node of a given var - * @head: head of list - * @var: value to match of the node to fetch - * - * Return: fetched node or head - */ -env_t *fetch_node(env_t *head, char *var) -{ - env_t *tmp; - tmp = head; - - while (tmp != NULL) - { - if (_strcmp(tmp->var, var) == 0) - return (tmp); - else - tmp = tmp->next; - } - - return (NULL); -} diff --git a/parse.c b/parse.c deleted file mode 100644 index 59716af..0000000 --- a/parse.c +++ /dev/null @@ -1,224 +0,0 @@ -#include "header.h" - -/** - * parse_error - prints parser error - * @error: error to print - * @near: where the issue is at - * - * Return: 1 because of error - */ -int parse_error(const char *error, token_t *near) -{ - if (near) - fprintf(stderr, "Parse error near \"%s\": %s\n", near->str, error); - else - fprintf(stderr, "Parse error: %s\n", error); - - return (1); -} - -/** - * parse_expr - operator precedence parser - * @ntoken: token number; - * @tokens: tokens_t struct; - * @lhs: left hand side; - * @min_prec: minimum precedent - * - * Return: pointer to built tree - */ -ptree_t *parse_expr(unsigned int *ntoken, tokens_t *tokens, ptree_t *lhs, int min_prec) -{ - int lookahead, op; - ptree_t *rhs, *new; - - lookahead = *ntoken; - - while (*ntoken < tokens->tokensN && tokens->tokens[lookahead].prec >= min_prec) - { - op = *ntoken; - *ntoken = *ntoken + 1; - - rhs = ptree_new_string_node(lhs, tokens, ntoken); - - if (rhs == NULL) - { - if (*ntoken < tokens->tokensN || tokens->tokens[op].id != TOKEN_BACKGROUND) - { - parse_error("Line starts with operator, expected command", &tokens->tokens[*ntoken]); - return (NULL); - } - } - else if (*ntoken < tokens->tokensN) - { - lookahead = *ntoken; - - while (*ntoken < tokens->tokensN && tokens->tokens[lookahead].id != TOKEN_STRING && tokens->tokens[lookahead].prec > tokens->tokens[op].prec) - { - rhs = parse_expr(ntoken, tokens, rhs, tokens->tokens[lookahead].prec); - - if (rhs == NULL) - return (NULL); - - lookahead = *ntoken; - } - } - - new = ptree_new_node(NULL); - new->token_id = tokens->tokens[op].id; - new->left = lhs; - new->right = rhs; - lhs = new; - } - - return (lhs); -} - -/** - * parse - main funciton that creates the entire parse tree from the tokenizer - * @parser: parser_t struct - * @tokens: tokens_t struct - * - * Return: 0 - */ -int parse(parser_t *parser, tokens_t *tokens) -{ - ptree_t *ptree; - unsigned int cur_token = 0; - - parser->tree = NULL; - - if (tokens->tokensN == 0) - return (parse_error("Nothing to parse", NULL)); - - ptree = ptree_new_string_node(NULL, tokens, &cur_token); - - if (!ptree) - return (parse_error("Line starts with operator, expected command", tokens->tokens + 0)); - - parser->tree = ptree; - - parser->tree = parse_expr(&cur_token, tokens, ptree, 0); - - if (parser->tree == NULL) - return (1); - - return (0); -} - -/** - * delete_parser - frees parser struct - * @parser: parser struct - * - * Return: 0; - */ -int delete_parser(parser_t *parser) -{ - if (!parser->tree) - return (0); - - delete_ptree(parser->tree); - parser->tree = NULL; - - return (0); -} - -/** - * replace_str - replace part of string by another - * - * @old_str: string that will be modified - * @new_str: string to be used as replacement - * @i: starting position to replace in old_str - * @j: ending position to replace in old_str - * @flg: indicates if new_str should be freed - * - */ -void replace_str(char **old_str, char *new_str, int i, int j, int flg) -{ - *old_str = _str_replace(*old_str, i, j, new_str); - if (flg) - { - if (new_str[0]) - free(new_str); - } -} - -/** - * expand_bash_vars - expand all variables found in the arginv strings - * - * @arginv: args inventory - * - */ -void expand_bash_vars(arg_inventory_t *arginv) -{ - unsigned int i, j; - env_t *node; - - for (i = 0; i < arginv->tokens.tokensN; i++) - if (arginv->tokens.tokens[i].id == TOKEN_STRING) - { - for (j = 0; j < _strlen(arginv->tokens.tokens[i].str); j++) - if (arginv->tokens.tokens[i].str[j] == '$') - switch (arginv->tokens.tokens[i].str[j + 1]) - { - case '$': - replace_str((char **)&arginv->tokens.tokens[i].str, int_to_str(getpid()), j, j + 1, 1); - break; - case '?': - replace_str((char **)&arginv->tokens.tokens[i].str, int_to_str(arginv->last_exit_code), j, j + 1, 1); - break; - case '!': - replace_str((char **)&arginv->tokens.tokens[i].str, (arginv->last_bg_pid == -1) ? "" : int_to_str(arginv->last_bg_pid), j, j + 1, 1); - break; - case '0': - replace_str((char **)&arginv->tokens.tokens[i].str, "hsh", j, j + 1, 0); - break; - default: - node = fetch_node(arginv->envlist, (char *)&arginv->tokens.tokens[i].str[j + 1]); - replace_str((char **)&arginv->tokens.tokens[i].str, (node == NULL) ? "" : node->val, j, _strlen(arginv->tokens.tokens[i].str) - 1, 0); - } - else if (arginv->tokens.tokens[i].str[j] == '~' && j == 0) - { - node = fetch_node(arginv->envlist, "HOME"); - replace_str((char **)&arginv->tokens.tokens[i].str, node->val, j, j, 0); - } - } -} - -/** - * expand_alias - expand the alias found in the command strings - * - * @arginv: args inventory - * - */ -void expand_alias(arg_inventory_t *arginv) -{ - alias_t *node; - tokens_t cmd_tokens; - unsigned int i; - char **commands; - unsigned int count = 0; - - node = fetch_node_alias(arginv->alias, (char *)arginv->commands[0]); - - if (node != NULL) - { - tokenize(&cmd_tokens, node->command); - count = 0; - while (arginv->commands[count] != NULL) - { - count++; - } - commands = safe_malloc((count + cmd_tokens.tokensN) * sizeof(char *)); - for (i = count - 1; i >= 1; i--) - { - commands[i + cmd_tokens.tokensN - 1] = (char *)_strdup((char *)arginv->commands[i]); - } - - for (i = 0; i < cmd_tokens.tokensN; i++) - { - commands[i] = _strdup((char *)cmd_tokens.tokens[i].str); - } - arginv->commands = (const char **)commands; - delete_tokens(&cmd_tokens); - } -} diff --git a/parseA.c b/parseA.c new file mode 100644 index 0000000..2f787f1 --- /dev/null +++ b/parseA.c @@ -0,0 +1,123 @@ +#include "header.h" + +/** + * parse_error - prints parser error + * @error: error to print + * @near: where the issue is at + * + * Return: 1 because of error + */ +int parse_error(const char *error, token_t *near) +{ + if (near) + fprintf(stderr, "Parse error near \"%s\": %s\n", near->str, error); + else + fprintf(stderr, "Parse error: %s\n", error); + + return (1); +} + +/** + * parse_expr - operator precedence parser + * @ntoken: token number; + * @tokens: tokens_t struct; + * @lhs: left hand side; + * @min_prec: minimum precedent + * + * Return: pointer to built tree + */ +ptree_t *parse_expr(unsigned int *ntoken, tokens_t *tokens, ptree_t *lhs, int min_prec) +{ + int lookahead, op; + ptree_t *rhs, *new; + + lookahead = *ntoken; + + while (*ntoken < tokens->tokensN && tokens->tokens[lookahead].prec >= min_prec) + { + op = *ntoken; + *ntoken = *ntoken + 1; + + rhs = ptree_new_string_node(lhs, tokens, ntoken); + + if (rhs == NULL) + { + if (*ntoken < tokens->tokensN || tokens->tokens[op].id != TOKEN_BACKGROUND) + { + parse_error("Line starts with operator, expected command", &tokens->tokens[*ntoken]); + return (NULL); + } + } + else if (*ntoken < tokens->tokensN) + { + lookahead = *ntoken; + + while (*ntoken < tokens->tokensN && tokens->tokens[lookahead].id != TOKEN_STRING && tokens->tokens[lookahead].prec > tokens->tokens[op].prec) + { + rhs = parse_expr(ntoken, tokens, rhs, tokens->tokens[lookahead].prec); + + if (rhs == NULL) + return (NULL); + + lookahead = *ntoken; + } + } + + new = ptree_new_node(NULL); + new->token_id = tokens->tokens[op].id; + new->left = lhs; + new->right = rhs; + lhs = new; + } + + return (lhs); +} + +/** + * parse - main funciton that creates the entire parse tree from the tokenizer + * @parser: parser_t struct + * @tokens: tokens_t struct + * + * Return: 0 + */ +int parse(parser_t *parser, tokens_t *tokens) +{ + ptree_t *ptree; + unsigned int cur_token = 0; + + parser->tree = NULL; + + if (tokens->tokensN == 0) + return (parse_error("Nothing to parse", NULL)); + + ptree = ptree_new_string_node(NULL, tokens, &cur_token); + + if (!ptree) + return (parse_error("Line starts with operator, expected command", tokens->tokens + 0)); + + parser->tree = ptree; + + parser->tree = parse_expr(&cur_token, tokens, ptree, 0); + + if (parser->tree == NULL) + return (1); + + return (0); +} + +/** + * delete_parser - frees parser struct + * @parser: parser struct + * + * Return: 0; + */ +int delete_parser(parser_t *parser) +{ + if (!parser->tree) + return (0); + + delete_ptree(parser->tree); + parser->tree = NULL; + + return (0); +} diff --git a/parseB.c b/parseB.c new file mode 100644 index 0000000..f177b78 --- /dev/null +++ b/parseB.c @@ -0,0 +1,82 @@ +#include "header.h" + +/** + * expand_bash_vars - expand all variables found in the arginv strings + * + * @arginv: args inventory + * + */ +void expand_bash_vars(arg_inventory_t *arginv) +{ + unsigned int i, j; + env_t *node; + + for (i = 0; i < arginv->tokens.tokensN; i++) + if (arginv->tokens.tokens[i].id == TOKEN_STRING) + { + for (j = 0; j < _strlen(arginv->tokens.tokens[i].str); j++) + if (arginv->tokens.tokens[i].str[j] == '$') + switch (arginv->tokens.tokens[i].str[j + 1]) + { + case '$': + replace_str((char **)&arginv->tokens.tokens[i].str, int_to_str(getpid()), j, j + 1, 1); + break; + case '?': + replace_str((char **)&arginv->tokens.tokens[i].str, int_to_str(arginv->last_exit_code), j, j + 1, 1); + break; + case '!': + replace_str((char **)&arginv->tokens.tokens[i].str, (arginv->last_bg_pid == -1) ? "" : int_to_str(arginv->last_bg_pid), j, j + 1, 1); + break; + case '0': + replace_str((char **)&arginv->tokens.tokens[i].str, "hsh", j, j + 1, 0); + break; + default: + node = fetch_node(arginv->envlist, (char *)&arginv->tokens.tokens[i].str[j + 1]); + replace_str((char **)&arginv->tokens.tokens[i].str, (node == NULL) ? "" : node->val, j, _strlen(arginv->tokens.tokens[i].str) - 1, 0); + } + else if (arginv->tokens.tokens[i].str[j] == '~' && j == 0) + { + node = fetch_node(arginv->envlist, "HOME"); + replace_str((char **)&arginv->tokens.tokens[i].str, node->val, j, j, 0); + } + } +} + +/** + * expand_alias - expand the alias found in the command strings + * + * @arginv: args inventory + * + */ +void expand_alias(arg_inventory_t *arginv) +{ + alias_t *node; + tokens_t cmd_tokens; + unsigned int i; + char **commands; + unsigned int count = 0; + + node = fetch_node_alias(arginv->alias, (char *)arginv->commands[0]); + + if (node != NULL) + { + tokenize(&cmd_tokens, node->command); + count = 0; + while (arginv->commands[count] != NULL) + { + count++; + } + commands = safe_malloc((count + cmd_tokens.tokensN) * sizeof(char *)); + for (i = count - 1; i >= 1; i--) + { + commands[i + cmd_tokens.tokensN - 1] = (char *)_strdup((char *)arginv->commands[i]); + } + + for (i = 0; i < cmd_tokens.tokensN; i++) + { + commands[i] = _strdup((char *)cmd_tokens.tokens[i].str); + } + arginv->commands = (const char **)commands; + delete_tokens(&cmd_tokens); + } +} diff --git a/strings.c b/strings.c deleted file mode 100644 index 1065828..0000000 --- a/strings.c +++ /dev/null @@ -1,247 +0,0 @@ -#include "header.h" - -/** - * _strncat - concatenates from src string to dest string - * @dest: destination string - * @src: source string - * @n: number of bytes to concatenate - * - * Return: pointer to destination - */ -char *_strncat(char *dest, char *src, int n) -{ - int i = 0, j = 0; - - while (dest[i] != '\0') - i++; - - while (j < n && src[j] != '\0') - { - dest[i] = src[j]; - i++; - j++; - } - - dest[i] = '\0'; - - return (dest); -} - -/** - * _strcmp - compares string - * @s1: first string - * @s2: second string - * - * Return: difference between two ascii valuves - */ - -int _strcmp(const char *s1, const char *s2) -{ - int i; - - i = 0; - - while (TRUE) - { - if (s1[i] != s2[i]) - return (s1[i] - s2[i]); - - if (s1[i] == '\0' || s2[i] == '\0') - break; - - i++; - } - - return (0); -} - -/** - * _strlen - finds and returns length of string - * @str: string to find length - * - * Return: length of string - */ -unsigned int _strlen(const char *str) -{ - int i = 0; - - while (str[i] != '\0') - i++; - - return (i); -} - -/** - * _strdup - takes a string and copies to another a new memory location - * @str: string to copy - * - * Return: pointer to copied string - */ -char *_strdup(char *str) -{ - unsigned int len, j; - char *ptrstring; - - if (str == NULL) - return (NULL); - - len = _strlen(str); - - ptrstring = safe_malloc((len + 1) * sizeof(char)); - - for (j = 0; j < len; j++) - ptrstring[j] = str[j]; - ptrstring[j] = '\0'; - - return (ptrstring); -} - -/** - * _strncmp - checks if 2 strings are of equal value and length - * @s1: first string - * @s2: second string - * @n: number of bytes to compare - * - * Return: difference of first characters that are of diff value or 0 on success - */ -int _strncmp(char *s1, char *s2, unsigned int n) -{ - unsigned int j; - - for (j = 0; j < n; j++) - if (s1[j] != s2[j]) - return (s1[j] - s2[j]); - - return (0); -} - -/** - * _strcpy - copies a string from src to dest - * @dest: new copy of string - * @src: the source of the copy - * - * Return: pointer to copy - */ -char *_strcpy(char *dest, char *src) -{ - int c; - - for (c = 0; src[c] != '\0'; c++) - dest[c] = src[c]; - - dest[c] = '\0'; - - return (dest); -} - -/** - * _strncpy - copies string from source to destination - * @dest: destination string - * @src: source string to be copied - * @n: bytes to be copied from source string - * - * Return: destination string concatenated - */ -char *_strncpy(char *dest, char *src, int n) -{ - int j; - - for (j = 0; j < n && src[j] != '\0'; j++) - dest[j] = src[j]; - - while (j < n) - { - dest[j] = '\0'; - j++; - } - - return (dest); -} - -/** - * _strcat - concatenates from src string to dest string - * @dest: destination string - * @src: source string - * - * Return: pointer to destination - */ -char *_strcat(char *dest, char *src) -{ - while (*dest) - dest++; - - while (*src) - *(dest++) = *(src++); - - *dest = '\0'; - - return (dest); -} - -/** - * int_to_str - convert an integer to a string - * @n: unsigned integer to print - * Return: string with converted integer - */ -char *int_to_str(unsigned int n) -{ - unsigned int copy, size; - int nth, chars_written; - char *str; - int chars; - - size = 1; - chars_written = 0; - copy = n; - - if (n < 10) - { - str = safe_malloc(2); - str[0] = ('0' + n); - return (str); - } - - chars = 0; - while (copy / 10 != 0) - { - copy /= 10, size *= 10; - chars++; - } - - str = safe_malloc(chars + 1); - while (size > 0) - { - nth = n / size; - str[chars_written] = ('0' + nth); - n -= nth * size; - size /= 10; - chars_written++; - } - str[chars_written] = '\0'; - return (str); -} - -/** - * str_replace - replaces part of a string for another - * @string: string to replace - * @start: where to start - * @end: where to end - * @rep: string to replace with - * - * Return: replaced string - */ -char *_str_replace(char *string, unsigned int start, unsigned int end, char *rep) -{ - char *new_str; - - new_str = safe_malloc(_strlen(string) + _strlen(rep) + 1); - - _strncpy(new_str, string, start); - - _strcat(new_str, rep); - - if (end < _strlen(string) - 1) - _strcat(new_str, &string[end + 1]); - - return (new_str); -} diff --git a/stringsA.c b/stringsA.c new file mode 100644 index 0000000..3f1cb56 --- /dev/null +++ b/stringsA.c @@ -0,0 +1,116 @@ +#include "header.h" + +/** + * _strncat - concatenates from src string to dest string + * @dest: destination string + * @src: source string + * @n: number of bytes to concatenate + * + * Return: pointer to destination + */ +char *_strncat(char *dest, char *src, int n) +{ + int i = 0, j = 0; + + while (dest[i] != '\0') + i++; + + while (j < n && src[j] != '\0') + { + dest[i] = src[j]; + i++; + j++; + } + + dest[i] = '\0'; + + return (dest); +} + +/** + * _strcmp - compares string + * @s1: first string + * @s2: second string + * + * Return: difference between two ascii valuves + */ + +int _strcmp(const char *s1, const char *s2) +{ + int i; + + i = 0; + + while (TRUE) + { + if (s1[i] != s2[i]) + return (s1[i] - s2[i]); + + if (s1[i] == '\0' || s2[i] == '\0') + break; + + i++; + } + + return (0); +} + +/** + * _strlen - finds and returns length of string + * @str: string to find length + * + * Return: length of string + */ +unsigned int _strlen(const char *str) +{ + int i = 0; + + while (str[i] != '\0') + i++; + + return (i); +} + +/** + * _strdup - takes a string and copies to another a new memory location + * @str: string to copy + * + * Return: pointer to copied string + */ +char *_strdup(char *str) +{ + unsigned int len, j; + char *ptrstring; + + if (str == NULL) + return (NULL); + + len = _strlen(str); + + ptrstring = safe_malloc((len + 1) * sizeof(char)); + + for (j = 0; j < len; j++) + ptrstring[j] = str[j]; + ptrstring[j] = '\0'; + + return (ptrstring); +} + +/** + * _strncmp - checks if 2 strings are of equal value and length + * @s1: first string + * @s2: second string + * @n: number of bytes to compare + * + * Return: difference of first characters that are of diff value or 0 on success + */ +int _strncmp(char *s1, char *s2, unsigned int n) +{ + unsigned int j; + + for (j = 0; j < n; j++) + if (s1[j] != s2[j]) + return (s1[j] - s2[j]); + + return (0); +} diff --git a/stringsB.c b/stringsB.c new file mode 100644 index 0000000..a601eff --- /dev/null +++ b/stringsB.c @@ -0,0 +1,64 @@ +#include "header.h" + +/** + * _strcpy - copies a string from src to dest + * @dest: new copy of string + * @src: the source of the copy + * + * Return: pointer to copy + */ +char *_strcpy(char *dest, char *src) +{ + int c; + + for (c = 0; src[c] != '\0'; c++) + dest[c] = src[c]; + + dest[c] = '\0'; + + return (dest); +} + +/** + * _strncpy - copies string from source to destination + * @dest: destination string + * @src: source string to be copied + * @n: bytes to be copied from source string + * + * Return: destination string concatenated + */ +char *_strncpy(char *dest, char *src, int n) +{ + int j; + + for (j = 0; j < n && src[j] != '\0'; j++) + dest[j] = src[j]; + + while (j < n) + { + dest[j] = '\0'; + j++; + } + + return (dest); +} + +/** + * _strcat - concatenates from src string to dest string + * @dest: destination string + * @src: source string + * + * Return: pointer to destination + */ +char *_strcat(char *dest, char *src) +{ + while (*dest) + dest++; + + while (*src) + *(dest++) = *(src++); + + *dest = '\0'; + + return (dest); +} diff --git a/stringsC.c b/stringsC.c new file mode 100644 index 0000000..840f198 --- /dev/null +++ b/stringsC.c @@ -0,0 +1,122 @@ +#include "header.h" + +/** + * replace_str - replace part of string by another + * + * @old_str: string that will be modified + * @new_str: string to be used as replacement + * @i: starting position to replace in old_str + * @j: ending position to replace in old_str + * @flg: indicates if new_str should be freed + * + */ +void replace_str(char **old_str, char *new_str, int i, int j, int flg) +{ + *old_str = _str_replace(*old_str, i, j, new_str); + if (flg) + { + if (new_str[0]) + free(new_str); + } +} + +/** + * separate_string - separates string at first '=' + * @string: one string from environ or alias input + * + * Return: array of 2 strings + */ +char **separate_string(char *string) +{ + char **result, *left, *right; + int i, j, lenleft = 0, lenright = 0; + + while (string[lenleft] != '=') + lenleft++; + left = safe_malloc(sizeof(char) * lenleft + 1); + + for (i = 0; i < lenleft; i++) + left[i] = string[i]; + + i = lenleft + 1; + + while (string[i] != '\0') + lenright++, i++; + right = safe_malloc(sizeof(char) * lenright + 1); + + for (i = lenleft + 1, j = 0; j < lenright; i++, j++) + right[j] = string[i]; + + result = safe_malloc(sizeof(char *) * 3); + result[0] = left, result[1] = right; + + return (result); +} + +/** + * int_to_str - convert an integer to a string + * @n: unsigned integer to print + * Return: string with converted integer + */ +char *int_to_str(unsigned int n) +{ + unsigned int copy, size; + int nth, chars_written; + char *str; + int chars; + + size = 1; + chars_written = 0; + copy = n; + + if (n < 10) + { + str = safe_malloc(2); + str[0] = ('0' + n); + return (str); + } + + chars = 0; + while (copy / 10 != 0) + { + copy /= 10, size *= 10; + chars++; + } + + str = safe_malloc(chars + 1); + while (size > 0) + { + nth = n / size; + str[chars_written] = ('0' + nth); + n -= nth * size; + size /= 10; + chars_written++; + } + str[chars_written] = '\0'; + return (str); +} + +/** + * str_replace - replaces part of a string for another + * @string: string to replace + * @start: where to start + * @end: where to end + * @rep: string to replace with + * + * Return: replaced string + */ +char *_str_replace(char *string, unsigned int start, unsigned int end, char *rep) +{ + char *new_str; + + new_str = safe_malloc(_strlen(string) + _strlen(rep) + 1); + + _strncpy(new_str, string, start); + + _strcat(new_str, rep); + + if (end < _strlen(string) - 1) + _strcat(new_str, &string[end + 1]); + + return (new_str); +} diff --git a/tokenize.c b/tokenize.c new file mode 100644 index 0000000..72d40e5 --- /dev/null +++ b/tokenize.c @@ -0,0 +1,180 @@ +#include "header.h" + +/** + * tokenize - tokenizes command string + * @tokens: tokens_t struct containing initial string and array of strings + * @string: command string + * + * Return: 0, or exits with error + */ +int tokenize(tokens_t *tokens, const char *string) +{ + unsigned int length, string_idx, data_idx, tokens_idx; + unsigned int skip_next, skip_quote; + unsigned int is_token; + unsigned int tokens_to_move; + unsigned int i, j; + + char symbol; + token_types token_names[] = { + { TOKEN_SEMICOLON, ";", "semicolon", 1 }, + { TOKEN_BACKGROUND, "&", "background", 1 }, + { TOKEN_AND, "&&", "and", 2 }, + { TOKEN_OR, "||", "or", 2 }, + { TOKEN_PIPE, "|", "pipe", 3 }, + { TOKEN_REWRITE, ">", "rewrite", 4 }, + { TOKEN_APPEND, ">>", "append", 4 }, + { TOKEN_CAT, "<", "cat", 4 } + }; + + /* First of all, we need to carefully allocate memory */ + /* It does not matter if we allocate too much, it is better than constant reallocations, */ + /* because they take too much time, and memory is not a concern */ + length = _strlen(string); + if (length == 0) + length = 1; /* Empty string should be properly processed too! */ + + /* Initializes struct */ + init_tokens(tokens, length); + + /* Set up current indexes; */ + string_idx = 0; /* Current position in original string */ + data_idx = 0; /* Current position in resulting data string */ + tokens_idx = 0; /* Current token */ + + skip_next = 0; /* If it is set to 1, then any symbol except for '\0' would be skipped */ + skip_quote = 0; /* If it is set to 1, then we need to skip any symbol (including '\') until we find another '\"' symbol */ + + is_token = 0; /* If it is set to 1, then we are currently processing a token. If 0, then we are processing whitespace symbols */ + + /* Cycle for each symbol from the original string */ + while (string[string_idx] != '\0' && string[string_idx] != '#') + { + /* Cycle until the end */ + /* Retrieve current symbol and advance further */ + symbol = string[string_idx]; + string_idx++; + + if (!is_token && _isspace(symbol)) + continue; /* Skip whitespaces if we are not in token mode */ + + if (!is_token && !_isspace(symbol) && (symbol != ';')) + { + /* Note that we'll handle ';' later, this is the special case */ + /* New token has been started */ + /* We need to set up pointer properly so it points to current location in data */ + tokens->tokens[tokens_idx].str = tokens->data + data_idx; + tokens_idx++; + is_token = 1; /* The token has started. We need to process it carefully */ + } + + if (is_token && _isspace(symbol) && !skip_next && !skip_quote) + { + /* Previous token has been ended */ + /* Finish this token */ + tokens->data[data_idx] = '\0'; + data_idx++; + + /* Also set token flag to 0 */ + is_token = 0; + + continue; /* We have nothing to do here, because current symbol is a space symbol */ + } + + /* Deal with ; */ + /* It should be the separate token */ + if ((symbol == ';') && !skip_next && !skip_quote) + { + if (is_token) + { + /* First, we need to close previous token */ + tokens->data[data_idx] = '\0'; + data_idx++; + /* No need to mark is_token here, it'll be set to 0 afterwards anyway */ + } + + /* Next, we need to add new token */ + tokens->tokens[tokens_idx].str = tokens->data + data_idx; + tokens_idx++; + + /* And fill it with ';' */ + tokens->data[data_idx] = ';'; + tokens->data[data_idx + 1] = '\0'; + data_idx += 2; + + /* Set up is_token to 0 and skip this iteration */ + is_token = 0; + continue; + } + + /* Deal with " */ + /* Note that we need to deal with them only if we are not skipping next symbol, i.e. */ + /* \" is to be skipped */ + if ((symbol == '\"') && !skip_next) + { + skip_quote = !skip_quote; + continue; /* We do not need \" to be in token then*/ + } + + /* Deal with '\' */ + if ((symbol == '\\') && !skip_next) + { + skip_next = 1; + continue; /* We do not need \\ to be in token then */ + } + skip_next = 0; /* The next symbol has been skipped (or skip_next was 0 to begin with) */ + + /* When we got here, is_token is 1, and next symbol is not space or we are skipping it */ + /* We need to add it to current data */ + tokens->data[data_idx] = symbol; + data_idx++; + } + + /* Finalize data by placing the last '\0' just to be sure that it has been terminated */ + tokens->data[data_idx] = '\0'; + + /* Set current amount of tokens properly */ + tokens->tokensN = tokens_idx; + + /* Next - tokenize all tokens */ + /* By default, every token is TOKEN_STRING, but in case if equals to some predefined token, */ + /* its ID should change */ + for (i = 0; i < tokens->tokensN; i++) + { + tokens->tokens[i].id = TOKEN_STRING; /* Set default value */ + + /* Compare each token with pre-defined token names */ + for (j = 0; j < sizeof(token_names) / sizeof(token_names[0]); j++) + { + if (_strcmp(token_names[j].token_str, tokens->tokens[i].str) == 0) + { + /* It is a match */ + tokens->tokens[i].id = token_names[j].token_id; + tokens->tokens[i].prec = token_names[j].precedence; + break; /* No need to cycle further here, we found corresponding token ID */ + } + } + } + + /* The last thing we'll need to do here is to delete duplicates */ + /* At the moment, we'll only need to delete ; token, turning ;; into ; */ + for (i = 0; i + 1 < tokens->tokensN;) + { /* The increment is inside of the cycle... or, rather, increment or decrement */ + if ((tokens->tokens[i].id == tokens->tokens[i + 1].id) && (tokens->tokens[i].id == TOKEN_SEMICOLON)) + { + /* Carefully shift the array one element */ + tokens_to_move = tokens->tokensN - i - 1; + memmove(tokens->tokens + i, tokens->tokens + i + 1, tokens_to_move * sizeof(token_t)); + + /* Also decrease amount of tokens left */ + tokens->tokensN--; + } else + i++; /* Otherwise, cycle as usual */ + } + + if (tokens->tokensN && tokens->tokens[tokens->tokensN - 1].id == TOKEN_SEMICOLON) + tokens->tokensN--; + + + return (0); /* All OK */ +} diff --git a/tokenizer.c b/tokenizer.c index 2f1c098..798e5f7 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -33,185 +33,6 @@ int is_redirection(int token_id) return (token_id == TOKEN_REWRITE || token_id == TOKEN_APPEND || token_id == TOKEN_CAT); } -/** - * tokenize - tokenizes command string - * @tokens: tokens_t struct containing initial string and array of strings - * @string: command string - * - * Return: 0, or exits with error - */ -int tokenize(tokens_t *tokens, const char *string) -{ - unsigned int length, string_idx, data_idx, tokens_idx; - unsigned int skip_next, skip_quote; - unsigned int is_token; - unsigned int tokens_to_move; - unsigned int i, j; - - char symbol; - token_types token_names[] = { - { TOKEN_SEMICOLON, ";", "semicolon", 1 }, - { TOKEN_BACKGROUND, "&", "background", 1 }, - { TOKEN_AND, "&&", "and", 2 }, - { TOKEN_OR, "||", "or", 2 }, - { TOKEN_PIPE, "|", "pipe", 3 }, - { TOKEN_REWRITE, ">", "rewrite", 4 }, - { TOKEN_APPEND, ">>", "append", 4 }, - { TOKEN_CAT, "<", "cat", 4 } - }; - - /* First of all, we need to carefully allocate memory */ - /* It does not matter if we allocate too much, it is better than constant reallocations, */ - /* because they take too much time, and memory is not a concern */ - length = _strlen(string); - if (length == 0) - length = 1; /* Empty string should be properly processed too! */ - - /* Initializes struct */ - init_tokens(tokens, length); - - /* Set up current indexes; */ - string_idx = 0; /* Current position in original string */ - data_idx = 0; /* Current position in resulting data string */ - tokens_idx = 0; /* Current token */ - - skip_next = 0; /* If it is set to 1, then any symbol except for '\0' would be skipped */ - skip_quote = 0; /* If it is set to 1, then we need to skip any symbol (including '\') until we find another '\"' symbol */ - - is_token = 0; /* If it is set to 1, then we are currently processing a token. If 0, then we are processing whitespace symbols */ - - /* Cycle for each symbol from the original string */ - while (string[string_idx] != '\0' && string[string_idx] != '#') - { - /* Cycle until the end */ - /* Retrieve current symbol and advance further */ - symbol = string[string_idx]; - string_idx++; - - if (!is_token && _isspace(symbol)) - continue; /* Skip whitespaces if we are not in token mode */ - - if (!is_token && !_isspace(symbol) && (symbol != ';')) - { - /* Note that we'll handle ';' later, this is the special case */ - /* New token has been started */ - /* We need to set up pointer properly so it points to current location in data */ - tokens->tokens[tokens_idx].str = tokens->data + data_idx; - tokens_idx++; - is_token = 1; /* The token has started. We need to process it carefully */ - } - - if (is_token && _isspace(symbol) && !skip_next && !skip_quote) - { - /* Previous token has been ended */ - /* Finish this token */ - tokens->data[data_idx] = '\0'; - data_idx++; - - /* Also set token flag to 0 */ - is_token = 0; - - continue; /* We have nothing to do here, because current symbol is a space symbol */ - } - - /* Deal with ; */ - /* It should be the separate token */ - if ((symbol == ';') && !skip_next && !skip_quote) - { - if (is_token) - { - /* First, we need to close previous token */ - tokens->data[data_idx] = '\0'; - data_idx++; - /* No need to mark is_token here, it'll be set to 0 afterwards anyway */ - } - - /* Next, we need to add new token */ - tokens->tokens[tokens_idx].str = tokens->data + data_idx; - tokens_idx++; - - /* And fill it with ';' */ - tokens->data[data_idx] = ';'; - tokens->data[data_idx + 1] = '\0'; - data_idx += 2; - - /* Set up is_token to 0 and skip this iteration */ - is_token = 0; - continue; - } - - /* Deal with " */ - /* Note that we need to deal with them only if we are not skipping next symbol, i.e. */ - /* \" is to be skipped */ - if ((symbol == '\"') && !skip_next) - { - skip_quote = !skip_quote; - continue; /* We do not need \" to be in token then*/ - } - - /* Deal with '\' */ - if ((symbol == '\\') && !skip_next) - { - skip_next = 1; - continue; /* We do not need \\ to be in token then */ - } - skip_next = 0; /* The next symbol has been skipped (or skip_next was 0 to begin with) */ - - /* When we got here, is_token is 1, and next symbol is not space or we are skipping it */ - /* We need to add it to current data */ - tokens->data[data_idx] = symbol; - data_idx++; - } - - /* Finalize data by placing the last '\0' just to be sure that it has been terminated */ - tokens->data[data_idx] = '\0'; - - /* Set current amount of tokens properly */ - tokens->tokensN = tokens_idx; - - /* Next - tokenize all tokens */ - /* By default, every token is TOKEN_STRING, but in case if equals to some predefined token, */ - /* its ID should change */ - for (i = 0; i < tokens->tokensN; i++) - { - tokens->tokens[i].id = TOKEN_STRING; /* Set default value */ - - /* Compare each token with pre-defined token names */ - for (j = 0; j < sizeof(token_names) / sizeof(token_names[0]); j++) - { - if (_strcmp(token_names[j].token_str, tokens->tokens[i].str) == 0) - { - /* It is a match */ - tokens->tokens[i].id = token_names[j].token_id; - tokens->tokens[i].prec = token_names[j].precedence; - break; /* No need to cycle further here, we found corresponding token ID */ - } - } - } - - /* The last thing we'll need to do here is to delete duplicates */ - /* At the moment, we'll only need to delete ; token, turning ;; into ; */ - for (i = 0; i + 1 < tokens->tokensN;) - { /* The increment is inside of the cycle... or, rather, increment or decrement */ - if ((tokens->tokens[i].id == tokens->tokens[i + 1].id) && (tokens->tokens[i].id == TOKEN_SEMICOLON)) - { - /* Carefully shift the array one element */ - tokens_to_move = tokens->tokensN - i - 1; - memmove(tokens->tokens + i, tokens->tokens + i + 1, tokens_to_move * sizeof(token_t)); - - /* Also decrease amount of tokens left */ - tokens->tokensN--; - } else - i++; /* Otherwise, cycle as usual */ - } - - if (tokens->tokensN && tokens->tokens[tokens->tokensN - 1].id == TOKEN_SEMICOLON) - tokens->tokensN--; - - - return (0); /* All OK */ -} - /** * delete_tokens - freeing tokens * @tokens: tokens_t struct with tokens