Skip to content

Commit abb2ddf

Browse files
committed
feat: respect IFS environment variable for internal splits.
1 parent 3c18731 commit abb2ddf

19 files changed

Lines changed: 227 additions & 211 deletions

Makefile

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ LIBFT_DIR = ./libft
44
LIBFT_PATH = $(LIBFT_DIR)/libft.a
55

66
CC = gcc
7-
FLAGS = -g -Wall -Wextra -Werror #-fsanitize=address
7+
8+
FLAGS = -g -Wall -Wextra -Werror -fsanitize=address -I/opt/homebrew/opt/readline/include -L/opt/homebrew/opt/readline/lib -lreadline -Wno-unused-command-line-argument #-fsanitize=address
89

910
MEMORY_ALLOCATOR_SOURCES = memory-allocator/aborter.c memory-allocator/allocator.c
1011
SOURCES = src/execute/execute_utils.c src/builtin/cd.c src/builtin/exit.c src/builtin/export.c src/builtin/export_utils.c \
@@ -13,7 +14,7 @@ SOURCES = src/execute/execute_utils.c src/builtin/cd.c src/builtin/exit.c src/bu
1314
src/lexer/lexer.c src/lexer/unquote.c src/lexer/lexer_utils.c src/execute/execute.c \
1415
src/lexer/lexer_error_message.c src/lexer/is_valid.c src/execute/error_message.c src/execute/fd_utils.c \
1516
src/parser/parser.c src/parser/parser_state.c src/parser/parser_utils.c src/execute/heredoc.c \
16-
src/expander/expander.c src/splitter.c src/lexer/syntax_analyzer.c src/signal.c $(MEMORY_ALLOCATOR_SOURCES) \
17+
src/expander/expander.c src/lexer/syntax_analyzer.c src/signal.c $(MEMORY_ALLOCATOR_SOURCES) \
1718
src/redirections/redirections.c src/env/global_env.c src/utils/unsafe_utils.c src/utils/char_classification.c src/utils/string_utils.c \
1819
src/utils/quote_classification.c src/expander/expander_2.c
1920

@@ -31,15 +32,22 @@ $(TEST_PATH):
3132

3233
test: $(TEST_PATH) $(NAME)
3334
@printf "$(CLEAN_CAR)$(GREEN_COLOR)[Tests compiling]$(BLUE_COLOR) : $(PURPLE_COLOR)$<$(NO_COLOR)"
34-
@$(CC) $(FLAGS) $(SOURCES:.c=.o) $(LIBFT_PATH) $(TEST_SOURCES) -o $(TEST_PATH)/tests -lcriterion -L/usr/local/lib -I/usr/local/include -lreadline
35+
@$(CC) $(FLAGS) $(SOURCES:.c=.o) $(LIBFT_PATH) $(TEST_SOURCES) -o $(TEST_PATH)/tests -I/opt/homebrew/Cellar/criterion/2.4.2_2/include -L/opt/homebrew/Cellar/criterion/2.4.2_2/lib -lcriterion
36+
@printf "$(CLEAN_CAR)$(GREEN_COLOR)Tests running right now. Please wait.\n$(BLUE_COLOR)$(NO_COLOR)"
37+
@./$(TEST_PATH)/tests ; export TEST_RESULT=$$? ; rm -f __test_file* | exit $$TEST_RESULT
38+
39+
testifs: $(TEST_PATH) $(NAME)
40+
@printf "$(CLEAN_CAR)$(GREEN_COLOR)[Tests compiling]$(BLUE_COLOR) : $(PURPLE_COLOR)$<$(NO_COLOR)"
41+
@$(CC) $(FLAGS) $(SOURCES:.c=.o) $(LIBFT_PATH) -o $(TEST_PATH)/tests -I/opt/homebrew/Cellar/criterion/2.4.2_2/include -L/opt/homebrew/Cellar/criterion/2.4.2_2/lib -lcriterion
3542
@printf "$(CLEAN_CAR)$(GREEN_COLOR)Tests running right now. Please wait.\n$(BLUE_COLOR)$(NO_COLOR)"
3643
@./$(TEST_PATH)/tests ; export TEST_RESULT=$$? ; rm -f __test_file* | exit $$TEST_RESULT
3744

45+
3846
$(LIBFT_PATH):
3947
@make bonus -C $(LIBFT_DIR) FLAGS="$(FLAGS)"
4048

4149
$(NAME): $(LIBFT_PATH) $(MINISHELL_OBJECTS)
42-
@$(CC) $(FLAGS) -o $(NAME) $(MINISHELL_OBJECTS) $(LIBFT_PATH) -L/usr/local/lib -I/usr/local/include -lreadline
50+
@$(CC) $(FLAGS) -o $(NAME) $(MINISHELL_OBJECTS) $(LIBFT_PATH)
4351
@sleep 0.2
4452
@echo "$(CLEAN_CAR)$(GREEN_COLOR)Minishell compiled!$(NO_COLOR)"
4553

@@ -60,7 +68,7 @@ fclean:
6068

6169
re: fclean all
6270

63-
.PHONY: all clean fclean re
71+
.PHONY: all clean fclean re test testifs
6472

6573
NO_COLOR = \x1b[0m
6674
GREEN_COLOR = \x1b[32;01m

includes/char_classification.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,12 @@
1313
#ifndef CHAR_CLASSIFICATION_H
1414
# define CHAR_CLASSIFICATION_H
1515

16-
/**
17-
* @file char_classification.h
18-
* @file char_classification.c
19-
*
20-
* @brief This file contains macros and enums for
21-
* character classification.
22-
*
23-
* @description This file completely defines what our
24-
* shell should understand when it comes to characters.
25-
*
26-
* @note This file completely defines what our shellshould understand
27-
* regarding characters. If this file makes you feel like we just told
28-
* you that cars have 4 wheels, then you are right. But we need to be
29-
* explicit about it.
30-
*
31-
* @note You can find tons of code that does not care about these details.
32-
* and probably you'll see that they going to be a soup instead of being a
33-
* code. This file is very critical. So we carefully read the manual before
34-
* and during writing this file.
35-
*
36-
**/
3716
typedef enum s_quote
3817
{
3918
DOUBLE_QUOTE = '\"',
4019
SINGLE_QUOTE = '\''
4120
} t_quote;
4221

43-
int is_field_terminator(char c);
4422
int is_meta_char(char c);
4523
int is_whitespace(char c);
4624
int is_quote(char c);

includes/minishell.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,13 @@ void handle_invalid_input(t_token *lexer_data);
112112

113113
// expander
114114
void expand(t_token **head);
115-
void internal_field_split(t_token **token);
116-
void insert_uword_tokens(t_token **token_ptr, char **strings);
115+
void internal_field_split(t_token **token, t_token**next_token_ptr);
117116
void expand_string(char **string);
118117
char *replace_string(char *input, int p_start,
119118
int p_len, char *replacement);
120119
int is_nameless_variable(t_token *token);
121120
void expand_token(t_token *token, t_token **head,
122-
t_token **token_ptr, t_token **prev_ptr);
121+
t_token **token_ptr, t_token **prev_ptr, t_token**next_token);
123122

124123
// parser
125124
t_command *parse(t_token *lexer_data);
@@ -184,4 +183,8 @@ void abort_function(void);
184183
void path_error(char *cmd);
185184
void pid_error(int *prev_pipe, int *next_pipe);
186185

186+
int are_quotes_valid(t_token *token);
187+
t_token *do_ifs(char *str);
188+
t_token **find_token_ptr_before(t_token **head, t_token *tofind);
189+
187190
#endif

includes/utils.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ char *ft_str_arr_join(char **str_list, unsigned int str_count);
2020
int skip_white_spaces(const char *str);
2121
int find_char(const char *str, char looking_for);
2222
int is_escaped(char *input, unsigned int index);
23-
int is_internal_field_sep(char *str, int index);
24-
char **str_split(char const *str, int (is_delimiter)(char *, int));
23+
int is_internal_field_sep(char c);
2524
int count_len(const char *str, int (*is_valid)(char c));
2625
int str_arr_size(char **strings);
2726
char **ft_unsafe_strarrdup(char **arr);

src/expander/expander.c

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "../../includes/char_classification.h"
1717
#include "../../memory-allocator/allocator.h"
1818
#include "../../includes/env.h"
19+
#include <stdio.h>
1920

2021
int expand_variable(char **input, int index)
2122
{
@@ -85,23 +86,79 @@ void expand(t_token **head)
8586
while (token)
8687
{
8788
if (token->type == UNQUOTED_WORD || token->type == DOUBLE_QUOTED_WORD)
88-
expand_token(token, head, token_ptr, prev_ptr);
89+
expand_token(token, head, token_ptr, prev_ptr, &token);
8990
prev_ptr = token_ptr;
9091
token_ptr = &token->next;
9192
token = token->next;
9293
}
9394
}
9495

95-
void internal_field_split(t_token **token_ptr)
96+
t_token *do_ifs(char *str)
9697
{
97-
char **new_words;
98+
//printf("do_ifs: %s\n", str);
99+
int len = ft_strlen(str);
100+
int i = 0;
101+
t_token *head = NULL;
102+
int last_was_word = 0;
103+
104+
if (is_internal_field_sep(str[0])) {
105+
i++;
106+
if (i < len && is_whitespace(str[i]) && is_internal_field_sep(str[i])) {
107+
while (i < len && is_whitespace(str[i]) && is_internal_field_sep(str[i]))
108+
i++;
109+
if (is_internal_field_sep(str[i]))
110+
i++;
111+
}
112+
head = lexer_data_new((t_token){NULL, DELIMITER, NULL});
113+
}
114+
115+
while (i < len) {
116+
int start = i;
117+
int substrlen = 0;
118+
while (i < len && !is_internal_field_sep(str[i]))
119+
i++, substrlen++;
120+
121+
if (last_was_word)
122+
lexer_data_append(&head, lexer_data_new((t_token){NULL, DELIMITER, NULL}));
123+
lexer_data_append(&head, lexer_data_new((t_token){ft_substr(str, start, substrlen), UNQUOTED_WORD, NULL}));
124+
last_was_word = 1;
125+
if (i < len && is_internal_field_sep(str[i])) {
126+
i++;
127+
while (i < len && is_whitespace(str[i]))
128+
i++;
129+
}
130+
}
131+
132+
/* debug purposes - inspect tokens
133+
134+
t_token t = *head;
135+
while (t.next) {
136+
printf(t.type == UNQUOTED_WORD ? "'%s' ->" : "'DELIMITER' -> ", t.value);
137+
t = *t.next;
138+
}
139+
printf(t.type == UNQUOTED_WORD ? "'%s'\n" : "'DELIMITER'\n", t.value);
140+
*/
141+
return head;
142+
}
143+
144+
void internal_field_split(t_token **token_ptr, t_token **next_token_ptr)
145+
{
146+
t_token *new_words;
98147
t_token *token;
99148

100149
token = *token_ptr;
101-
new_words = str_split(token->value, is_internal_field_sep);
102-
if (str_arr_size(new_words) == 1)
150+
new_words = do_ifs(token->value);
151+
if (new_words == NULL || new_words->next == NULL)
103152
return ;
104-
safe_free(token->value);
105-
insert_uword_tokens(token_ptr, new_words);
106-
safe_free(new_words);
153+
154+
// move expander cursor to the last token
155+
*next_token_ptr = get_last_lexer_data(new_words);
156+
157+
// put new expanded tokens
158+
lexer_data_insert(token, new_words);
159+
160+
// remove legacy token
161+
t_token **prev = find_token_ptr_before(token_ptr, token);
162+
remove_token(prev, token_ptr, token);
163+
107164
}

src/expander/expander_2.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@
1515
#include "../../libft/libft.h"
1616

1717
void expand_token(t_token *token, t_token **head,
18-
t_token **token_ptr, t_token **prev_ptr)
18+
t_token **token_ptr, t_token **prev_ptr, t_token**next_token_ptr)
1919
{
2020
if (is_nameless_variable(token))
2121
token->value = ft_strdup("");
2222
else
2323
{
24+
int isvar = token->value[0] == '$';
2425
expand_string(&token->value);
2526
if (is_full_of_spaces(token->value))
2627
remove_token(prev_ptr, head, token);
27-
else if (token->type == UNQUOTED_WORD)
28-
internal_field_split(token_ptr);
28+
else if ((token->type == UNQUOTED_WORD && isvar))
29+
internal_field_split(token_ptr, next_token_ptr);
2930
}
3031
}

src/expander/expander_nonvariables.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,6 @@
1616
#include "../../includes/char_classification.h"
1717
#include "../../memory-allocator/allocator.h"
1818

19-
void insert_uword_tokens(t_token **token_ptr, char **strings)
20-
{
21-
t_token *token;
22-
t_token *list;
23-
t_token *new;
24-
int i;
25-
26-
token = *token_ptr;
27-
token->value = strings[0];
28-
list = NULL;
29-
i = 1;
30-
while (strings[i])
31-
{
32-
new = lexer_data_new((t_token){NULL, DELIMITER, NULL});
33-
lexer_data_append(&list, new);
34-
new = lexer_data_new((t_token){strings[i], UNQUOTED_WORD, NULL});
35-
lexer_data_append(&list, new);
36-
i++;
37-
}
38-
lexer_data_insert(token, list);
39-
}
40-
4119
int is_nameless_variable(t_token *token)
4220
{
4321
return (ft_strcmp(token->value, "$") == 0

src/handler.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "../includes/minishell.h"
1414
#include <stdlib.h>
15+
#include <stdio.h>
16+
#include <time.h>
1517

1618
int *get_exit_status(void)
1719
{
@@ -39,14 +41,16 @@ void handle_input(char *input)
3941
return (handle_invalid_input(lexer_data));
4042
if (is_empty(lexer_data))
4143
return ;
44+
if (are_quotes_valid(lexer_data) == 0)
45+
return (handle_invalid_input(lexer_data));
46+
unquote(lexer_data);
4247
expand(&lexer_data);
4348
if (!is_valid(lexer_data))
4449
return (handle_invalid_input(lexer_data));
45-
unquote(lexer_data);
4650
parser_data = parse(lexer_data);
4751
handle_file_redirections(parser_data);
4852
g_signal_type = RUNNING_COMMANDS;
53+
uninit_tokens(lexer_data);
4954
execute(parser_data);
5055
g_signal_type = PROMPT;
51-
uninit_tokens(lexer_data);
5256
}

src/lexer/is_valid.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ int are_tokens_valid(t_token *lexer_data)
5959
int is_valid(t_token *lexer_data)
6060
{
6161
return (are_tokens_valid(lexer_data)
62-
&& are_quotes_valid(lexer_data)
6362
&& is_there_lack_of_word(lexer_data)
6463
&& validate_pipes(lexer_data));
6564
}

src/lexer/lexer.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,15 @@ t_lexer_state word_state(t_token **lexer_data, char *input, int *const i)
5555
}
5656
else
5757
{
58-
token.type = UNQUOTED_WORD;
59-
while (is_unquoted_word_char(input[*i]) || is_escaped(input, *i))
58+
if (input[*i] == '$'){
6059
(*i)++;
60+
while (is_name_char(input[*i]))
61+
(*i)++;
62+
} else {
63+
while ((is_unquoted_word_char(input[*i]) || is_escaped(input, *i)) && input[*i] != '$')
64+
(*i)++;
65+
}
66+
token.type = UNQUOTED_WORD;
6167
(*i)--;
6268
}
6369
token.value = ft_substr(input, start_i, *i - start_i + 1);

0 commit comments

Comments
 (0)