Skip to content

Commit

Permalink
Merge pull request #2 from nanafox/updates/aliases
Browse files Browse the repository at this point in the history
Improved aliases
  • Loading branch information
nanafox authored Nov 15, 2023
2 parents 8740ec2 + d590180 commit f7bb3de
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 79 deletions.
17 changes: 11 additions & 6 deletions alias.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,23 @@ void print_aliases(const alias_t *head)
*
* Return: 0 if alias was found and removed successfully, else 1
*/
int unalias(alias_t **head, char **command)
int unalias(alias_t **head, char *command)
{
alias_t *current, *prev;
size_t i;
char *name;
char **names;
int exit_code = 1; /* assume failure by default */

names = _strtok(command, NULL);
if (names == NULL)
return (-1);

current = *head;
for (i = 1; command[i] != NULL; i++)
for (i = 1; names[i] != NULL; i++)
{
name = strtok(command[i], "=");
while (current != NULL)
{
if (!_strcmp(current->name, name))
if (!_strcmp(current->name, names[i]))
{
if (current == *head)
*head = (*head)->next;
Expand All @@ -106,10 +109,12 @@ int unalias(alias_t **head, char **command)

if (exit_code != 0)
{
dprintf(2, "unalias: %s not found\n", name);
dprintf(2, "unalias: %s not found\n", names[i]);
exit_code = 1;
}
safe_free(names[i]);
}
free_str(names);
return (exit_code);
}

Expand Down
170 changes: 121 additions & 49 deletions alias_handler.c
Original file line number Diff line number Diff line change
@@ -1,79 +1,151 @@
#include "shell.h"

static int exit_code;

/**
* handle_alias - handles the processing of alias
* @head: a pointer to the list containing all aliases
* @command: the list of commands containing alias-specific lines
*
* Return: 0 on success, -1 on error
*/
int handle_alias(alias_t **head, char **command)
int handle_alias(alias_t **head, char *command)
{
char *value, *loc, *name, *tmp;
ssize_t i, offset, exit_code = 0;
if (_strlen(command) == 5)
print_aliases(*head);

else if (!_strncmp(command, "alias", 5))
{
if (!_strchr(command, '='))
process_non_matching(*head, command + 5, 1);
else
parse_aliases(command, head);
}

if (!_strcmp("unalias", command[0]))
else if (!_strncmp(command, "unalias", 7))
return (unalias(head, command));
if ((!_strcmp(command[0], "alias") && command[1] == NULL))
print_aliases(*head);
for (i = 1; command[i] != NULL; i++)

return (exit_code);
}

/**
* parse_aliases - extract aliases from the input string using regular
* expressions.
* @input: the input string containing aliases
* @aliases: a pointer to a list of aliases
*
* Description: This function uses regular expressions to extract aliases from
* the input string. It populates the provided array of Alias structures with
* the parsed aliases and updates the aliasCount accordingly.
*/
void parse_aliases(const char *input, alias_t **aliases)
{
char *input_ptr = NULL;
size_t valueLength, alias_count = 0;
regmatch_t matches[3];
regex_t regex;
const char *pattern =
"([^\"]\\S*|\"[^\"]*\"|'[^\']*')=([^\"]\\S*|\"[^\"]*\"|'[^\']*')";

if (regcomp(&regex, pattern, REG_EXTENDED) != 0)
return; /* regular expression compilation failed */
input_ptr = (char *)input;
while (regexec(&regex, input_ptr, 3, matches, 0) == 0)
{
tmp = _strdup(command[i]);
loc = _strchr(tmp, '=');
if (loc != NULL)
char name[MAX_ALIAS_LENGTH] = {0};
char value[MAX_VALUE_LENGTH] = {0};

/* extract the alias name, accounts for the leading spaces */
_strncpy(name, (input_ptr + 1) + matches[1].rm_so,
(matches[1].rm_eo - 1) - matches[1].rm_so);
_strncpy(value, input_ptr + matches[2].rm_so,
matches[2].rm_eo - matches[2].rm_so); /* extract the alias value */
name[matches[1].rm_eo - matches[1].rm_so] = '\0';

valueLength = matches[2].rm_eo - matches[2].rm_so;
if (isquote(value[0])) /* remove quotes */
{
offset = (&loc[0]) - (&tmp[0]);
tmp[offset] = '\0';
name = _strdup(tmp);
if (name == NULL)
{
safe_free(tmp);
return (-1);
}
value = (tmp[offset + 1] == '"' || tmp[offset + 1] == '\'')
? extract_value(&tmp[offset + 1]) : _strdup(&tmp[offset + 1]);
if (value == NULL)
{
multi_free("ss", value, name);
return (-1);
}
if (add_alias(head, name, value) == NULL)
_strncpy(value, input_ptr + matches[2].rm_so + 1, valueLength - 2);
value[valueLength - 2] = '\0';
}
else /* not enclosed in quotes, copy as is */
value[valueLength] = '\0';
if (add_alias(aliases, name, value) == NULL)
return;
if (alias_count)
process_non_matching(*aliases, input_ptr, 0);
alias_count++; /* increment alias count */
input_ptr += matches[0].rm_eo; /* keep searching */
}
if (alias_count)
process_non_matching(*aliases, input_ptr, 1);
regfree(&regex);
}

/**
* process_non_matching - processes strings that do not have the `name=value`
* format while parsing aliases
* @aliases: a list containing aliases
* @non_matching: the string to check for non-matching patterns
* @end: used to signal the end. 1 means it can process the whole string at
* once. 0 means it can do only word token at a time
*/
void process_non_matching(alias_t *aliases, const char *non_matching, int end)
{
char *token, *dup;

if (non_matching == NULL || *non_matching == '\0')
return; /* there's nothing to work on, everything matched */

dup = _strdup(non_matching);
token = strtok(dup, " ");

/* it is non-matching if it doesn't contain an equal sign */
if (!_strchr(token, '='))
{
if (end)
{
while (token != NULL)
{
multi_free("ss", value, name);
return (-1);
exit_code = print_alias(aliases, token);
token = strtok(NULL, " ");
}
multi_free("ss", value, name);
}
else
exit_code = print_alias(*head, command[i]);
safe_free(tmp);
exit_code = print_alias(aliases, token);
}
return (exit_code);
free(dup);
}

/**
* extract_value - returns the string value enclosed in quotes
* @value: the string containing value
*
* Return: the string data without the quotes
* build_alias_cmd - builds the correct command line when the received input is
* a valid alias command
* @sub_command: a pointer to the array containing the commands
* @alias_value: the value of the alias command
*/
char *extract_value(const char *value)
void build_alias_cmd(char ***sub_command, char *alias_value)
{
int i, j;
char quote = value[0];
int length = strlen(value);
char *content = malloc(length);
char **dup_array = NULL;

if (content == NULL)
if ((*sub_command)[1] != NULL)
{
return (NULL);
}
/* save a copy of the the commands array, excluding the alias */
dup_array = duplicate_str_array((*sub_command) + 1);

/* memory and build the command line string based on the alias value */
free_str(*sub_command);
*sub_command = _strtok(alias_value, NULL);

/* concatenate both arrays to form a complete command string */
concatenate_arrays(sub_command, dup_array);

for (i = 1, j = 0; i < length && value[i] != quote; ++i, ++j)
/* clean up and return */
free_str(dup_array);
}
else
{
content[j] = value[i];
/* there was alias alright but no other arguments */
free_str(*sub_command);
*sub_command = _strtok(alias_value, NULL);
}
content[j] = '\0';

return (content);
}
11 changes: 6 additions & 5 deletions builtins_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@
* Return: exit code
*/
int handle_builtin(char **sub_command, char **commands, char *line,
alias_t *aliases, path_t *path_list, int exit_code)
alias_t *aliases, path_t *path_list, int exit_code)
{
if (!_strcmp(sub_command[0], "env") || !_strcmp(sub_command[0], "printenv"))
if (!_strcmp(sub_command[0], "env") ||
!_strcmp(sub_command[0], "printenv"))
{
_printenv();
return (0);
}
else if (!_strcmp(sub_command[0], "exit"))
{
return (handle_exit(sub_command[1], exit_code, multi_free,
sub_command, commands, line, &path_list, &aliases));
return (handle_exit(sub_command[1], exit_code, multi_free, sub_command,
commands, line, &path_list, &aliases));
}

/* let's handle the builtin 'cd' command */
Expand All @@ -33,7 +34,7 @@ int handle_builtin(char **sub_command, char **commands, char *line,
{
if (sub_command[1] && sub_command[2])
return (setenv(sub_command[1], sub_command[2], 1));
return (1); /* inavlid number of parameters received */
return (1); /* invalid number of parameters received */
}
else if (!_strcmp(sub_command[0], "unsetenv"))
return (_unsetenv(sub_command[1]));
Expand Down
9 changes: 5 additions & 4 deletions parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ int parse_line(char *line, path_t *path_list)
/* first of all, let's get rid of all comments */
line = handle_comments(line);

/* now let's all the commands provided by the user */
/* now let's tokenize all the commands provided by the user */
commands = _strtok(line, "\n;");
if (commands == NULL)
{
Expand All @@ -33,6 +33,7 @@ int parse_line(char *line, path_t *path_list)

exit_code = parse(commands, path_list, line);
free_str(commands);

return (exit_code);
}

Expand Down Expand Up @@ -136,18 +137,18 @@ void parse_helper(char **commands, char **sub_command, path_t *path_list,
if (!_strcmp(sub_command[0], "alias") ||
!_strcmp(sub_command[0], "unalias"))
{
exit_code = handle_alias(&aliases, sub_command);
exit_code = handle_alias(&aliases, commands[index]);
free_str(sub_command);
return;
}

alias_value = get_alias(aliases, sub_command[0]);
if (alias_value != NULL)
{
safe_free(sub_command[0]);
sub_command[0] = _strdup(alias_value);
build_alias_cmd(&sub_command, alias_value);
safe_free(alias_value);
}

exit_code = handle_builtin(sub_command, commands, line, aliases, path_list,
exit_code);
if (exit_code != NOT_BUILTIN)
Expand Down
Loading

0 comments on commit f7bb3de

Please sign in to comment.