fix: now compiles and works for simple commands + clang format

This commit is contained in:
matteo 2026-01-17 19:11:55 +01:00
parent 6099bbb9e3
commit 352c122549
23 changed files with 168 additions and 150 deletions

View file

@ -7,26 +7,22 @@
TODO TODO
### Build ### Build
run theses commands: run this command:
`autoreconf --force --verbose --install && ./configure` `autoreconf --force --verbose --install`
### Test
run this command:
`./configure CFLAGS='-std=c99 -Werror -Wall -Wextra -Wvla'`
then:
`make` `make`
`./src/42sh --help`
### Testing
#### asan
run this command: run this command:
`./configure CFLAGS='-std=c99 -Werror -Wall -Wextra -Wvla -g -fsanitize=address'`
then:
`make check` `make check`
#### debug (asan)
run this command:
`./src/debug`
#### testsuite
run this command:
`./src/testsuite`
## Authors ## Authors
- Matteo Flebus - Matteo Flebus

View file

@ -28,8 +28,8 @@ bin_PROGRAMS = 42sh
check_PROGRAMS = testsuite check_PROGRAMS = testsuite
testsuite_CFLAGS = $(42sh_CFLAGS) #testsuite_CFLAGS = $(42sh_CFLAGS)
testsuite_CFLAGS += $(CRITERION_CFLAGS) #testsuite_CFLAGS += $(CRITERION_CFLAGS)
testsuite_SOURCES = ../tests/unit/lexer/lexer_tests.c \ testsuite_SOURCES = ../tests/unit/lexer/lexer_tests.c \
../tests/unit/utils/utils_tests.c ../tests/unit/utils/utils_tests.c
@ -42,8 +42,8 @@ testsuite_LDADD = $(42sh_LDADD) $(CRITERION_LIBS)
check_PROGRAMS += debug check_PROGRAMS += debug
debug_CFLAGS = $(42sh_CFLAGS) #debug_CFLAGS = $(42sh_CFLAGS)
debug_CFLAGS += -fsanitize=address -g #debug_CFLAGS += -fsanitize=address -g
debug_SOURCES = $(42sh_SOURCES) debug_SOURCES = $(42sh_SOURCES)

View file

@ -1,13 +1,13 @@
#include "execution.h" #include "execution.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "../utils/ast/ast.h" #include "../utils/ast/ast.h"
@ -262,7 +262,9 @@ int execution(struct ast *ast)
int fd_target = redir->io_number; int fd_target = redir->io_number;
if (fd_target == -1) if (fd_target == -1)
{ {
if (redir->type == AST_REDIR_TYPE_LESS || redir->type == AST_REDIR_TYPE_DLESS || redir->type == AST_REDIR_TYPE_LESSAND) if (redir->type == AST_REDIR_TYPE_LESS
|| redir->type == AST_REDIR_TYPE_DLESS
|| redir->type == AST_REDIR_TYPE_LESSAND)
fd_target = 0; fd_target = 0;
else else
fd_target = 1; fd_target = 1;
@ -274,22 +276,24 @@ int execution(struct ast *ast)
int flags = 0; int flags = 0;
int mode = 0644; int mode = 0644;
if (redir->type == AST_REDIR_TYPE_GREAT || redir->type == AST_REDIR_TYPE_CLOBBER) if (redir->type == AST_REDIR_TYPE_GREAT
|| redir->type == AST_REDIR_TYPE_CLOBBER)
{ {
flags = O_WRONLY | O_CREAT | O_TRUNC; flags = O_WRONLY | O_CREAT | O_TRUNC;
new_fd = open(redir->filename, flags, mode); new_fd = open(redir->filename, flags, mode);
} }
else if (redir->type == AST_REDIR_TYPE_DGREAT) else if (redir->type == AST_REDIR_TYPE_DGREAT)
{ {
flags = O_WRONLY | O_CREAT | O_APPEND; flags = O_WRONLY | O_CREAT | O_APPEND;
new_fd = open(redir->filename, flags, mode); new_fd = open(redir->filename, flags, mode);
} }
else if (redir->type == AST_REDIR_TYPE_LESS) else if (redir->type == AST_REDIR_TYPE_LESS)
{ {
flags = O_RDONLY; flags = O_RDONLY;
new_fd = open(redir->filename, flags); new_fd = open(redir->filename, flags);
} }
else if (redir->type == AST_REDIR_TYPE_GREATAND || redir->type == AST_REDIR_TYPE_LESSAND) else if (redir->type == AST_REDIR_TYPE_GREATAND
|| redir->type == AST_REDIR_TYPE_LESSAND)
{ {
// Simple fd duplication // Simple fd duplication
new_fd = atoi(redir->filename); new_fd = atoi(redir->filename);
@ -297,7 +301,8 @@ int execution(struct ast *ast)
if (dup2(new_fd, fd_target) == -1) if (dup2(new_fd, fd_target) == -1)
{ {
perror("dup2"); perror("dup2");
if (saved_fd != -1) close(saved_fd); if (saved_fd != -1)
close(saved_fd);
return 1; return 1;
} }
new_fd = -2; // Mark as "already duped" new_fd = -2; // Mark as "already duped"
@ -306,7 +311,8 @@ int execution(struct ast *ast)
if (new_fd == -1) if (new_fd == -1)
{ {
perror("open"); perror("open");
if (saved_fd != -1) close(saved_fd); if (saved_fd != -1)
close(saved_fd);
return 1; return 1;
} }
@ -316,7 +322,8 @@ int execution(struct ast *ast)
{ {
perror("dup2"); perror("dup2");
close(new_fd); close(new_fd);
if (saved_fd != -1) close(saved_fd); if (saved_fd != -1)
close(saved_fd);
return 1; return 1;
} }
close(new_fd); close(new_fd);

View file

@ -2,6 +2,7 @@
#define IO_BACKEND_H #define IO_BACKEND_H
#include <sys/types.h> #include <sys/types.h>
#include "utils/args/args.h" #include "utils/args/args.h"
// Error codes // Error codes

View file

@ -69,62 +69,62 @@ static void set_token_spechar(struct token *tok, char *begin, ssize_t size)
return; return;
switch (begin[0]) switch (begin[0])
{ {
case EOF: case EOF:
tok->type = TOKEN_EOF; tok->type = TOKEN_EOF;
break; break;
case ';': case ';':
tok->type = TOKEN_SEMICOLON; tok->type = TOKEN_SEMICOLON;
break; break;
case '\n': case '\n':
tok->type = TOKEN_NEWLINE; tok->type = TOKEN_NEWLINE;
break; break;
case '\'': case '\'':
tok->type = TOKEN_QUOTE; tok->type = TOKEN_QUOTE;
break; break;
case '"': case '"':
tok->type = TOKEN_DOUBLE_QUOTE; tok->type = TOKEN_DOUBLE_QUOTE;
break; break;
case '`': case '`':
tok->type = TOKEN_GRAVE; tok->type = TOKEN_GRAVE;
break; break;
case '#': case '#':
tok->type = TOKEN_COMMENT; tok->type = TOKEN_COMMENT;
break; break;
case '|': case '|':
tok->type = TOKEN_PIPE; tok->type = TOKEN_PIPE;
break; break;
case '&': case '&':
tok->type = TOKEN_AMPERSAND; tok->type = TOKEN_AMPERSAND;
break; break;
case '\\': case '\\':
tok->type = TOKEN_BACKSLASH; tok->type = TOKEN_BACKSLASH;
break; break;
case '$': case '$':
tok->type = TOKEN_DOLLAR; tok->type = TOKEN_DOLLAR;
break; break;
case '(': case '(':
tok->type = TOKEN_LEFT_PAREN; tok->type = TOKEN_LEFT_PAREN;
break; break;
case ')': case ')':
tok->type = TOKEN_RIGHT_PAREN; tok->type = TOKEN_RIGHT_PAREN;
break; break;
case '{': case '{':
tok->type = TOKEN_LEFT_BRACKET; tok->type = TOKEN_LEFT_BRACKET;
break; break;
case '}': case '}':
tok->type = TOKEN_RIGHT_BRACKET; tok->type = TOKEN_RIGHT_BRACKET;
break; break;
case '<': case '<':
tok->type = TOKEN_LESS; tok->type = TOKEN_LESS;
break; break;
case '>': case '>':
tok->type = TOKEN_GREATER; tok->type = TOKEN_GREATER;
break; break;
case '*': case '*':
tok->type = TOKEN_STAR; tok->type = TOKEN_STAR;
break; break;
default: default:
break; break;
} }
} }

View file

@ -69,9 +69,14 @@ int main(int argc, char **argv)
// Execute AST // Execute AST
return_code = execution(command_ast); return_code = execution(command_ast);
ast_free(&command_ast);
// Retrieve and build next AST // Retrieve and build next AST
command_ast = get_ast(); command_ast = get_ast();
} }
ast_free(&command_ast);
if (command_ast == NULL) if (command_ast == NULL)
return ERR_INPUT_PROCESSING; return ERR_INPUT_PROCESSING;

View file

@ -7,8 +7,8 @@
#include <string.h> #include <string.h>
#include "lexer/lexer.h" #include "lexer/lexer.h"
#include "utils/lists/lists.h"
#include "parser/parsing_utils.h" #include "parser/parsing_utils.h"
#include "utils/lists/lists.h"
// === Static functions // === Static functions
// ... // ...

View file

@ -1,9 +1,11 @@
#define _POSIX_C_SOURCE 200809L
// === Includes // === Includes
#include "parsing_utils.h" #include "parsing_utils.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "lexer/lexer.h" #include "lexer/lexer.h"
#include "utils/ast/ast.h" #include "utils/ast/ast.h"
@ -58,7 +60,8 @@ struct ast *parse_simple_command(void)
while (!isterminator(token)) while (!isterminator(token))
{ {
token = POP_TOKEN(); token = POP_TOKEN();
command_elements = list_append(command_elements, token->data); char *word = strdup(token->data);
command_elements = list_append(command_elements, word);
token = PEEK_TOKEN(); token = PEEK_TOKEN();
} }
@ -86,6 +89,7 @@ struct ast *parse_list(void)
} }
token = PEEK_TOKEN(); token = PEEK_TOKEN();
} }
result_list = list_append(result_list, current_node);
return ast_create_list(result_list); return ast_create_list(result_list);
} }
@ -163,7 +167,9 @@ struct ast *parse_compound_list(void)
return NULL; return NULL;
} }
command_elements = list_append(command_elements, token->data); char *word = strdup(token->data);
command_elements = list_append(command_elements, word);
token = POP_TOKEN(); token = POP_TOKEN();
} }

View file

@ -39,14 +39,14 @@ struct ast *parse_shell_command(void);
/* @brief parses commands inside if/else clauses and returns the corresponding /* @brief parses commands inside if/else clauses and returns the corresponding
* AST list * AST list
*/ */
struct ast* parse_compound_list(void); struct ast *parse_compound_list(void);
/* /*
*/ */
struct ast* parse_and_or(void); struct ast *parse_and_or(void);
/* /*
*/ */
struct ast* parse_else_clause(void); struct ast *parse_else_clause(void);
#endif /* ! PARSING_UTILS_H */ #endif /* ! PARSING_UTILS_H */

View file

@ -1,13 +1,13 @@
#ifndef AST_H #ifndef AST_H
#define AST_H #define AST_H
#include "utils/ast/ast_and_or.h"
#include "utils/ast/ast_base.h" #include "utils/ast/ast_base.h"
#include "utils/ast/ast_command.h" #include "utils/ast/ast_command.h"
#include "utils/ast/ast_if.h"
#include "utils/ast/ast_and_or.h"
#include "utils/ast/ast_redir.h"
#include "utils/ast/ast_list.h"
#include "utils/ast/ast_end.h" #include "utils/ast/ast_end.h"
#include "utils/ast/ast_if.h"
#include "utils/ast/ast_list.h"
#include "utils/ast/ast_redir.h"
#include "utils/ast/ast_void.h" #include "utils/ast/ast_void.h"
#endif /* ! AST_H */ #endif /* ! AST_H */

View file

@ -1,4 +1,5 @@
#include "utils/ast/ast_and_or.h" #include "utils/ast/ast_and_or.h"
#include <stdlib.h> #include <stdlib.h>
bool ast_is_and_or(struct ast *node) bool ast_is_and_or(struct ast *node)
@ -13,7 +14,8 @@ struct ast_and_or *ast_get_and_or(struct ast *node)
return NULL; return NULL;
} }
struct ast *ast_create_and_or(struct ast *left, struct ast *right, enum ast_and_or_type type) struct ast *ast_create_and_or(struct ast *left, struct ast *right,
enum ast_and_or_type type)
{ {
struct ast_and_or *and_or = malloc(sizeof(struct ast_and_or)); struct ast_and_or *and_or = malloc(sizeof(struct ast_and_or));
if (!and_or) if (!and_or)

View file

@ -2,14 +2,17 @@
#define AST_AND_OR_H #define AST_AND_OR_H
#include <stdbool.h> #include <stdbool.h>
#include "utils/ast/ast_base.h" #include "utils/ast/ast_base.h"
enum ast_and_or_type { enum ast_and_or_type
{
AST_AND_OR_TYPE_AND, AST_AND_OR_TYPE_AND,
AST_AND_OR_TYPE_OR AST_AND_OR_TYPE_OR
}; };
struct ast_and_or { struct ast_and_or
{
struct ast *left; struct ast *left;
struct ast *right; struct ast *right;
enum ast_and_or_type type; enum ast_and_or_type type;
@ -17,7 +20,8 @@ struct ast_and_or {
bool ast_is_and_or(struct ast *node); bool ast_is_and_or(struct ast *node);
struct ast_and_or *ast_get_and_or(struct ast *node); struct ast_and_or *ast_get_and_or(struct ast *node);
struct ast *ast_create_and_or(struct ast *left, struct ast *right, enum ast_and_or_type type); struct ast *ast_create_and_or(struct ast *left, struct ast *right,
enum ast_and_or_type type);
void ast_free_and_or(struct ast_and_or *and_or); void ast_free_and_or(struct ast_and_or *and_or);
#endif /* ! AST_AND_OR_H */ #endif /* ! AST_AND_OR_H */

View file

@ -1,8 +1,8 @@
#include "utils/ast/ast_command.h" #include "utils/ast/ast_command.h"
#include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#include "utils/lists/lists.h" #include "utils/lists/lists.h"

View file

@ -3,8 +3,8 @@
#include <stdbool.h> #include <stdbool.h>
#include "utils/lists/lists.h"
#include "utils/ast/ast_base.h" #include "utils/ast/ast_base.h"
#include "utils/lists/lists.h"
struct ast_command struct ast_command
{ {

View file

@ -1,8 +1,8 @@
#include "utils/ast/ast_end.h" #include "utils/ast/ast_end.h"
#include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
bool ast_is_end(struct ast *node) bool ast_is_end(struct ast *node)
{ {

View file

@ -3,8 +3,8 @@
#include <stdbool.h> #include <stdbool.h>
#include "utils/lists/lists.h"
#include "utils/ast/ast_base.h" #include "utils/ast/ast_base.h"
#include "utils/lists/lists.h"
/** /**
* Checks if the given AST node is of type AST_END. * Checks if the given AST node is of type AST_END.

View file

@ -1,8 +1,8 @@
#include "utils/ast/ast_if.h" #include "utils/ast/ast_if.h"
#include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
struct ast *ast_create_if(struct ast *condition, struct ast *then_clause, struct ast *ast_create_if(struct ast *condition, struct ast *then_clause,
struct ast *else_clause) struct ast *else_clause)

View file

@ -1,7 +1,7 @@
#include "utils/ast/ast.h"
#include <assert.h> #include <assert.h>
#include "utils/ast/ast.h"
struct ast *ast_create_list(struct list *list) struct ast *ast_create_list(struct list *list)
{ {
struct ast_list *ast_list = malloc(sizeof(struct ast_list)); struct ast_list *ast_list = malloc(sizeof(struct ast_list));
@ -16,7 +16,7 @@ struct ast *ast_create_list(struct list *list)
struct ast_list *ast_get_list(struct ast *node) struct ast_list *ast_get_list(struct ast *node)
{ {
assert(node != NULL); assert(node != NULL);
return (struct ast_list*)node->data; return (struct ast_list *)node->data;
} }
bool ast_is_list(struct ast *node) bool ast_is_list(struct ast *node)

View file

@ -1,4 +1,5 @@
#include "utils/ast/ast_redir.h" #include "utils/ast/ast_redir.h"
#include <stdlib.h> #include <stdlib.h>
bool ast_is_redir(struct ast *node) bool ast_is_redir(struct ast *node)
@ -13,13 +14,16 @@ struct ast_redir *ast_get_redir(struct ast *node)
return NULL; return NULL;
} }
struct ast *ast_create_redir(struct ast *child, char *filename, int io_number, enum ast_redir_type type) struct ast *ast_create_redir(struct ast *child, char *filename, int io_number,
enum ast_redir_type type)
{ {
struct ast_redir *redir = malloc(sizeof(struct ast_redir)); struct ast_redir *redir = malloc(sizeof(struct ast_redir));
if (!redir) if (!redir)
return NULL; return NULL;
redir->child = child; redir->child = child;
redir->filename = filename; // Takes ownership? Usually yes in simple ASTs, or dup. Let's assume pointer copy for now, but user must manage memory. redir->filename =
filename; // Takes ownership? Usually yes in simple ASTs, or dup. Let's
// assume pointer copy for now, but user must manage memory.
redir->io_number = io_number; redir->io_number = io_number;
redir->type = type; redir->type = type;

View file

@ -2,28 +2,33 @@
#define AST_REDIR_H #define AST_REDIR_H
#include <stdbool.h> #include <stdbool.h>
#include "utils/ast/ast_base.h" #include "utils/ast/ast_base.h"
enum ast_redir_type { enum ast_redir_type
AST_REDIR_TYPE_LESS, // < {
AST_REDIR_TYPE_GREAT, // > AST_REDIR_TYPE_LESS, // <
AST_REDIR_TYPE_DLESS, // << AST_REDIR_TYPE_GREAT, // >
AST_REDIR_TYPE_DGREAT, // >> AST_REDIR_TYPE_DLESS, // <<
AST_REDIR_TYPE_LESSAND, // <& AST_REDIR_TYPE_DGREAT, // >>
AST_REDIR_TYPE_GREATAND, // >& AST_REDIR_TYPE_LESSAND, // <&
AST_REDIR_TYPE_CLOBBER // >| AST_REDIR_TYPE_GREATAND, // >&
AST_REDIR_TYPE_CLOBBER // >|
}; };
struct ast_redir { struct ast_redir
{
struct ast *child; struct ast *child;
char *filename; char *filename;
int io_number; // The FD being redirected (default -1 if not specified, implies 0 or 1 based on type) int io_number; // The FD being redirected (default -1 if not specified,
// implies 0 or 1 based on type)
enum ast_redir_type type; enum ast_redir_type type;
}; };
bool ast_is_redir(struct ast *node); bool ast_is_redir(struct ast *node);
struct ast_redir *ast_get_redir(struct ast *node); struct ast_redir *ast_get_redir(struct ast *node);
struct ast *ast_create_redir(struct ast *child, char *filename, int io_number, enum ast_redir_type type); struct ast *ast_create_redir(struct ast *child, char *filename, int io_number,
enum ast_redir_type type);
void ast_free_redir(struct ast_redir *redir); void ast_free_redir(struct ast_redir *redir);
#endif /* ! AST_REDIR_H */ #endif /* ! AST_REDIR_H */

View file

@ -1,8 +1,8 @@
#include "utils/ast/ast_void.h" #include "utils/ast/ast_void.h"
#include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
bool ast_is_void(struct ast *node) bool ast_is_void(struct ast *node)
{ {

View file

@ -3,8 +3,8 @@
#include <stdbool.h> #include <stdbool.h>
#include "utils/lists/lists.h"
#include "utils/ast/ast_base.h" #include "utils/ast/ast_base.h"
#include "utils/lists/lists.h"
/** /**
* Checks if the given AST node is of type AST_VOID. * Checks if the given AST node is of type AST_VOID.

View file

@ -5,8 +5,8 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include "lexer/lexer.h"
#include "io_backend/io_backend.h" #include "io_backend/io_backend.h"
#include "lexer/lexer.h"
TestSuite(peek_token); TestSuite(peek_token);
@ -14,11 +14,7 @@ Test(peek_token, basic_empty)
{ {
// simulates input // simulates input
char command[] = ""; char command[] = "";
struct iob_context context = struct iob_context context = { IOB_MODE_CMD, command };
{
IOB_MODE_CMD,
command
};
iob_init(&context); iob_init(&context);
// test // test
@ -38,11 +34,7 @@ Test(peek_token, basic_word)
{ {
// simulates input // simulates input
char command[] = "hello"; char command[] = "hello";
struct iob_context context = struct iob_context context = { IOB_MODE_CMD, command };
{
IOB_MODE_CMD,
command
};
iob_init(&context); iob_init(&context);
// test // test
@ -60,11 +52,7 @@ Test(peek_token, basic_words)
{ {
// simulates input // simulates input
char command[] = "echo hello there"; char command[] = "echo hello there";
struct iob_context context = struct iob_context context = { IOB_MODE_CMD, command };
{
IOB_MODE_CMD,
command
};
iob_init(&context); iob_init(&context);
// ======= echo // ======= echo