Skip to content

Commit f7bb3de

Browse files
authored
Merge pull request #2 from nanafox/updates/aliases
Improved aliases
2 parents 8740ec2 + d590180 commit f7bb3de

File tree

6 files changed

+234
-79
lines changed

6 files changed

+234
-79
lines changed

alias.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,23 @@ void print_aliases(const alias_t *head)
7575
*
7676
* Return: 0 if alias was found and removed successfully, else 1
7777
*/
78-
int unalias(alias_t **head, char **command)
78+
int unalias(alias_t **head, char *command)
7979
{
8080
alias_t *current, *prev;
8181
size_t i;
82-
char *name;
82+
char **names;
8383
int exit_code = 1; /* assume failure by default */
8484

85+
names = _strtok(command, NULL);
86+
if (names == NULL)
87+
return (-1);
88+
8589
current = *head;
86-
for (i = 1; command[i] != NULL; i++)
90+
for (i = 1; names[i] != NULL; i++)
8791
{
88-
name = strtok(command[i], "=");
8992
while (current != NULL)
9093
{
91-
if (!_strcmp(current->name, name))
94+
if (!_strcmp(current->name, names[i]))
9295
{
9396
if (current == *head)
9497
*head = (*head)->next;
@@ -106,10 +109,12 @@ int unalias(alias_t **head, char **command)
106109

107110
if (exit_code != 0)
108111
{
109-
dprintf(2, "unalias: %s not found\n", name);
112+
dprintf(2, "unalias: %s not found\n", names[i]);
110113
exit_code = 1;
111114
}
115+
safe_free(names[i]);
112116
}
117+
free_str(names);
113118
return (exit_code);
114119
}
115120

alias_handler.c

Lines changed: 121 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,151 @@
11
#include "shell.h"
22

3+
static int exit_code;
4+
35
/**
46
* handle_alias - handles the processing of alias
57
* @head: a pointer to the list containing all aliases
68
* @command: the list of commands containing alias-specific lines
79
*
810
* Return: 0 on success, -1 on error
911
*/
10-
int handle_alias(alias_t **head, char **command)
12+
int handle_alias(alias_t **head, char *command)
1113
{
12-
char *value, *loc, *name, *tmp;
13-
ssize_t i, offset, exit_code = 0;
14+
if (_strlen(command) == 5)
15+
print_aliases(*head);
16+
17+
else if (!_strncmp(command, "alias", 5))
18+
{
19+
if (!_strchr(command, '='))
20+
process_non_matching(*head, command + 5, 1);
21+
else
22+
parse_aliases(command, head);
23+
}
1424

15-
if (!_strcmp("unalias", command[0]))
25+
else if (!_strncmp(command, "unalias", 7))
1626
return (unalias(head, command));
17-
if ((!_strcmp(command[0], "alias") && command[1] == NULL))
18-
print_aliases(*head);
19-
for (i = 1; command[i] != NULL; i++)
27+
28+
return (exit_code);
29+
}
30+
31+
/**
32+
* parse_aliases - extract aliases from the input string using regular
33+
* expressions.
34+
* @input: the input string containing aliases
35+
* @aliases: a pointer to a list of aliases
36+
*
37+
* Description: This function uses regular expressions to extract aliases from
38+
* the input string. It populates the provided array of Alias structures with
39+
* the parsed aliases and updates the aliasCount accordingly.
40+
*/
41+
void parse_aliases(const char *input, alias_t **aliases)
42+
{
43+
char *input_ptr = NULL;
44+
size_t valueLength, alias_count = 0;
45+
regmatch_t matches[3];
46+
regex_t regex;
47+
const char *pattern =
48+
"([^\"]\\S*|\"[^\"]*\"|'[^\']*')=([^\"]\\S*|\"[^\"]*\"|'[^\']*')";
49+
50+
if (regcomp(&regex, pattern, REG_EXTENDED) != 0)
51+
return; /* regular expression compilation failed */
52+
input_ptr = (char *)input;
53+
while (regexec(&regex, input_ptr, 3, matches, 0) == 0)
2054
{
21-
tmp = _strdup(command[i]);
22-
loc = _strchr(tmp, '=');
23-
if (loc != NULL)
55+
char name[MAX_ALIAS_LENGTH] = {0};
56+
char value[MAX_VALUE_LENGTH] = {0};
57+
58+
/* extract the alias name, accounts for the leading spaces */
59+
_strncpy(name, (input_ptr + 1) + matches[1].rm_so,
60+
(matches[1].rm_eo - 1) - matches[1].rm_so);
61+
_strncpy(value, input_ptr + matches[2].rm_so,
62+
matches[2].rm_eo - matches[2].rm_so); /* extract the alias value */
63+
name[matches[1].rm_eo - matches[1].rm_so] = '\0';
64+
65+
valueLength = matches[2].rm_eo - matches[2].rm_so;
66+
if (isquote(value[0])) /* remove quotes */
2467
{
25-
offset = (&loc[0]) - (&tmp[0]);
26-
tmp[offset] = '\0';
27-
name = _strdup(tmp);
28-
if (name == NULL)
29-
{
30-
safe_free(tmp);
31-
return (-1);
32-
}
33-
value = (tmp[offset + 1] == '"' || tmp[offset + 1] == '\'')
34-
? extract_value(&tmp[offset + 1]) : _strdup(&tmp[offset + 1]);
35-
if (value == NULL)
36-
{
37-
multi_free("ss", value, name);
38-
return (-1);
39-
}
40-
if (add_alias(head, name, value) == NULL)
68+
_strncpy(value, input_ptr + matches[2].rm_so + 1, valueLength - 2);
69+
value[valueLength - 2] = '\0';
70+
}
71+
else /* not enclosed in quotes, copy as is */
72+
value[valueLength] = '\0';
73+
if (add_alias(aliases, name, value) == NULL)
74+
return;
75+
if (alias_count)
76+
process_non_matching(*aliases, input_ptr, 0);
77+
alias_count++; /* increment alias count */
78+
input_ptr += matches[0].rm_eo; /* keep searching */
79+
}
80+
if (alias_count)
81+
process_non_matching(*aliases, input_ptr, 1);
82+
regfree(&regex);
83+
}
84+
85+
/**
86+
* process_non_matching - processes strings that do not have the `name=value`
87+
* format while parsing aliases
88+
* @aliases: a list containing aliases
89+
* @non_matching: the string to check for non-matching patterns
90+
* @end: used to signal the end. 1 means it can process the whole string at
91+
* once. 0 means it can do only word token at a time
92+
*/
93+
void process_non_matching(alias_t *aliases, const char *non_matching, int end)
94+
{
95+
char *token, *dup;
96+
97+
if (non_matching == NULL || *non_matching == '\0')
98+
return; /* there's nothing to work on, everything matched */
99+
100+
dup = _strdup(non_matching);
101+
token = strtok(dup, " ");
102+
103+
/* it is non-matching if it doesn't contain an equal sign */
104+
if (!_strchr(token, '='))
105+
{
106+
if (end)
107+
{
108+
while (token != NULL)
41109
{
42-
multi_free("ss", value, name);
43-
return (-1);
110+
exit_code = print_alias(aliases, token);
111+
token = strtok(NULL, " ");
44112
}
45-
multi_free("ss", value, name);
46113
}
47114
else
48-
exit_code = print_alias(*head, command[i]);
49-
safe_free(tmp);
115+
exit_code = print_alias(aliases, token);
50116
}
51-
return (exit_code);
117+
free(dup);
52118
}
53119

54120
/**
55-
* extract_value - returns the string value enclosed in quotes
56-
* @value: the string containing value
57-
*
58-
* Return: the string data without the quotes
121+
* build_alias_cmd - builds the correct command line when the received input is
122+
* a valid alias command
123+
* @sub_command: a pointer to the array containing the commands
124+
* @alias_value: the value of the alias command
59125
*/
60-
char *extract_value(const char *value)
126+
void build_alias_cmd(char ***sub_command, char *alias_value)
61127
{
62-
int i, j;
63-
char quote = value[0];
64-
int length = strlen(value);
65-
char *content = malloc(length);
128+
char **dup_array = NULL;
66129

67-
if (content == NULL)
130+
if ((*sub_command)[1] != NULL)
68131
{
69-
return (NULL);
70-
}
132+
/* save a copy of the the commands array, excluding the alias */
133+
dup_array = duplicate_str_array((*sub_command) + 1);
134+
135+
/* memory and build the command line string based on the alias value */
136+
free_str(*sub_command);
137+
*sub_command = _strtok(alias_value, NULL);
138+
139+
/* concatenate both arrays to form a complete command string */
140+
concatenate_arrays(sub_command, dup_array);
71141

72-
for (i = 1, j = 0; i < length && value[i] != quote; ++i, ++j)
142+
/* clean up and return */
143+
free_str(dup_array);
144+
}
145+
else
73146
{
74-
content[j] = value[i];
147+
/* there was alias alright but no other arguments */
148+
free_str(*sub_command);
149+
*sub_command = _strtok(alias_value, NULL);
75150
}
76-
content[j] = '\0';
77-
78-
return (content);
79151
}

builtins_handler.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@
1212
* Return: exit code
1313
*/
1414
int handle_builtin(char **sub_command, char **commands, char *line,
15-
alias_t *aliases, path_t *path_list, int exit_code)
15+
alias_t *aliases, path_t *path_list, int exit_code)
1616
{
17-
if (!_strcmp(sub_command[0], "env") || !_strcmp(sub_command[0], "printenv"))
17+
if (!_strcmp(sub_command[0], "env") ||
18+
!_strcmp(sub_command[0], "printenv"))
1819
{
1920
_printenv();
2021
return (0);
2122
}
2223
else if (!_strcmp(sub_command[0], "exit"))
2324
{
24-
return (handle_exit(sub_command[1], exit_code, multi_free,
25-
sub_command, commands, line, &path_list, &aliases));
25+
return (handle_exit(sub_command[1], exit_code, multi_free, sub_command,
26+
commands, line, &path_list, &aliases));
2627
}
2728

2829
/* let's handle the builtin 'cd' command */
@@ -33,7 +34,7 @@ int handle_builtin(char **sub_command, char **commands, char *line,
3334
{
3435
if (sub_command[1] && sub_command[2])
3536
return (setenv(sub_command[1], sub_command[2], 1));
36-
return (1); /* inavlid number of parameters received */
37+
return (1); /* invalid number of parameters received */
3738
}
3839
else if (!_strcmp(sub_command[0], "unsetenv"))
3940
return (_unsetenv(sub_command[1]));

parser.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ int parse_line(char *line, path_t *path_list)
2323
/* first of all, let's get rid of all comments */
2424
line = handle_comments(line);
2525

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

3434
exit_code = parse(commands, path_list, line);
3535
free_str(commands);
36+
3637
return (exit_code);
3738
}
3839

@@ -136,18 +137,18 @@ void parse_helper(char **commands, char **sub_command, path_t *path_list,
136137
if (!_strcmp(sub_command[0], "alias") ||
137138
!_strcmp(sub_command[0], "unalias"))
138139
{
139-
exit_code = handle_alias(&aliases, sub_command);
140+
exit_code = handle_alias(&aliases, commands[index]);
140141
free_str(sub_command);
141142
return;
142143
}
143144

144145
alias_value = get_alias(aliases, sub_command[0]);
145146
if (alias_value != NULL)
146147
{
147-
safe_free(sub_command[0]);
148-
sub_command[0] = _strdup(alias_value);
148+
build_alias_cmd(&sub_command, alias_value);
149149
safe_free(alias_value);
150150
}
151+
151152
exit_code = handle_builtin(sub_command, commands, line, aliases, path_list,
152153
exit_code);
153154
if (exit_code != NOT_BUILTIN)

0 commit comments

Comments
 (0)