From eac570d6f54ede48f30d456b3d20f9de526d7746 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Thu, 23 Oct 2025 19:03:00 +0200 Subject: [PATCH 01/23] ' --- .gitignore | 2 ++ micromake/src/micromake.c | 47 ++++++++++++++++++++++++++++++++++++++ microshell/a.out | Bin 19032 -> 0 bytes microshell/microshell.c | 10 +++++--- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 micromake/src/micromake.c delete mode 100755 microshell/a.out diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7756c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +a.out +*.o diff --git a/micromake/src/micromake.c b/micromake/src/micromake.c new file mode 100644 index 0000000..a2272e5 --- /dev/null +++ b/micromake/src/micromake.c @@ -0,0 +1,47 @@ +#define _POSIX_C_SOURCE 200809L +#define BUFFER_SIZE 1024 +#define STRING_BUFFER_SIZE 32 + +#include +#include +#include +#include + +// Helps to match a string (excludes blanks and special characters) +int is_char(char c) +{ + return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; +} + +int main(int argc, char **argv) +{ + // Open file + FILE *stream = fopen(argv[1], "r"); + if (stream == 0) + errx(1, "Could not open file"); + + // Allocate buffer + size_t buf_size = BUFFER_SIZE; + char *buf = malloc(sizeof(char) * buf_size); + if (buf == NULL) + errx(1, "Could not allocate more memory"); + + // Read + ssize_t nread; + while ((nread = getline(&buf, &buf_size, stream)) != -1) + { + int i = 0; + // Skip blanks + while (i < nread && isblank(buf[i])) + i++; + + // Read target name + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + while (is_char(buf[i])) + { + } + + // Read deps + } +} diff --git a/microshell/a.out b/microshell/a.out deleted file mode 100755 index a27d743861df091fe626dd55ae252deee130ac56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19032 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 diff --git a/microshell/microshell.c b/microshell/microshell.c index 72dbf99..4a7b661 100644 --- a/microshell/microshell.c +++ b/microshell/microshell.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,21 +7,24 @@ int main(int argc, char **argv) { if (argc < 2) - errx(1, "Not enough args"); + err(1, "Not enough args"); int id = fork(); if (id < 0) - errx(1, "Cannot fork"); + err(1, "Cannot fork"); if (id == 0) { int res = 0; wait(&res); + // printf("%d\n", res); return res; } else { int res = execl("/bin/sh", "supershell", "-c", argv[1], NULL); - exit(res); + printf("process exit status: %d\n", res); + // exit(res); + return res; } } From ce214b8bbd3b440f4b35dbc77c6c0b191c4a7637 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Fri, 24 Oct 2025 21:24:28 +0200 Subject: [PATCH 02/23] ' --- micromake/src/micromake.c | 94 ++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/micromake/src/micromake.c b/micromake/src/micromake.c index a2272e5..fda3fe2 100644 --- a/micromake/src/micromake.c +++ b/micromake/src/micromake.c @@ -8,40 +8,112 @@ #include // Helps to match a string (excludes blanks and special characters) -int is_char(char c) +static int is_char(char c) { return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; } +// Returns the next word from buf until buf_len, +// and the numbers of read characters in *read_chars +// WARNING allocates the result on the heap +static char *readWord(char *buf, size_t buf_len, size_t *read_chars) +{ + size_t i = 0; + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + while (i < buf_len && is_char(buf[i])) + { + // Reallocate more space if necessary + if (i >= str_buf_size - 1) + { + str_buf_size += STRING_BUFFER_SIZE; + str_buf = realloc(str_buf, str_buf_size); + if (str_buf == NULL) + errx(2, "Could not realloc"); + } + + str_buf[i] = buf[i]; + i++; + } + + str_buf[i] = '\0'; + *read_chars = i; + + return str_buf; +} + +int skip_blanks(char *buf, size_t buf_len) +{ + size_t i = 0; + while (i < buf_len && isblank(buf[i])) + i++; + return i; +} + int main(int argc, char **argv) { + if (argc < 2) + errx(2, "Not enough arguments"); + if (argc > 2) + errx(2, "Not enough arguments"); + // Open file FILE *stream = fopen(argv[1], "r"); if (stream == 0) - errx(1, "Could not open file"); + errx(2, "Could not open file"); // Allocate buffer size_t buf_size = BUFFER_SIZE; char *buf = malloc(sizeof(char) * buf_size); if (buf == NULL) - errx(1, "Could not allocate more memory"); + errx(2, "Could not allocate more memory"); // Read ssize_t nread; while ((nread = getline(&buf, &buf_size, stream)) != -1) { - int i = 0; + size_t u_nread = nread; + size_t i = 0; // Skip blanks - while (i < nread && isblank(buf[i])) - i++; + i += skip_blanks(buf + i, nread - i); // Read target name - size_t str_buf_size = STRING_BUFFER_SIZE; - char *str_buf = malloc(sizeof(char) * str_buf_size); - while (is_char(buf[i])) - { - } + size_t skipped_chars = 0; + char *rule_name = readWord(buf + i, nread - i, &skipped_chars); + if (skipped_chars != 0) + printf("%s:", rule_name); + i += skipped_chars; + + // Skip until ':' + i += skip_blanks(buf + i, nread - i); + if (buf[i] != ':') + errx(2, "Unexpected character '%c' after rule declaration '%s'", + buf[i], rule_name); + i++; // Read deps + while (i < u_nread) + { + // Skip blanks + i += skip_blanks(buf + i, nread - i); + + // Read word + size_t skipped_chars = 0; + char *dep_name = readWord(buf + i, nread - i, &skipped_chars); + if (skipped_chars != 0) + printf(" %s", dep_name); + free(dep_name); + i += skipped_chars; + + if (!is_char(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') + errx(2, "Unexpected character '%c'", buf[i]); + } + + i++; + free(rule_name); } + + free(buf); + fclose(stream); + return 0; } From 9dabdcfbfd0d503948a251f83346f58a677e2a3c Mon Sep 17 00:00:00 2001 From: Guillem George Date: Fri, 24 Oct 2025 23:16:13 +0200 Subject: [PATCH 03/23] ' --- .gitignore | 9 ++++++++- micromake/src/Microfile | 3 +++ minimake/Makefile | 3 +++ minimake/minimake.c | 31 +++++++++++++++++++++++++++++++ simple_ls/simple_ls.c | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 micromake/src/Microfile create mode 100644 minimake/Makefile create mode 100644 minimake/minimake.c create mode 100644 simple_ls/simple_ls.c diff --git a/.gitignore b/.gitignore index d7756c2..1801c29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ -a.out +*.out +*~ +*.swp *.o +*.a +*.so +*.class +*.log +*.core diff --git a/micromake/src/Microfile b/micromake/src/Microfile new file mode 100644 index 0000000..607b02a --- /dev/null +++ b/micromake/src/Microfile @@ -0,0 +1,3 @@ +qwertyu: +cbejw: a bc d +dmwq :d wdwd diff --git a/minimake/Makefile b/minimake/Makefile new file mode 100644 index 0000000..a1b29ea --- /dev/null +++ b/minimake/Makefile @@ -0,0 +1,3 @@ +CC= gcc +CFLAGS= -std=c99 -pedantic -Werror -Wall -Wextra -Wvla + diff --git a/minimake/minimake.c b/minimake/minimake.c new file mode 100644 index 0000000..e3abfb9 --- /dev/null +++ b/minimake/minimake.c @@ -0,0 +1,31 @@ +// Error Codes +#define INVALID_ARG 2 + +#include +#include +#include +#include +#include + +// TODO: +// Look at perror for stdlib functions +// Create an enum for error handling + +int handle_args(int argc, char **argv) +{ + int flags = 0; + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-h")) + errx(INVALID_ARG, "-h: not implemented"); + else if (strcmp(argv[i], "-f")) + errx(INVALID_ARG, "-f: not implemented"); + else if (strcmp(argv[i], "-p")) + errx(INVALID_ARG, "-p: not implemented"); + else + errx(INVALID_ARG, ": Pleaase give an argument"); + } +} + +int main(int argc, char **argv) +{} diff --git a/simple_ls/simple_ls.c b/simple_ls/simple_ls.c new file mode 100644 index 0000000..508c5df --- /dev/null +++ b/simple_ls/simple_ls.c @@ -0,0 +1,37 @@ +#include +#include +#include + +static void simple_ls(char *path) +{ + if (path == NULL) + errx(1, "Internal error: Passed NULL path"); + + DIR *dir = opendir(path); + if (dir == NULL) + errx(1, "Internal error: cannot open directory"); + + struct dirent *element; + while ((element = readdir(dir))) + { + puts(element->d_name); + } + + int res = closedir(dir); + if (res == -1) + errx(1, "Could not close dir"); +} + +int main(int argc, char **argv) +{ + if (argc < 2) + simple_ls("."); + else + { + for (int i = 1; i < argc; i++) + { + simple_ls(argv[i]); + } + } + return 0; +} From 6bca1e84fb2081650e09bd62ad6c4505a062f2e0 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Sat, 25 Oct 2025 14:19:33 +0200 Subject: [PATCH 04/23] ' --- minimake/src/hash_map/hash.c | 27 ++++++ minimake/src/hash_map/hash_map.c | 133 ++++++++++++++++++++++++++++++ minimake/src/hash_map/hash_map.h | 29 +++++++ minimake/src/main.c | 31 +++++++ minimake/src/minimake.c | 137 +++++++++++++++++++++++++++++++ minimake/src/minimake.h | 21 +++++ 6 files changed, 378 insertions(+) create mode 100644 minimake/src/hash_map/hash.c create mode 100644 minimake/src/hash_map/hash_map.c create mode 100644 minimake/src/hash_map/hash_map.h create mode 100644 minimake/src/main.c create mode 100644 minimake/src/minimake.c create mode 100644 minimake/src/minimake.h diff --git a/minimake/src/hash_map/hash.c b/minimake/src/hash_map/hash.c new file mode 100644 index 0000000..247893b --- /dev/null +++ b/minimake/src/hash_map/hash.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +#include "hash_map.h" + +/* +** Hash the key using FNV-1a 32 bits hash algorithm. +*/ +size_t hash(const char *key) +{ + if (!key) + return 0; + + uint32_t hash = 2166136261; // FNV offset basis + uint32_t prime = 16777619; // FNV prime + + while (*key) + { + hash ^= *key; + hash *= prime; + key++; + } + + return hash; +} diff --git a/minimake/src/hash_map/hash_map.c b/minimake/src/hash_map/hash_map.c new file mode 100644 index 0000000..5c57115 --- /dev/null +++ b/minimake/src/hash_map/hash_map.c @@ -0,0 +1,133 @@ +#include "hash_map.h" + +#include +#include +#include +#include + +struct hash_map *hashMapInit(size_t size) { + struct pair_list **data = calloc(size, sizeof(struct pair_list)); + struct hash_map *map = malloc(sizeof(struct hash_map)); + map->data = data; + map->size = size; + return map; +} + +bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, + bool *updated) { + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) { + if (updated) + *updated = false; + return false; + } + + // Insert into hashmap (head) + + size_t entry_hash = hash(key) % hash_map->size; + // Search if key is already present + struct pair_list *elt = hash_map->data[entry_hash]; + while (elt != NULL) { + if (strcmp(elt->key, key) == 0) { + elt->value = value; + if (updated) + *updated = true; + return true; + } + elt = elt->next; + } + + // Create entry + struct pair_list *new_entry = malloc(sizeof(struct pair_list)); + if (new_entry == NULL) + return false; + new_entry->key = key; + new_entry->value = value; + + new_entry->next = hash_map->data[entry_hash]; + hash_map->data[entry_hash] = new_entry; + + if (updated) + *updated = false; + + return true; +} + +void hashMapFree(struct hash_map *hash_map) { + if (hash_map == NULL) + return; + if (hash_map->data == NULL) + return; + + for (size_t i = 0; i < hash_map->size; i++) { + struct pair_list *entry = hash_map->data[i]; + while (entry != NULL) { + struct pair_list *next = entry->next; + free(entry); + entry = next; + } + } + free(hash_map->data); + free(hash_map); +} + +void hashMapDump(struct hash_map *hash_map) { + for (size_t i = 0; i < hash_map->size; i++) { + struct pair_list *entry = hash_map->data[i]; + bool is_null = true; + if (entry != NULL) { + is_null = false; + printf("%s: %s", entry->key, entry->value); + entry = entry->next; + } + while (entry != NULL) { + printf(", %s: %s", entry->key, entry->value); + entry = entry->next; + } + if (!is_null) + putchar('\n'); + } +} + +const char *hashMapGet(const struct hash_map *hash_map, const char *key) { + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + return NULL; + + size_t entry_hash = hash(key) % hash_map->size; + struct pair_list *entry = hash_map->data[entry_hash]; + while (entry != NULL && strcmp(entry->key, key) != 0) { + entry = entry->next; + } + if (entry == NULL) + return NULL; + + return entry->value; +} + +bool hashMapRemove(struct hash_map *hash_map, const char *key) { + if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) + return false; + + size_t entry_hash = hash(key) % hash_map->size; + struct pair_list *entry = hash_map->data[entry_hash]; + + if (entry == NULL) + return false; + if (strcmp(entry->key, key) == 0) { + hash_map->data[entry_hash] = entry->next; + free(entry); + return true; + } + + if (entry->next == NULL) + return false; + while (strcmp(entry->next->key, key) != 0) { + entry = entry->next; + if (entry->next == NULL) + return false; + } + + struct pair_list *elt_to_free = entry->next; + entry->next = entry->next->next; + free(elt_to_free); + return true; +} diff --git a/minimake/src/hash_map/hash_map.h b/minimake/src/hash_map/hash_map.h new file mode 100644 index 0000000..ca21916 --- /dev/null +++ b/minimake/src/hash_map/hash_map.h @@ -0,0 +1,29 @@ +#ifndef HASH_MAP_H +#define HASH_MAP_H + +#include +#include + +struct pair_list +{ + const char *key; + char *value; + struct pair_list *next; +}; + +struct hash_map +{ + struct pair_list **data; + size_t size; +}; + +size_t hash(const char *str); +struct hash_map *hashMapInit(size_t size); +bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, + bool *updated); +void hashMapFree(struct hash_map *hash_map); +void hashMapDump(struct hash_map *hash_map); +const char *hashMapGet(const struct hash_map *hash_map, const char *key); +bool hashMapRemove(struct hash_map *hash_map, const char *key); + +#endif /* ! HASH_MAP_H */ diff --git a/minimake/src/main.c b/minimake/src/main.c new file mode 100644 index 0000000..e3abfb9 --- /dev/null +++ b/minimake/src/main.c @@ -0,0 +1,31 @@ +// Error Codes +#define INVALID_ARG 2 + +#include +#include +#include +#include +#include + +// TODO: +// Look at perror for stdlib functions +// Create an enum for error handling + +int handle_args(int argc, char **argv) +{ + int flags = 0; + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-h")) + errx(INVALID_ARG, "-h: not implemented"); + else if (strcmp(argv[i], "-f")) + errx(INVALID_ARG, "-f: not implemented"); + else if (strcmp(argv[i], "-p")) + errx(INVALID_ARG, "-p: not implemented"); + else + errx(INVALID_ARG, ": Pleaase give an argument"); + } +} + +int main(int argc, char **argv) +{} diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c new file mode 100644 index 0000000..3aa5f2e --- /dev/null +++ b/minimake/src/minimake.c @@ -0,0 +1,137 @@ +#define _POSIX_C_SOURCE 200809L + +#define BUFFER_SIZE 1024 +#define STRING_BUFFER_SIZE 32 +#define HASHMAP_SIZE 32 + +#include "minimake.h" +#include "hash_map/hash_map.h" + +#include +#include +#include +#include + +// ==== Parsing ==== + +// Helps to match a string (excludes blanks and special characters) +static int isChar(char c) { + return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; +} + +// Returns the next word from buf until buf_len, +// and the numbers of read characters in *read_chars +// WARNING allocates the result on the heap +static char *readWord(char *buf, size_t buf_len, size_t *read_chars) { + size_t i = 0; + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + while (i < buf_len && isChar(buf[i])) { + // Reallocate more space if necessary + if (i >= str_buf_size - 1) { + str_buf_size += STRING_BUFFER_SIZE; + str_buf = realloc(str_buf, str_buf_size); + if (str_buf == NULL) + errx(2, "Could not realloc"); + } + + str_buf[i] = buf[i]; + i++; + } + + str_buf[i] = '\0'; + *read_chars = i; + + return str_buf; +} + +static int skipBlanks(char *buf, size_t buf_len) { + size_t i = 0; + while (i < buf_len && isblank(buf[i])) + i++; + return i; +} + +// Takes a buffer containing the line to parse and it length +// As well as the line number in the file for error handling +static void parseLine(char *buf, size_t line_number, size_t line_size) { + + size_t i = 0; + + i += skipBlanks(buf + i, line_size - i); + + // Read name + size_t skipped_chars = 0; + char *name = readWord(buf + i, line_size - i, &skipped_chars); + i += skipped_chars; + + i += skipBlanks(buf + i, line_size - i); + + // Definition type + switch (buf[i]) + { + // Variable + case '=': + return; + // Rule + case ':': + return; + default: + errx(2, "Unexpected character '%c' after declaration '%s'", buf[i], name); + + } + if (buf[i] != ':') + i++; + + // Read deps + while (i < line_size) { + + i += skipBlanks(buf + i, line_size - i); + + // Read word + size_t skipped_chars = 0; + char *dep_name = readWord(buf + i, line_size - i, &skipped_chars); + if (skipped_chars != 0) + printf(" %s", dep_name); + free(dep_name); + i += skipped_chars; + + if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') + errx(2, "Unexpected character '%c'", buf[i]); + } + + free(name); +} + +void make_parse(char *path) { + + // Open file + FILE *stream = fopen(path, "r"); + if (stream == 0) + errx(2, "Could not open file: %s", path); + + // Init hash maps + struct hash_map *variables = hashMapInit(HASHMAP_SIZE); + struct hash_map *rules = hashMapInit(HASHMAP_SIZE); + + // Allocate line buffer + size_t buf_size = BUFFER_SIZE; + char *buf = malloc(sizeof(char) * buf_size); + if (buf == NULL) + errx(2, "Could not allocate more memory"); + + // Parse line by line + ssize_t nread; + size_t line_nb = 0; + while ((nread = getline(&buf, &buf_size, stream)) != -1) { + if (nread == -1) + errx(1, "Could not get line %lu", line_nb); + parseLine(buf, line_nb, nread); + } + + free(buf); + fclose(stream); + return; +} + +// ==== Runtime ==== diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h new file mode 100644 index 0000000..2cc08f9 --- /dev/null +++ b/minimake/src/minimake.h @@ -0,0 +1,21 @@ +#ifndef MINIMAKE_H +#define MINIMAKE_H + +// Holds variable information +// WARNING its values must be freed after use +struct variable { + char* name; + char* value; +}; +// Holds rule information +// WARNING its values must be freed after use +struct rule { + char* name; + struct list* dependencies; + struct list* commands; +}; + +int make(char* path, int flags); +void make_parse(char* path); + +#endif // ! MINIMAKE_H From 750bf778468fa219ac1f4ba1f6d22aa6322121cf Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Sat, 25 Oct 2025 14:20:09 +0200 Subject: [PATCH 05/23] ' --- minimake/minimake.c | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 minimake/minimake.c diff --git a/minimake/minimake.c b/minimake/minimake.c deleted file mode 100644 index e3abfb9..0000000 --- a/minimake/minimake.c +++ /dev/null @@ -1,31 +0,0 @@ -// Error Codes -#define INVALID_ARG 2 - -#include -#include -#include -#include -#include - -// TODO: -// Look at perror for stdlib functions -// Create an enum for error handling - -int handle_args(int argc, char **argv) -{ - int flags = 0; - for (int i = 1; i < argc; i++) - { - if (strcmp(argv[i], "-h")) - errx(INVALID_ARG, "-h: not implemented"); - else if (strcmp(argv[i], "-f")) - errx(INVALID_ARG, "-f: not implemented"); - else if (strcmp(argv[i], "-p")) - errx(INVALID_ARG, "-p: not implemented"); - else - errx(INVALID_ARG, ": Pleaase give an argument"); - } -} - -int main(int argc, char **argv) -{} From ad6f81afc0f53a988bac091733b99f4dc6cd0793 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 25 Oct 2025 16:16:07 +0200 Subject: [PATCH 06/23] backup --- minimake/src/list/.gitignore | 1 + minimake/src/list/list.h | 104 ++++++++++ minimake/src/list/list_advanced.c | 101 ++++++++++ minimake/src/list/list_basic.c | 86 ++++++++ minimake/src/list/list_ultimate.c | 138 +++++++++++++ minimake/src/list_void/list.c | 46 +++++ minimake/src/list_void/list.h | 31 +++ minimake/src/minimake.c | 292 +++++++++++++++++++--------- minimake/src/minimake.h | 30 ++- minimake/tests/Makefile.syntax-test | 35 ++++ 10 files changed, 765 insertions(+), 99 deletions(-) create mode 100644 minimake/src/list/.gitignore create mode 100644 minimake/src/list/list.h create mode 100644 minimake/src/list/list_advanced.c create mode 100644 minimake/src/list/list_basic.c create mode 100644 minimake/src/list/list_ultimate.c create mode 100644 minimake/src/list_void/list.c create mode 100644 minimake/src/list_void/list.h create mode 100644 minimake/tests/Makefile.syntax-test diff --git a/minimake/src/list/.gitignore b/minimake/src/list/.gitignore new file mode 100644 index 0000000..3309b20 --- /dev/null +++ b/minimake/src/list/.gitignore @@ -0,0 +1 @@ +list.c diff --git a/minimake/src/list/list.h b/minimake/src/list/list.h new file mode 100644 index 0000000..03a03ca --- /dev/null +++ b/minimake/src/list/list.h @@ -0,0 +1,104 @@ +#ifndef LIST_H +#define LIST_H + +#include + +struct list +{ + int data; + struct list *next; +}; + +/* +** Insert a node containing `value` at the beginning of the list. +** Return `NULL` if an error occured. +*/ +struct list *list_prepend(struct list *list, int value); + +/* +** Return the lenght of the list. +** Return `0` if the list is empty. +*/ +size_t list_length(struct list *list); + +/* +** Display the list contents on `stdout`. +** Nothing is displayed if the list is empty. +*/ +void list_print(struct list *list); + +/* +** Release the memory used by the list. +** Does nothing if `list` is `NULL`. +*/ +void list_destroy(struct list *list); + +/* +** Append a node containing `value` at the end of the list. +** Return `NULL` if an error occured. +*/ +// START PROTO list_append +struct list *list_append(struct list *list, int value); +// END PROTO list_append + +/* +** Insert a node containing `value` at the index `index` in the list. +** If the index is greater than the length of the list, the behaviour is the +** same as `list_append`. +** Return `NULL` if an error occured. +*/ +// START PROTO list_insert +struct list *list_insert(struct list *list, int value, size_t index); +// END PROTO list_insert + +/* +** Remove the element at the index `index`. +** Return `NULL` if an error occured. +*/ +// START PROTO list_remove +struct list *list_remove(struct list *list, size_t index); +// END PROTO list_remove + +/* +** Return the position of the first node containing `value`. +** Return `-1` if nothing is found. +*/ +// START PROTO list_find +int list_find(struct list *list, int value); +// END PROTO list_find + +/* +** Concatenate the list `list2` at the end of the list `list`. +** Return `list2` if `list` is `NULL`. +*/ +// START PROTO list_concat +struct list *list_concat(struct list *list, struct list *list2); +// END PROTO list_concat + +/* +** Sort the elements of the list in ascending order. +** Return the new list. +*/ +// START PROTO list_sort +struct list *list_sort(struct list *list); +// END PROTO list_sort + +/* +** Invert the order of the elements of the list. +** Return the new list. +*/ +// START PROTO list_reverse +struct list *list_reverse(struct list *list); +// END PROTO list_reverse + +/* +** Split the list at index `index`. +** First part goes in `list` and contains the element at `index`. +** Second part is returned. +** Return `NULL` if `list` is `NULL` or `index` is invalid. +*/ +// START PROTO list_split +struct list *list_split(struct list *list, size_t index); +// END PROTO list_split + +#endif /* ! LIST_H */ diff --git a/minimake/src/list/list_advanced.c b/minimake/src/list/list_advanced.c new file mode 100644 index 0000000..75b401a --- /dev/null +++ b/minimake/src/list/list_advanced.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include "list.h" + +struct list *list_insert(struct list *list, int value, size_t index) +{ + if (list == NULL || index == 0) + { + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = list; + return new_elt; + } + + struct list *elt = list; + + for (size_t i = 0; i < index - 1; i++) + { + if (elt->next == NULL) + { + break; + } + elt = elt->next; + } + + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = elt->next; + elt->next = new_elt; + + return list; +} + +struct list *list_remove(struct list *list, size_t index) +{ + struct list *elt = list; + struct list *prev_elt; + + if (index == 0) + { + struct list *res = elt->next; + free(elt); + return res; + } + + for (size_t i = 0; i < index; i++) + { + if (elt == NULL) + { + return list; + } + prev_elt = elt; + elt = elt->next; + } + if (elt == NULL) + { + return list; + } + + prev_elt->next = elt->next; + free(elt); + + return list; +} + +int list_find(struct list *list, int value) +{ + if (list == NULL) + { + return -1; + } + + int res = 0; + while (list->data != value) + { + list = list->next; + res++; + if (list == NULL) + { + return -1; + } + } + return res; +} + +struct list *list_concat(struct list *list, struct list *list2) +{ + if (list == NULL) + { + return list2; + } + struct list *elt = list; + while (elt->next != NULL) + { + elt = elt->next; + } + elt->next = list2; + return list; +} diff --git a/minimake/src/list/list_basic.c b/minimake/src/list/list_basic.c new file mode 100644 index 0000000..094924b --- /dev/null +++ b/minimake/src/list/list_basic.c @@ -0,0 +1,86 @@ +#include +#include + +#include "list.h" + +struct list *list_prepend(struct list *list, int value) +{ + struct list *new_elt = malloc(sizeof(struct list)); + if (new_elt == NULL) + { + return NULL; + } + new_elt->next = list; + new_elt->data = value; + + return new_elt; +} + +size_t list_length(struct list *list) +{ + size_t len = 0; + while (list != NULL) + { + len++; + list = list->next; + } + return len; +} + +void list_print(struct list *list) +{ + if (list == NULL) + { + return; + } + + while (list != NULL) + { + if (list->next != NULL) + { + printf("%d ", list->data); + } + else + { + printf("%d\n", list->data); + } + list = list->next; + } +} + +void list_destroy(struct list *list) +{ + struct list *elt = list; + struct list *next_elt; + while (elt != NULL) + { + next_elt = elt->next; + free(elt); + elt = next_elt; + } +} + +struct list *list_append(struct list *list, int value) +{ + if (list == NULL) + { + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = NULL; + return new_elt; + } + + struct list *elt = list; + + while (elt->next != NULL) + { + elt = elt->next; + } + + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = NULL; + elt->next = new_elt; + + return list; +} diff --git a/minimake/src/list/list_ultimate.c b/minimake/src/list/list_ultimate.c new file mode 100644 index 0000000..6207398 --- /dev/null +++ b/minimake/src/list/list_ultimate.c @@ -0,0 +1,138 @@ +#include +#include + +#include "list.h" + +void swap_next(struct list *elt) +{ + int c = elt->next->data; + elt->next->data = elt->data; + elt->data = c; +} +struct list *list_sort(struct list *list) +{ + // Bubble sort go ! + if (list == NULL) + { + return list; + } + struct list *elt = list; + int len = 0; + while (elt->next != NULL) + { + if (elt->data > elt->next->data) + { + swap_next(elt); + } + elt = elt->next; + len++; + } + + for (int i = 1; i < len; i++) + { + elt = list; + while (elt->next != NULL) + { + if (elt->data > elt->next->data) + { + swap_next(elt); + } + elt = elt->next; + } + } + + return list; +} + +// Old proto +// WARNING no malloc/free allowed (moulinette issue) +struct list *list_reverse(struct list *list) +{ + if (list == NULL) + { + return list; + } + + // Get len + struct list *elt = list; + int len = 0; + while (elt->next != NULL) + { + len++; + elt = elt->next; + } + elt = list; + + // Bring each elt to end + for (int i = 0; i < len; i++) + { + elt = list; + for (int j = 0; j < len - i; j++) + { + swap_next(elt); + elt = elt->next; + } + } + + return list; +} + +// Doesn't work neither +// struct list *list_reverse(struct list *list) +// { +// struct list *new_list = NULL; +// struct list *elt = list; +// while (elt != NULL) +// { +// struct list *new_elt = malloc(sizeof(struct list)); +// if (new_elt == NULL) +// { +// return NULL; +// } +// new_elt->data = elt->data; +// new_elt->next = new_list; + +// struct list *next_elt = elt->next; +// free(elt); +// elt = next_elt; +// } +// return new_list; +// } + +// Moulinette issue +// struct list *list_reverse(struct list *list) +// { +// if (list == NULL) +// { +// return list; +// } + +// struct list *new_list = NULL; +// while (list != NULL) +// { +// new_list = list_prepend(new_list, list->data); +// list = list_remove(list, 0); +// } + +// return new_list; +// } + +struct list *list_split(struct list *list, size_t index) +{ + struct list *elt = list; + for (size_t i = 0; i < index; i++) + { + if (elt == NULL) + { + return NULL; + } + elt = elt->next; + } + if (elt == NULL) + { + return NULL; + } + struct list *res = elt->next; + elt->next = NULL; + return res; +} diff --git a/minimake/src/list_void/list.c b/minimake/src/list_void/list.c new file mode 100644 index 0000000..24b462e --- /dev/null +++ b/minimake/src/list_void/list.c @@ -0,0 +1,46 @@ +#include "list.h" + +#include +#include + +struct list *list_prepend(struct list *list, const void *value, + size_t data_size) +{ + struct list *new_node = malloc(sizeof(struct list)); + if (new_node == NULL) + { + return NULL; + } + void *node_data = malloc(data_size); + if (node_data == NULL) + { + return NULL; + } + new_node->data = node_data; + memcpy(node_data, value, data_size); + new_node->next = list; + return new_node; +} + +size_t list_length(struct list *list) +{ + size_t res = 0; + while (list != NULL) + { + list = list->next; + res++; + } + return res; +} + +void list_destroy(struct list *list) +{ + struct list *next; + while (list != NULL) + { + next = list->next; + free(list->data); + free(list); + list = next; + } +} diff --git a/minimake/src/list_void/list.h b/minimake/src/list_void/list.h new file mode 100644 index 0000000..b129adc --- /dev/null +++ b/minimake/src/list_void/list.h @@ -0,0 +1,31 @@ +#ifndef LIST_H +#define LIST_H + +#include + +struct list +{ + void *data; + struct list *next; +}; + +/* +** Insert a node containing `value` at the beginning of the list. +** Return `NULL` if an error occurred. +*/ +struct list *list_prepend(struct list *list, const void *value, + size_t data_size); + +/* +** Return the length of the list. +** Return `0` if the list is empty. +*/ +size_t list_length(struct list *list); + +/* +** Release the memory used by the list. +** Does nothing if `list` is `NULL`. +*/ +void list_destroy(struct list *list); + +#endif /* ! LIST_H */ diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 3aa5f2e..8db5234 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -1,137 +1,247 @@ +#include "list/list.h" #define _POSIX_C_SOURCE 200809L +// Default values #define BUFFER_SIZE 1024 #define STRING_BUFFER_SIZE 32 #define HASHMAP_SIZE 32 -#include "minimake.h" -#include "hash_map/hash_map.h" - #include #include #include #include +#include "hash_map/hash_map.h" +#include "minimake.h" + +// Static variables +struct hash_map *variables = NULL; +struct hash_map *rules = NULL; + // ==== Parsing ==== // Helps to match a string (excludes blanks and special characters) -static int isChar(char c) { - return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; +static int isChar(char c) +{ + return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; } // Returns the next word from buf until buf_len, // and the numbers of read characters in *read_chars // WARNING allocates the result on the heap -static char *readWord(char *buf, size_t buf_len, size_t *read_chars) { - size_t i = 0; - size_t str_buf_size = STRING_BUFFER_SIZE; - char *str_buf = malloc(sizeof(char) * str_buf_size); - while (i < buf_len && isChar(buf[i])) { - // Reallocate more space if necessary - if (i >= str_buf_size - 1) { - str_buf_size += STRING_BUFFER_SIZE; - str_buf = realloc(str_buf, str_buf_size); - if (str_buf == NULL) - errx(2, "Could not realloc"); +static char *readWord(char *buf, size_t buf_len, size_t *read_chars) +{ + size_t i = 0; + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + while (i < buf_len && isChar(buf[i])) + { + // Reallocate more space if necessary + if (i >= str_buf_size - 1) + { + str_buf_size += STRING_BUFFER_SIZE; + str_buf = realloc(str_buf, str_buf_size); + if (str_buf == NULL) + errx(2, "Could not realloc"); + } + + str_buf[i] = buf[i]; + i++; } - str_buf[i] = buf[i]; - i++; - } + str_buf[i] = '\0'; + *read_chars = i; - str_buf[i] = '\0'; - *read_chars = i; - - return str_buf; + return str_buf; } -static int skipBlanks(char *buf, size_t buf_len) { - size_t i = 0; - while (i < buf_len && isblank(buf[i])) - i++; - return i; +static int skipBlanks(char *buf, size_t buf_len) +{ + size_t i = 0; + while (i < buf_len && isblank(buf[i])) + i++; + return i; +} + +// Registers a new variable and returns its pointer +// WARNING Allocates memory on the heap, +// the variables hashmap should be freed before exit +static struct variable *createVariable(char *name) +{ + struct variable *res = malloc(sizeof(struct variable)); + res->name = name; + res->value = NULL; + + int err = hashMapInsert(variables, name, NULL, NULL); + if (!err) + errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", + name); + + return res; +} + +// Registers a new rule and returns its pointer +// WARNING Allocates memory on the heap, +// the rules hashmap should be freed before exit +static struct rule *createRule(char *name) +{ + struct rule *res = malloc(sizeof(struct rule)); + res->name = name; + res->dependencies = NULL; + res->recipe = NULL; + + int err = hashMapInsert(variables, name, NULL, NULL); + if (!err) + errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", + name); + + return res; +} + +// Parse dependencies from buf and returns them inside a chained list +static struct list *readDependencies(char *buf, size_t buf_size) +{ + size_t i = 0; + struct list *res = NULL; + while (i < buf_size) + { + i += skipBlanks(buf + i, buf_size - i); + + // Read word + size_t skipped_chars = 0; + char *dep_name = readWord(buf + i, buf_size - i, &skipped_chars); + if (skipped_chars != 0) + // Add to list + res = list_append(res, dep_name); + i += skipped_chars; + + // TODO handle comments here + + if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') + errx(2, "Unexpected character '%c'", buf[i]); + } + + return res; +} + +static int isBlankLine(struct line *l) +{ + size_t line_size = l->length; + char *buf = l->buffer; + + size_t i = 0; + while (i < line_size) + { + if (!isblank(buf[i])) + return 0; + if (buf[i] == '#') // Comment + return 1; + } + return 1; +} + +static struct list *readRecipe() +{ + // Getline + // Skip blank lines and comments + // } // Takes a buffer containing the line to parse and it length // As well as the line number in the file for error handling -static void parseLine(char *buf, size_t line_number, size_t line_size) { +static void parseLine(struct line *current_line) +{ + char *buf = current_line->buffer; + size_t line_size = current_line->length; - size_t i = 0; - - i += skipBlanks(buf + i, line_size - i); - - // Read name - size_t skipped_chars = 0; - char *name = readWord(buf + i, line_size - i, &skipped_chars); - i += skipped_chars; - - i += skipBlanks(buf + i, line_size - i); - - // Definition type - switch (buf[i]) - { - // Variable - case '=': - return; - // Rule - case ':': - return; - default: - errx(2, "Unexpected character '%c' after declaration '%s'", buf[i], name); - - } - if (buf[i] != ':') - i++; - - // Read deps - while (i < line_size) { + size_t i = 0; i += skipBlanks(buf + i, line_size - i); - // Read word + // Read name size_t skipped_chars = 0; - char *dep_name = readWord(buf + i, line_size - i, &skipped_chars); - if (skipped_chars != 0) - printf(" %s", dep_name); - free(dep_name); + char *name = readWord(buf + i, line_size - i, &skipped_chars); i += skipped_chars; - if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') - errx(2, "Unexpected character '%c'", buf[i]); - } + i += skipBlanks(buf + i, line_size - i); - free(name); + // Potential elements + struct rule *new_rule; + struct variable *new_variable; + + // Definition type + switch (buf[i]) + { + // Variable + case '=': + new_variable = createVariable(name); + // Read value + break; + + // Rule + case ':': + new_rule = createRule(name); + // Read dependencies + // Read recipe + break; + + // Blank line + case '\0': + case '#': + if (name != NULL) + errx(2, + "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); + else + break; + + default: + errx(2, "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); + } + + free(name); } -void make_parse(char *path) { +void makeParse(char *path) +{ + // Open file + FILE *stream = fopen(path, "r"); + if (stream == 0) + errx(2, "Could not open file: %s", path); - // Open file - FILE *stream = fopen(path, "r"); - if (stream == 0) - errx(2, "Could not open file: %s", path); + // Init hash maps + variables = hashMapInit(HASHMAP_SIZE); + rules = hashMapInit(HASHMAP_SIZE); + if (variables == NULL || rules == NULL) + errx(1, "Internal error: Failed to initiate hash maps"); - // Init hash maps - struct hash_map *variables = hashMapInit(HASHMAP_SIZE); - struct hash_map *rules = hashMapInit(HASHMAP_SIZE); + // Allocate line buffer + size_t buf_size = BUFFER_SIZE; + char *buf = malloc(sizeof(char) * buf_size); + if (buf == NULL) + errx(2, "Could not allocate more memory"); - // Allocate line buffer - size_t buf_size = BUFFER_SIZE; - char *buf = malloc(sizeof(char) * buf_size); - if (buf == NULL) - errx(2, "Could not allocate more memory"); + // Parse line by line + ssize_t nread; + struct line current_line; + current_line.number = 1; + while ((nread = getline(&buf, &buf_size, stream)) != -1) + { + if (nread == -1) + errx(1, "Could not get line %lu", current_line.number); - // Parse line by line - ssize_t nread; - size_t line_nb = 0; - while ((nread = getline(&buf, &buf_size, stream)) != -1) { - if (nread == -1) - errx(1, "Could not get line %lu", line_nb); - parseLine(buf, line_nb, nread); - } + current_line.buffer = buf; + current_line.length = nread; - free(buf); - fclose(stream); - return; + parseLine(¤t_line); + + current_line.number += 1; + } + + free(buf); + fclose(stream); + return; } // ==== Runtime ==== diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index 2cc08f9..07a560e 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -1,21 +1,35 @@ #ifndef MINIMAKE_H #define MINIMAKE_H +#include "list/list.h" + // Holds variable information // WARNING its values must be freed after use -struct variable { - char* name; - char* value; +struct variable +{ + char *name; + char *value; }; + // Holds rule information // WARNING its values must be freed after use -struct rule { +struct rule +{ char* name; - struct list* dependencies; - struct list* commands; + struct list *dependencies; + struct list *recipe; }; -int make(char* path, int flags); -void make_parse(char* path); +// Holds line information +// Exists only because of EPITA's annoying 4 parameters limit +// WARNING buffer must be freed after use +struct line +{ + char* buffer; + size_t number; + size_t length; +}; + +int make(char *path, int flags); #endif // ! MINIMAKE_H diff --git a/minimake/tests/Makefile.syntax-test b/minimake/tests/Makefile.syntax-test new file mode 100644 index 0000000..fff0427 --- /dev/null +++ b/minimake/tests/Makefile.syntax-test @@ -0,0 +1,35 @@ +SIMPLE_VAR = coucou +SIMPLE_VAR_COMMENT = the comment is gone # comment + +# the following line starts with a space then a tab + SPACES_BEFORE_TAB = var_beginning var_end + +sparse_rule: depa depb + + command 1 + + command 2 + + B = B_var_beginning B_var_end + +packed_rule: depa depb + command 1 + command 2 + +silent_rule: depa depb + @ command 1 + @command 2 + +rule_comment: depa depb # comment + +command_space_rule: depa depb + echo spaces before + echo spaces after + echo this is a # comment + +simple_rule: simple_dep + +no_dep_rule: + +variable_rule: beginning $(SIMPLE_VAR) end + echo "shouldn't be expanded: $(SIMPLE_VAR)" From e106a4ca663d3e7493871c47063a529158ce00f4 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 25 Oct 2025 21:56:43 +0200 Subject: [PATCH 07/23] backup --- minimake/src/hash_map/hash.c | 27 --- minimake/src/hash_map/hash_map.c | 277 +++++++++++++++++------------- minimake/src/lines/lines.c | 68 ++++++++ minimake/src/lines/lines.h | 25 +++ minimake/src/list/list.h | 10 +- minimake/src/list/list_advanced.c | 4 +- minimake/src/list/list_basic.c | 42 ++--- minimake/src/list/list_ultimate.c | 2 +- minimake/src/list_void/list.c | 46 ----- minimake/src/list_void/list.h | 31 ---- minimake/src/minimake.c | 136 ++++++++------- minimake/src/minimake.h | 15 +- 12 files changed, 355 insertions(+), 328 deletions(-) delete mode 100644 minimake/src/hash_map/hash.c create mode 100644 minimake/src/lines/lines.c create mode 100644 minimake/src/lines/lines.h delete mode 100644 minimake/src/list_void/list.c delete mode 100644 minimake/src/list_void/list.h diff --git a/minimake/src/hash_map/hash.c b/minimake/src/hash_map/hash.c deleted file mode 100644 index 247893b..0000000 --- a/minimake/src/hash_map/hash.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include - -#include "hash_map.h" - -/* -** Hash the key using FNV-1a 32 bits hash algorithm. -*/ -size_t hash(const char *key) -{ - if (!key) - return 0; - - uint32_t hash = 2166136261; // FNV offset basis - uint32_t prime = 16777619; // FNV prime - - while (*key) - { - hash ^= *key; - hash *= prime; - key++; - } - - return hash; -} diff --git a/minimake/src/hash_map/hash_map.c b/minimake/src/hash_map/hash_map.c index 5c57115..d1609d0 100644 --- a/minimake/src/hash_map/hash_map.c +++ b/minimake/src/hash_map/hash_map.c @@ -1,133 +1,172 @@ #include "hash_map.h" #include +#include #include #include #include -struct hash_map *hashMapInit(size_t size) { - struct pair_list **data = calloc(size, sizeof(struct pair_list)); - struct hash_map *map = malloc(sizeof(struct hash_map)); - map->data = data; - map->size = size; - return map; +/* +** Hash the key using FNV-1a 32 bits hash algorithm. +*/ +size_t hash(const char *key) +{ + if (!key) + return 0; + + uint32_t hash = 2166136261; // FNV offset basis + uint32_t prime = 16777619; // FNV prime + + while (*key) + { + hash ^= *key; + hash *= prime; + key++; + } + + return hash; +} + +struct hash_map *hashMapInit(size_t size) +{ + struct pair_list **data = calloc(size, sizeof(struct pair_list)); + struct hash_map *map = malloc(sizeof(struct hash_map)); + map->data = data; + map->size = size; + return map; } bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, - bool *updated) { - if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) { + bool *updated) +{ + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + { + if (updated) + *updated = false; + return false; + } + + // Insert into hashmap (head) + + size_t entry_hash = hash(key) % hash_map->size; + // Search if key is already present + struct pair_list *elt = hash_map->data[entry_hash]; + while (elt != NULL) + { + if (strcmp(elt->key, key) == 0) + { + elt->value = value; + if (updated) + *updated = true; + return true; + } + elt = elt->next; + } + + // Create entry + struct pair_list *new_entry = malloc(sizeof(struct pair_list)); + if (new_entry == NULL) + return false; + new_entry->key = key; + new_entry->value = value; + + new_entry->next = hash_map->data[entry_hash]; + hash_map->data[entry_hash] = new_entry; + if (updated) - *updated = false; - return false; - } + *updated = false; - // Insert into hashmap (head) - - size_t entry_hash = hash(key) % hash_map->size; - // Search if key is already present - struct pair_list *elt = hash_map->data[entry_hash]; - while (elt != NULL) { - if (strcmp(elt->key, key) == 0) { - elt->value = value; - if (updated) - *updated = true; - return true; - } - elt = elt->next; - } - - // Create entry - struct pair_list *new_entry = malloc(sizeof(struct pair_list)); - if (new_entry == NULL) - return false; - new_entry->key = key; - new_entry->value = value; - - new_entry->next = hash_map->data[entry_hash]; - hash_map->data[entry_hash] = new_entry; - - if (updated) - *updated = false; - - return true; -} - -void hashMapFree(struct hash_map *hash_map) { - if (hash_map == NULL) - return; - if (hash_map->data == NULL) - return; - - for (size_t i = 0; i < hash_map->size; i++) { - struct pair_list *entry = hash_map->data[i]; - while (entry != NULL) { - struct pair_list *next = entry->next; - free(entry); - entry = next; - } - } - free(hash_map->data); - free(hash_map); -} - -void hashMapDump(struct hash_map *hash_map) { - for (size_t i = 0; i < hash_map->size; i++) { - struct pair_list *entry = hash_map->data[i]; - bool is_null = true; - if (entry != NULL) { - is_null = false; - printf("%s: %s", entry->key, entry->value); - entry = entry->next; - } - while (entry != NULL) { - printf(", %s: %s", entry->key, entry->value); - entry = entry->next; - } - if (!is_null) - putchar('\n'); - } -} - -const char *hashMapGet(const struct hash_map *hash_map, const char *key) { - if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) - return NULL; - - size_t entry_hash = hash(key) % hash_map->size; - struct pair_list *entry = hash_map->data[entry_hash]; - while (entry != NULL && strcmp(entry->key, key) != 0) { - entry = entry->next; - } - if (entry == NULL) - return NULL; - - return entry->value; -} - -bool hashMapRemove(struct hash_map *hash_map, const char *key) { - if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) - return false; - - size_t entry_hash = hash(key) % hash_map->size; - struct pair_list *entry = hash_map->data[entry_hash]; - - if (entry == NULL) - return false; - if (strcmp(entry->key, key) == 0) { - hash_map->data[entry_hash] = entry->next; - free(entry); return true; - } - - if (entry->next == NULL) - return false; - while (strcmp(entry->next->key, key) != 0) { - entry = entry->next; - if (entry->next == NULL) - return false; - } - - struct pair_list *elt_to_free = entry->next; - entry->next = entry->next->next; - free(elt_to_free); - return true; +} + +void hashMapFree(struct hash_map *hash_map) +{ + if (hash_map == NULL) + return; + if (hash_map->data == NULL) + return; + + for (size_t i = 0; i < hash_map->size; i++) + { + struct pair_list *entry = hash_map->data[i]; + while (entry != NULL) + { + struct pair_list *next = entry->next; + free(entry); + entry = next; + } + } + free(hash_map->data); + free(hash_map); +} + +void hashMapDump(struct hash_map *hash_map) +{ + for (size_t i = 0; i < hash_map->size; i++) + { + struct pair_list *entry = hash_map->data[i]; + bool is_null = true; + if (entry != NULL) + { + is_null = false; + printf("%s: %s", entry->key, entry->value); + entry = entry->next; + } + while (entry != NULL) + { + printf(", %s: %s", entry->key, entry->value); + entry = entry->next; + } + if (!is_null) + putchar('\n'); + } +} + +const char *hashMapGet(const struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) + return NULL; + + size_t entry_hash = hash(key) % hash_map->size; + struct pair_list *entry = hash_map->data[entry_hash]; + while (entry != NULL && strcmp(entry->key, key) != 0) + { + entry = entry->next; + } + if (entry == NULL) + return NULL; + + return entry->value; +} + +bool hashMapRemove(struct hash_map *hash_map, const char *key) +{ + if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) + return false; + + size_t entry_hash = hash(key) % hash_map->size; + struct pair_list *entry = hash_map->data[entry_hash]; + + if (entry == NULL) + return false; + if (strcmp(entry->key, key) == 0) + { + hash_map->data[entry_hash] = entry->next; + free(entry); + return true; + } + + if (entry->next == NULL) + return false; + while (strcmp(entry->next->key, key) != 0) + { + entry = entry->next; + if (entry->next == NULL) + return false; + } + + struct pair_list *elt_to_free = entry->next; + entry->next = entry->next->next; + free(elt_to_free); + return true; } diff --git a/minimake/src/lines/lines.c b/minimake/src/lines/lines.c new file mode 100644 index 0000000..4201eea --- /dev/null +++ b/minimake/src/lines/lines.c @@ -0,0 +1,68 @@ +#include "lines.h" + +#include +#include +#include +#include +#include + +// Helps to match a string (excludes blanks and special characters) +int isChar(char c) +{ + return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; +} + +int skipBlanks(char *buf, size_t buf_len) +{ + size_t i = 0; + while (i < buf_len && isblank(buf[i])) + i++; + return i; +} + +// Returns 1 if line is blank +int isBlankLine(struct line *l) +{ + size_t line_size = l->length; + char *buf = l->buffer; + + size_t i = 0; + while (i < line_size) + { + if (!isblank(buf[i])) + return 0; + if (buf[i] == '#') // Comments + return 1; + i++; + } + return 1; +} + +// Returns the next word from buf until buf_len, +// and the numbers of read characters in *read_chars +// WARNING allocates the result on the heap +char *readWord(char *buf, size_t buf_len, size_t *read_chars) +{ + size_t i = 0; + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + while (i < buf_len && isChar(buf[i])) + { + // Reallocate more space if necessary + if (i >= str_buf_size - 1) + { + str_buf_size += STRING_BUFFER_SIZE; + str_buf = realloc(str_buf, str_buf_size); + if (str_buf == NULL) + errx(2, "Could not realloc"); + } + + str_buf[i] = buf[i]; + i++; + } + + str_buf[i] = '\0'; + *read_chars = i; + + return str_buf; +} diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h new file mode 100644 index 0000000..1eed08c --- /dev/null +++ b/minimake/src/lines/lines.h @@ -0,0 +1,25 @@ +#ifndef LINES_H +#define LINES_H + +#define STRING_BUFFER_SIZE 32 + +#include +#include + +// Holds line information +// Exists only because of EPITA's annoying 4 parameters limit +// WARNING buffer must be freed after use +struct line +{ + char* buffer; // Line content + size_t length; // Line length + size_t number; // Line number in file + FILE* file_stream; // Full file stream +}; + +int isChar(char c); +int isBlankLine(struct line *l); +int skipBlanks(char *buf, size_t buf_len); +char *readWord(char *buf, size_t buf_len, size_t *read_chars); + +#endif // LINES_H diff --git a/minimake/src/list/list.h b/minimake/src/list/list.h index 03a03ca..a8f9b10 100644 --- a/minimake/src/list/list.h +++ b/minimake/src/list/list.h @@ -5,7 +5,7 @@ struct list { - int data; + void* data; struct list *next; }; @@ -13,7 +13,7 @@ struct list ** Insert a node containing `value` at the beginning of the list. ** Return `NULL` if an error occured. */ -struct list *list_prepend(struct list *list, int value); +struct list *list_prepend(struct list *list, void* value); /* ** Return the lenght of the list. @@ -38,7 +38,7 @@ void list_destroy(struct list *list); ** Return `NULL` if an error occured. */ // START PROTO list_append -struct list *list_append(struct list *list, int value); +struct list *list_append(struct list *list, void* value); // END PROTO list_append /* @@ -48,7 +48,7 @@ struct list *list_append(struct list *list, int value); ** Return `NULL` if an error occured. */ // START PROTO list_insert -struct list *list_insert(struct list *list, int value, size_t index); +struct list *list_insert(struct list *list, void* value, size_t index); // END PROTO list_insert /* @@ -64,7 +64,7 @@ struct list *list_remove(struct list *list, size_t index); ** Return `-1` if nothing is found. */ // START PROTO list_find -int list_find(struct list *list, int value); +int list_find(struct list *list, void* value); // END PROTO list_find /* diff --git a/minimake/src/list/list_advanced.c b/minimake/src/list/list_advanced.c index 75b401a..78402d1 100644 --- a/minimake/src/list/list_advanced.c +++ b/minimake/src/list/list_advanced.c @@ -4,7 +4,7 @@ #include "list.h" -struct list *list_insert(struct list *list, int value, size_t index) +struct list *list_insert(struct list *list, void *value, size_t index) { if (list == NULL || index == 0) { @@ -65,7 +65,7 @@ struct list *list_remove(struct list *list, size_t index) return list; } -int list_find(struct list *list, int value) +int list_find(struct list *list, void *value) { if (list == NULL) { diff --git a/minimake/src/list/list_basic.c b/minimake/src/list/list_basic.c index 094924b..a0672bb 100644 --- a/minimake/src/list/list_basic.c +++ b/minimake/src/list/list_basic.c @@ -3,7 +3,7 @@ #include "list.h" -struct list *list_prepend(struct list *list, int value) +struct list *list_prepend(struct list *list, void *value) { struct list *new_elt = malloc(sizeof(struct list)); if (new_elt == NULL) @@ -27,26 +27,26 @@ size_t list_length(struct list *list) return len; } -void list_print(struct list *list) -{ - if (list == NULL) - { - return; - } +// void list_print(struct list *list) +// { +// if (list == NULL) +// { +// return; +// } - while (list != NULL) - { - if (list->next != NULL) - { - printf("%d ", list->data); - } - else - { - printf("%d\n", list->data); - } - list = list->next; - } -} +// while (list != NULL) +// { +// if (list->next != NULL) +// { +// printf("%p ", list->data); +// } +// else +// { +// printf("%p\n", list->data); +// } +// list = list->next; +// } +// } void list_destroy(struct list *list) { @@ -60,7 +60,7 @@ void list_destroy(struct list *list) } } -struct list *list_append(struct list *list, int value) +struct list *list_append(struct list *list, void *value) { if (list == NULL) { diff --git a/minimake/src/list/list_ultimate.c b/minimake/src/list/list_ultimate.c index 6207398..d4a57f3 100644 --- a/minimake/src/list/list_ultimate.c +++ b/minimake/src/list/list_ultimate.c @@ -5,7 +5,7 @@ void swap_next(struct list *elt) { - int c = elt->next->data; + void *c = elt->next->data; elt->next->data = elt->data; elt->data = c; } diff --git a/minimake/src/list_void/list.c b/minimake/src/list_void/list.c deleted file mode 100644 index 24b462e..0000000 --- a/minimake/src/list_void/list.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "list.h" - -#include -#include - -struct list *list_prepend(struct list *list, const void *value, - size_t data_size) -{ - struct list *new_node = malloc(sizeof(struct list)); - if (new_node == NULL) - { - return NULL; - } - void *node_data = malloc(data_size); - if (node_data == NULL) - { - return NULL; - } - new_node->data = node_data; - memcpy(node_data, value, data_size); - new_node->next = list; - return new_node; -} - -size_t list_length(struct list *list) -{ - size_t res = 0; - while (list != NULL) - { - list = list->next; - res++; - } - return res; -} - -void list_destroy(struct list *list) -{ - struct list *next; - while (list != NULL) - { - next = list->next; - free(list->data); - free(list); - list = next; - } -} diff --git a/minimake/src/list_void/list.h b/minimake/src/list_void/list.h deleted file mode 100644 index b129adc..0000000 --- a/minimake/src/list_void/list.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef LIST_H -#define LIST_H - -#include - -struct list -{ - void *data; - struct list *next; -}; - -/* -** Insert a node containing `value` at the beginning of the list. -** Return `NULL` if an error occurred. -*/ -struct list *list_prepend(struct list *list, const void *value, - size_t data_size); - -/* -** Return the length of the list. -** Return `0` if the list is empty. -*/ -size_t list_length(struct list *list); - -/* -** Release the memory used by the list. -** Does nothing if `list` is `NULL`. -*/ -void list_destroy(struct list *list); - -#endif /* ! LIST_H */ diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 8db5234..e922791 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -1,18 +1,16 @@ -#include "list/list.h" #define _POSIX_C_SOURCE 200809L -// Default values -#define BUFFER_SIZE 1024 -#define STRING_BUFFER_SIZE 32 -#define HASHMAP_SIZE 32 +#include "minimake.h" #include #include #include #include +#include #include "hash_map/hash_map.h" -#include "minimake.h" +#include "lines/lines.h" +#include "list/list.h" // Static variables struct hash_map *variables = NULL; @@ -20,49 +18,6 @@ struct hash_map *rules = NULL; // ==== Parsing ==== -// Helps to match a string (excludes blanks and special characters) -static int isChar(char c) -{ - return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; -} - -// Returns the next word from buf until buf_len, -// and the numbers of read characters in *read_chars -// WARNING allocates the result on the heap -static char *readWord(char *buf, size_t buf_len, size_t *read_chars) -{ - size_t i = 0; - size_t str_buf_size = STRING_BUFFER_SIZE; - char *str_buf = malloc(sizeof(char) * str_buf_size); - while (i < buf_len && isChar(buf[i])) - { - // Reallocate more space if necessary - if (i >= str_buf_size - 1) - { - str_buf_size += STRING_BUFFER_SIZE; - str_buf = realloc(str_buf, str_buf_size); - if (str_buf == NULL) - errx(2, "Could not realloc"); - } - - str_buf[i] = buf[i]; - i++; - } - - str_buf[i] = '\0'; - *read_chars = i; - - return str_buf; -} - -static int skipBlanks(char *buf, size_t buf_len) -{ - size_t i = 0; - while (i < buf_len && isblank(buf[i])) - i++; - return i; -} - // Registers a new variable and returns its pointer // WARNING Allocates memory on the heap, // the variables hashmap should be freed before exit @@ -115,8 +70,11 @@ static struct list *readDependencies(char *buf, size_t buf_size) res = list_append(res, dep_name); i += skipped_chars; - // TODO handle comments here + // Comments + if (buf[i] == '#') + return res; + // Unknown chars if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') errx(2, "Unexpected character '%c'", buf[i]); } @@ -124,27 +82,70 @@ static struct list *readDependencies(char *buf, size_t buf_size) return res; } -static int isBlankLine(struct line *l) +// Searches the following lines for recipes and returns them in the form of a +// list +// WARNING begins to read the following line +static struct list *readRecipe(struct line *l) { - size_t line_size = l->length; + FILE *stream = l->file_stream; char *buf = l->buffer; + size_t buf_size = BUFFER_SIZE; - size_t i = 0; - while (i < line_size) + struct list *res = NULL; + + // Getline + while ((l->length = getline(&buf, &buf_size, stream))) { - if (!isblank(buf[i])) - return 0; - if (buf[i] == '#') // Comment - return 1; + l->number++; + + // Skip blank lines and comments + if (isBlankLine(l)) + continue; + else if (buf[0] != '\t') // Not a recipe + { + l->buffer = buf; // Update buffer ! + return res; + } + else // Add recipe to list + { + char *command = strdup(buf + 1); + if (command == NULL) + errx(1, "Internal error: couldn't duplicate string (%lu:1)", + l->number); + + res = list_append(res, command); + } } - return 1; + + l->buffer = buf; + return res; } -static struct list *readRecipe() +// Reads the value after a variable declaration +static char *readValue(char *buf, size_t buf_size) { - // Getline - // Skip blank lines and comments - // + size_t i = 0; + size_t str_buf_size = STRING_BUFFER_SIZE; + char *str_buf = malloc(sizeof(char) * str_buf_size); + + while (i < buf_size && buf[i] != '\0' && buf[i] != '#') + { + // Reallocate more space if necessary + if (i >= str_buf_size - 1) + { + str_buf_size += STRING_BUFFER_SIZE; + str_buf = realloc(str_buf, str_buf_size); + if (str_buf == NULL) + errx(2, "Could not realloc"); + } + + str_buf[i] = buf[i]; + i++; + } + + str_buf[i] = '\0'; + + return str_buf; } // Takes a buffer containing the line to parse and it length @@ -175,14 +176,16 @@ static void parseLine(struct line *current_line) // Variable case '=': new_variable = createVariable(name); - // Read value + new_variable->value = readValue(buf + i, line_size); break; // Rule case ':': new_rule = createRule(name); - // Read dependencies - // Read recipe + new_rule->dependencies = readDependencies(buf + i, line_size); + new_rule->recipe = readRecipe(current_line); + parseLine(current_line); + // TODO: check for loooooops break; // Blank line @@ -226,6 +229,7 @@ void makeParse(char *path) ssize_t nread; struct line current_line; current_line.number = 1; + current_line.file_stream = stream; while ((nread = getline(&buf, &buf_size, stream)) != -1) { if (nread == -1) diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index 07a560e..b04155e 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -1,6 +1,11 @@ #ifndef MINIMAKE_H #define MINIMAKE_H +#define BUFFER_SIZE 1024 +#define HASHMAP_SIZE 32 + +#include + #include "list/list.h" // Holds variable information @@ -20,16 +25,6 @@ struct rule struct list *recipe; }; -// Holds line information -// Exists only because of EPITA's annoying 4 parameters limit -// WARNING buffer must be freed after use -struct line -{ - char* buffer; - size_t number; - size_t length; -}; - int make(char *path, int flags); #endif // ! MINIMAKE_H From 1fe9f668b65be55b50fca784f40068ee69ae8104 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Mon, 27 Oct 2025 11:14:41 +0100 Subject: [PATCH 08/23] ' --- minimake/Makefile | 27 +- minimake/minimake | Bin 0 -> 21488 bytes .../hash_map.c => hash_maps/hash_maps.c} | 2 +- .../hash_map.h => hash_maps/hash_maps.h} | 0 minimake/src/list/list_advanced.c | 101 ------ minimake/src/list/list_basic.c | 86 ----- minimake/src/list/list_ultimate.c | 138 -------- minimake/src/{list => lists}/.gitignore | 0 minimake/src/lists/lists.c | 333 ++++++++++++++++++ minimake/src/{list/list.h => lists/lists.h} | 0 minimake/src/main.c | 8 +- minimake/src/minimake.c | 4 +- minimake/src/minimake.h | 2 +- 13 files changed, 368 insertions(+), 333 deletions(-) create mode 100755 minimake/minimake rename minimake/src/{hash_map/hash_map.c => hash_maps/hash_maps.c} (99%) rename minimake/src/{hash_map/hash_map.h => hash_maps/hash_maps.h} (100%) delete mode 100644 minimake/src/list/list_advanced.c delete mode 100644 minimake/src/list/list_basic.c delete mode 100644 minimake/src/list/list_ultimate.c rename minimake/src/{list => lists}/.gitignore (100%) create mode 100644 minimake/src/lists/lists.c rename minimake/src/{list/list.h => lists/lists.h} (100%) diff --git a/minimake/Makefile b/minimake/Makefile index a1b29ea..895b2d5 100644 --- a/minimake/Makefile +++ b/minimake/Makefile @@ -1,3 +1,26 @@ -CC= gcc -CFLAGS= -std=c99 -pedantic -Werror -Wall -Wextra -Wvla +CC = gcc +CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla +DBG_CFLAGS = -fsanitize=address -g +SRC_DIR = src +LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c +MAIN_SRCS = main.c minimake.c + +# SRCS = $(patsubst %,$(SRC_DIR)/%, $(MAIN_SRCS)) +SRCS = $(MAIN_SRCS:%=$(SRC_DIR)/%) $(LIB_SRCS:%=$(SRC_DIR)/%) +OBJS = $(SRCS:.c=.o) + +TARGET= minimake +# DBG_TARGET = minimake-dbg + +$(TARGET): $(OBJS) + $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) + @echo $(OBJS) + +debug: CFLAGS += $(DBG_CFLAGS) +debug: $(OBJS) + $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) + +clean: + $(RM) $(TARGET) + $(RM) $(OBJS) diff --git a/minimake/minimake b/minimake/minimake new file mode 100755 index 0000000000000000000000000000000000000000..5a2c793c9a47805f567772f1ccc009f1c8dab480 GIT binary patch literal 21488 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 TXbu)8ZTYn1_?Sb$Q5F9UDWXBq literal 0 HcmV?d00001 diff --git a/minimake/src/hash_map/hash_map.c b/minimake/src/hash_maps/hash_maps.c similarity index 99% rename from minimake/src/hash_map/hash_map.c rename to minimake/src/hash_maps/hash_maps.c index d1609d0..d97a420 100644 --- a/minimake/src/hash_map/hash_map.c +++ b/minimake/src/hash_maps/hash_maps.c @@ -1,4 +1,4 @@ -#include "hash_map.h" +#include "hash_maps.h" #include #include diff --git a/minimake/src/hash_map/hash_map.h b/minimake/src/hash_maps/hash_maps.h similarity index 100% rename from minimake/src/hash_map/hash_map.h rename to minimake/src/hash_maps/hash_maps.h diff --git a/minimake/src/list/list_advanced.c b/minimake/src/list/list_advanced.c deleted file mode 100644 index 78402d1..0000000 --- a/minimake/src/list/list_advanced.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include - -#include "list.h" - -struct list *list_insert(struct list *list, void *value, size_t index) -{ - if (list == NULL || index == 0) - { - struct list *new_elt = malloc(sizeof(struct list)); - new_elt->data = value; - new_elt->next = list; - return new_elt; - } - - struct list *elt = list; - - for (size_t i = 0; i < index - 1; i++) - { - if (elt->next == NULL) - { - break; - } - elt = elt->next; - } - - struct list *new_elt = malloc(sizeof(struct list)); - new_elt->data = value; - new_elt->next = elt->next; - elt->next = new_elt; - - return list; -} - -struct list *list_remove(struct list *list, size_t index) -{ - struct list *elt = list; - struct list *prev_elt; - - if (index == 0) - { - struct list *res = elt->next; - free(elt); - return res; - } - - for (size_t i = 0; i < index; i++) - { - if (elt == NULL) - { - return list; - } - prev_elt = elt; - elt = elt->next; - } - if (elt == NULL) - { - return list; - } - - prev_elt->next = elt->next; - free(elt); - - return list; -} - -int list_find(struct list *list, void *value) -{ - if (list == NULL) - { - return -1; - } - - int res = 0; - while (list->data != value) - { - list = list->next; - res++; - if (list == NULL) - { - return -1; - } - } - return res; -} - -struct list *list_concat(struct list *list, struct list *list2) -{ - if (list == NULL) - { - return list2; - } - struct list *elt = list; - while (elt->next != NULL) - { - elt = elt->next; - } - elt->next = list2; - return list; -} diff --git a/minimake/src/list/list_basic.c b/minimake/src/list/list_basic.c deleted file mode 100644 index a0672bb..0000000 --- a/minimake/src/list/list_basic.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include - -#include "list.h" - -struct list *list_prepend(struct list *list, void *value) -{ - struct list *new_elt = malloc(sizeof(struct list)); - if (new_elt == NULL) - { - return NULL; - } - new_elt->next = list; - new_elt->data = value; - - return new_elt; -} - -size_t list_length(struct list *list) -{ - size_t len = 0; - while (list != NULL) - { - len++; - list = list->next; - } - return len; -} - -// void list_print(struct list *list) -// { -// if (list == NULL) -// { -// return; -// } - -// while (list != NULL) -// { -// if (list->next != NULL) -// { -// printf("%p ", list->data); -// } -// else -// { -// printf("%p\n", list->data); -// } -// list = list->next; -// } -// } - -void list_destroy(struct list *list) -{ - struct list *elt = list; - struct list *next_elt; - while (elt != NULL) - { - next_elt = elt->next; - free(elt); - elt = next_elt; - } -} - -struct list *list_append(struct list *list, void *value) -{ - if (list == NULL) - { - struct list *new_elt = malloc(sizeof(struct list)); - new_elt->data = value; - new_elt->next = NULL; - return new_elt; - } - - struct list *elt = list; - - while (elt->next != NULL) - { - elt = elt->next; - } - - struct list *new_elt = malloc(sizeof(struct list)); - new_elt->data = value; - new_elt->next = NULL; - elt->next = new_elt; - - return list; -} diff --git a/minimake/src/list/list_ultimate.c b/minimake/src/list/list_ultimate.c deleted file mode 100644 index d4a57f3..0000000 --- a/minimake/src/list/list_ultimate.c +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include - -#include "list.h" - -void swap_next(struct list *elt) -{ - void *c = elt->next->data; - elt->next->data = elt->data; - elt->data = c; -} -struct list *list_sort(struct list *list) -{ - // Bubble sort go ! - if (list == NULL) - { - return list; - } - struct list *elt = list; - int len = 0; - while (elt->next != NULL) - { - if (elt->data > elt->next->data) - { - swap_next(elt); - } - elt = elt->next; - len++; - } - - for (int i = 1; i < len; i++) - { - elt = list; - while (elt->next != NULL) - { - if (elt->data > elt->next->data) - { - swap_next(elt); - } - elt = elt->next; - } - } - - return list; -} - -// Old proto -// WARNING no malloc/free allowed (moulinette issue) -struct list *list_reverse(struct list *list) -{ - if (list == NULL) - { - return list; - } - - // Get len - struct list *elt = list; - int len = 0; - while (elt->next != NULL) - { - len++; - elt = elt->next; - } - elt = list; - - // Bring each elt to end - for (int i = 0; i < len; i++) - { - elt = list; - for (int j = 0; j < len - i; j++) - { - swap_next(elt); - elt = elt->next; - } - } - - return list; -} - -// Doesn't work neither -// struct list *list_reverse(struct list *list) -// { -// struct list *new_list = NULL; -// struct list *elt = list; -// while (elt != NULL) -// { -// struct list *new_elt = malloc(sizeof(struct list)); -// if (new_elt == NULL) -// { -// return NULL; -// } -// new_elt->data = elt->data; -// new_elt->next = new_list; - -// struct list *next_elt = elt->next; -// free(elt); -// elt = next_elt; -// } -// return new_list; -// } - -// Moulinette issue -// struct list *list_reverse(struct list *list) -// { -// if (list == NULL) -// { -// return list; -// } - -// struct list *new_list = NULL; -// while (list != NULL) -// { -// new_list = list_prepend(new_list, list->data); -// list = list_remove(list, 0); -// } - -// return new_list; -// } - -struct list *list_split(struct list *list, size_t index) -{ - struct list *elt = list; - for (size_t i = 0; i < index; i++) - { - if (elt == NULL) - { - return NULL; - } - elt = elt->next; - } - if (elt == NULL) - { - return NULL; - } - struct list *res = elt->next; - elt->next = NULL; - return res; -} diff --git a/minimake/src/list/.gitignore b/minimake/src/lists/.gitignore similarity index 100% rename from minimake/src/list/.gitignore rename to minimake/src/lists/.gitignore diff --git a/minimake/src/lists/lists.c b/minimake/src/lists/lists.c new file mode 100644 index 0000000..aa355a1 --- /dev/null +++ b/minimake/src/lists/lists.c @@ -0,0 +1,333 @@ +#include "lists.h" + +#include +#include +#include + +struct list *list_prepend(struct list *list, void *value) +{ + struct list *new_elt = malloc(sizeof(struct list)); + if (new_elt == NULL) + { + return NULL; + } + new_elt->next = list; + new_elt->data = value; + + return new_elt; +} + +size_t list_length(struct list *list) +{ + size_t len = 0; + while (list != NULL) + { + len++; + list = list->next; + } + return len; +} + +// void list_print(struct list *list) +// { +// if (list == NULL) +// { +// return; +// } + +// while (list != NULL) +// { +// if (list->next != NULL) +// { +// printf("%p ", list->data); +// } +// else +// { +// printf("%p\n", list->data); +// } +// list = list->next; +// } +// } + +void list_destroy(struct list *list) +{ + struct list *elt = list; + struct list *next_elt; + while (elt != NULL) + { + next_elt = elt->next; + free(elt); + elt = next_elt; + } +} + +struct list *list_append(struct list *list, void *value) +{ + if (list == NULL) + { + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = NULL; + return new_elt; + } + + struct list *elt = list; + + while (elt->next != NULL) + { + elt = elt->next; + } + + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = NULL; + elt->next = new_elt; + + return list; +} + +/* + * + ******************* + * Advanced * + ******************* + * + */ + +struct list *list_insert(struct list *list, void *value, size_t index) +{ + if (list == NULL || index == 0) + { + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = list; + return new_elt; + } + + struct list *elt = list; + + for (size_t i = 0; i < index - 1; i++) + { + if (elt->next == NULL) + { + break; + } + elt = elt->next; + } + + struct list *new_elt = malloc(sizeof(struct list)); + new_elt->data = value; + new_elt->next = elt->next; + elt->next = new_elt; + + return list; +} + +struct list *list_remove(struct list *list, size_t index) +{ + struct list *elt = list; + struct list *prev_elt; + + if (index == 0) + { + struct list *res = elt->next; + free(elt); + return res; + } + + for (size_t i = 0; i < index; i++) + { + if (elt == NULL) + { + return list; + } + prev_elt = elt; + elt = elt->next; + } + if (elt == NULL) + { + return list; + } + + prev_elt->next = elt->next; + free(elt); + + return list; +} + +int list_find(struct list *list, void *value) +{ + if (list == NULL) + { + return -1; + } + + int res = 0; + while (list->data != value) + { + list = list->next; + res++; + if (list == NULL) + { + return -1; + } + } + return res; +} + +struct list *list_concat(struct list *list, struct list *list2) +{ + if (list == NULL) + { + return list2; + } + struct list *elt = list; + while (elt->next != NULL) + { + elt = elt->next; + } + elt->next = list2; + return list; +} + +/* + * + ****************** + * Ultimate * + ****************** + * + */ + +static void swap_next(struct list *elt) +{ + void *c = elt->next->data; + elt->next->data = elt->data; + elt->data = c; +} +struct list *list_sort(struct list *list) +{ + // Bubble sort go ! + if (list == NULL) + { + return list; + } + struct list *elt = list; + int len = 0; + while (elt->next != NULL) + { + if (elt->data > elt->next->data) + { + swap_next(elt); + } + elt = elt->next; + len++; + } + + for (int i = 1; i < len; i++) + { + elt = list; + while (elt->next != NULL) + { + if (elt->data > elt->next->data) + { + swap_next(elt); + } + elt = elt->next; + } + } + + return list; +} + +// Old proto +// WARNING no malloc/free allowed (moulinette issue) +struct list *list_reverse(struct list *list) +{ + if (list == NULL) + { + return list; + } + + // Get len + struct list *elt = list; + int len = 0; + while (elt->next != NULL) + { + len++; + elt = elt->next; + } + elt = list; + + // Bring each elt to end + for (int i = 0; i < len; i++) + { + elt = list; + for (int j = 0; j < len - i; j++) + { + swap_next(elt); + elt = elt->next; + } + } + + return list; +} + +// Doesn't work neither +// struct list *list_reverse(struct list *list) +// { +// struct list *new_list = NULL; +// struct list *elt = list; +// while (elt != NULL) +// { +// struct list *new_elt = malloc(sizeof(struct list)); +// if (new_elt == NULL) +// { +// return NULL; +// } +// new_elt->data = elt->data; +// new_elt->next = new_list; + +// struct list *next_elt = elt->next; +// free(elt); +// elt = next_elt; +// } +// return new_list; +// } + +// Moulinette issue +// struct list *list_reverse(struct list *list) +// { +// if (list == NULL) +// { +// return list; +// } + +// struct list *new_list = NULL; +// while (list != NULL) +// { +// new_list = list_prepend(new_list, list->data); +// list = list_remove(list, 0); +// } + +// return new_list; +// } + +struct list *list_split(struct list *list, size_t index) +{ + struct list *elt = list; + for (size_t i = 0; i < index; i++) + { + if (elt == NULL) + { + return NULL; + } + elt = elt->next; + } + if (elt == NULL) + { + return NULL; + } + struct list *res = elt->next; + elt->next = NULL; + return res; +} diff --git a/minimake/src/list/list.h b/minimake/src/lists/lists.h similarity index 100% rename from minimake/src/list/list.h rename to minimake/src/lists/lists.h diff --git a/minimake/src/main.c b/minimake/src/main.c index e3abfb9..8a9362a 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -11,7 +11,7 @@ // Look at perror for stdlib functions // Create an enum for error handling -int handle_args(int argc, char **argv) +static int handle_args(int argc, char **argv) { int flags = 0; for (int i = 1; i < argc; i++) @@ -25,7 +25,11 @@ int handle_args(int argc, char **argv) else errx(INVALID_ARG, ": Pleaase give an argument"); } + printf("%s: done", argv[0]); + return flags; } int main(int argc, char **argv) -{} +{ + return handle_args(argc, argv); +} diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index e922791..fa87c7b 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -8,9 +8,9 @@ #include #include -#include "hash_map/hash_map.h" +#include "hash_maps/hash_maps.h" #include "lines/lines.h" -#include "list/list.h" +#include "lists/lists.h" // Static variables struct hash_map *variables = NULL; diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index b04155e..b5cf465 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -6,7 +6,7 @@ #include -#include "list/list.h" +#include "lists/lists.h" // Holds variable information // WARNING its values must be freed after use From 44d62db74c154afbfbce71e4332778790cb84de7 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Mon, 27 Oct 2025 19:29:04 +0100 Subject: [PATCH 09/23] backup --- .gitignore | 1 + AUTHORS | 5 ++ minimake/Makefile | 5 ++ minimake/minimake | Bin 21488 -> 0 bytes minimake/src/lines/lines.c | 35 ++++---- minimake/src/lines/lines.h | 4 +- minimake/src/main.c | 122 ++++++++++++++++++++++++---- minimake/src/minimake.c | 70 ++++++++++++---- minimake/src/minimake.h | 13 ++- minimake/tests/Makefile.syntax-test | 35 -------- 10 files changed, 208 insertions(+), 82 deletions(-) create mode 100644 AUTHORS delete mode 100755 minimake/minimake delete mode 100644 minimake/tests/Makefile.syntax-test diff --git a/.gitignore b/.gitignore index 1801c29..14c96f3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ *.class *.log *.core +minimake diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..69b5c09 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +guillem.george + +Special thanks to + +- Timothée Battefort for the parser diff --git a/minimake/Makefile b/minimake/Makefile index 895b2d5..fa1a362 100644 --- a/minimake/Makefile +++ b/minimake/Makefile @@ -1,6 +1,10 @@ CC = gcc CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla +LDFLAGS= + DBG_CFLAGS = -fsanitize=address -g +DBG_LDFLAGS= -fsanitize=address + SRC_DIR = src LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c @@ -18,6 +22,7 @@ $(TARGET): $(OBJS) @echo $(OBJS) debug: CFLAGS += $(DBG_CFLAGS) +debug: LDFLAGS += $(DBG_LDFLAGS) debug: $(OBJS) $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) diff --git a/minimake/minimake b/minimake/minimake deleted file mode 100755 index 5a2c793c9a47805f567772f1ccc009f1c8dab480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21488 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 TXbu)8ZTYn1_?Sb$Q5F9UDWXBq diff --git a/minimake/src/lines/lines.c b/minimake/src/lines/lines.c index 4201eea..bf82c56 100644 --- a/minimake/src/lines/lines.c +++ b/minimake/src/lines/lines.c @@ -9,13 +9,14 @@ // Helps to match a string (excludes blanks and special characters) int isChar(char c) { - return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; + return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#' + && c != '\n'; } int skipBlanks(char *buf, size_t buf_len) { size_t i = 0; - while (i < buf_len && isblank(buf[i])) + while (i < buf_len && (isblank(buf[i]) || buf[i] == '\n')) i++; return i; } @@ -29,7 +30,7 @@ int isBlankLine(struct line *l) size_t i = 0; while (i < line_size) { - if (!isblank(buf[i])) + if (!isblank(buf[i]) && buf[i] != '\n') return 0; if (buf[i] == '#') // Comments return 1; @@ -41,28 +42,34 @@ int isBlankLine(struct line *l) // Returns the next word from buf until buf_len, // and the numbers of read characters in *read_chars // WARNING allocates the result on the heap -char *readWord(char *buf, size_t buf_len, size_t *read_chars) +size_t readWord(char *buf, size_t buf_len, char **word) { size_t i = 0; - size_t str_buf_size = STRING_BUFFER_SIZE; - char *str_buf = malloc(sizeof(char) * str_buf_size); + size_t res_size = STRING_BUFFER_SIZE; + char *res = malloc(sizeof(char) * res_size); while (i < buf_len && isChar(buf[i])) { // Reallocate more space if necessary - if (i >= str_buf_size - 1) + if (i >= res_size - 1) { - str_buf_size += STRING_BUFFER_SIZE; - str_buf = realloc(str_buf, str_buf_size); - if (str_buf == NULL) + res_size += STRING_BUFFER_SIZE; + res = realloc(res, res_size); + if (res == NULL) errx(2, "Could not realloc"); } - str_buf[i] = buf[i]; + res[i] = buf[i]; i++; } + res[i] = '\0'; - str_buf[i] = '\0'; - *read_chars = i; + if (i == 0) + { + free(res); + *word = NULL; + return i; + } - return str_buf; + *word = res; + return i; } diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h index 1eed08c..99e7f10 100644 --- a/minimake/src/lines/lines.h +++ b/minimake/src/lines/lines.h @@ -12,7 +12,7 @@ struct line { char* buffer; // Line content - size_t length; // Line length + ssize_t length; // Line length size_t number; // Line number in file FILE* file_stream; // Full file stream }; @@ -20,6 +20,6 @@ struct line int isChar(char c); int isBlankLine(struct line *l); int skipBlanks(char *buf, size_t buf_len); -char *readWord(char *buf, size_t buf_len, size_t *read_chars); +size_t readWord(char *buf, size_t buf_len, char **word); #endif // LINES_H diff --git a/minimake/src/main.c b/minimake/src/main.c index 8a9362a..c2d7a0b 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -1,35 +1,127 @@ -// Error Codes -#define INVALID_ARG 2 - #include #include -#include +#include +// #include #include #include +#include "lists/lists.h" +#include "minimake.h" + // TODO: // Look at perror for stdlib functions // Create an enum for error handling -static int handle_args(int argc, char **argv) +static void print_help(char *program_name) +{ + printf("Usage: %s [options] [target]... ", program_name); + puts("Options:"); + puts(" -f FILE Reads FILE as a makefile"); + puts(" -h Prints this message and exit"); + puts(" -p Prints minimake's internal database"); + puts(""); + puts("Pas mal non ? C'est français"); +} + +static int handle_args(int argc, char **argv, struct list **minimake_files, + struct list **minimake_rules) { int flags = 0; + struct list *files = NULL; + struct list *rules = NULL; for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "-h")) - errx(INVALID_ARG, "-h: not implemented"); - else if (strcmp(argv[i], "-f")) - errx(INVALID_ARG, "-f: not implemented"); - else if (strcmp(argv[i], "-p")) - errx(INVALID_ARG, "-p: not implemented"); - else - errx(INVALID_ARG, ": Pleaase give an argument"); + // Options + if (argv[i][0] == '-') + { + // No opt + if (strcmp(argv[i], "--") == 0) + { + // Treat as rules + for (int j = i; j < argc; j++) + { + files = list_append(rules, argv[i]); + } + *minimake_files = files; + *minimake_rules = rules; + return flags; + } + // Help + else if (strcmp(argv[i], "-h") == 0) + { + print_help(argv[0]); + exit(0); + } + // Custom file + else if (strcmp(argv[i], "-f") == 0) + { + flags |= FLAGS_CUSTOM_FILE; + if (i + 1 == argc || argv[i + 1][0] == '-') + errx(INVALID_ARG, "No file specified after '-f'"); + + files = list_prepend(files, argv[i]); + } + // Print + else if (strcmp(argv[i], "-p") == 0) + { + flags |= FLAGS_PRINT; + } + // Unknown option + else + { + printf("Unknown option '%s'", argv[i]); + print_help(argv[0]); + exit(INVALID_ARG); + } + } + else // Rules + { + files = list_append(rules, argv[i]); + } } - printf("%s: done", argv[0]); + + files = list_append(files, DEFAULT_MAKEFILE); + files = list_append(files, DEFAULT_MAKEFILE_2); + + *minimake_files = files; + *minimake_rules = rules; return flags; } +char *getMakefile(struct list *files) +{ + struct list *file = files; + int found = 0; + + // Test file presence + while (file != NULL && !found) + { + FILE *test = fopen(file->data, "r"); + if (test != NULL) + found = 1; + + fclose(test); + if (!found) + file = file->next; + } + + char *res = NULL; + if (found) + res = file->data; + + list_destroy(files); + return res; +} + int main(int argc, char **argv) { - return handle_args(argc, argv); + struct list *files; + struct list *rules; + int flags = handle_args(argc, argv, &files, &rules); + + char *filename = getMakefile(files); + if (filename == NULL) + errx(GENERIC_ERR, "No Makefile found"); + + make(filename, flags); } diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index fa87c7b..c8d66be 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -29,8 +29,12 @@ static struct variable *createVariable(char *name) int err = hashMapInsert(variables, name, NULL, NULL); if (!err) - errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", + { + // free(name); + free(res); + errx(2, "Internal Error: Couln't add entry for '%s' in the hashmap", name); + } return res; } @@ -54,29 +58,37 @@ static struct rule *createRule(char *name) } // Parse dependencies from buf and returns them inside a chained list -static struct list *readDependencies(char *buf, size_t buf_size) +static struct list *readDependencies(struct line *l, size_t offset) { - size_t i = 0; + size_t i = offset; + size_t buf_size = l->length; + char *buf = l->buffer; struct list *res = NULL; + while (i < buf_size) { i += skipBlanks(buf + i, buf_size - i); // Read word - size_t skipped_chars = 0; - char *dep_name = readWord(buf + i, buf_size - i, &skipped_chars); - if (skipped_chars != 0) + char *dep_name; + i += readWord(buf + i, buf_size - i, &dep_name); + if (dep_name != NULL) // Add to list res = list_append(res, dep_name); - i += skipped_chars; // Comments if (buf[i] == '#') return res; // Unknown chars - if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') - errx(2, "Unexpected character '%c'", buf[i]); + if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' + && buf[i] != '\n') + { + printf("DEBUG: line: %s", l->buffer); + errx(2, + "Unexpected character '%c' after rule declaration at %lu:%lu", + buf[i], l->number, i); + } } return res; @@ -94,7 +106,7 @@ static struct list *readRecipe(struct line *l) struct list *res = NULL; // Getline - while ((l->length = getline(&buf, &buf_size, stream))) + while ((l->length = getline(&buf, &buf_size, stream)) != -1) { l->number++; @@ -148,6 +160,8 @@ static char *readValue(char *buf, size_t buf_size) return str_buf; } +// static char *expand_variable(); + // Takes a buffer containing the line to parse and it length // As well as the line number in the file for error handling static void parseLine(struct line *current_line) @@ -160,9 +174,11 @@ static void parseLine(struct line *current_line) i += skipBlanks(buf + i, line_size - i); // Read name - size_t skipped_chars = 0; - char *name = readWord(buf + i, line_size - i, &skipped_chars); - i += skipped_chars; + char *name; + i += readWord(buf + i, line_size - i, &name); + // if (name == NULL) + // errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu", + // current_line->number, i); i += skipBlanks(buf + i, line_size - i); @@ -182,10 +198,16 @@ static void parseLine(struct line *current_line) // Rule case ':': new_rule = createRule(name); - new_rule->dependencies = readDependencies(buf + i, line_size); + new_rule->dependencies = readDependencies(current_line, i + 1); new_rule->recipe = readRecipe(current_line); + + // Check for EOF + if (current_line->length == -1) + return; + parseLine(current_line); // TODO: check for loooooops + break; // Blank line @@ -203,7 +225,7 @@ static void parseLine(struct line *current_line) buf[i], name, current_line->number); } - free(name); + // free(name); } void makeParse(char *path) @@ -249,3 +271,21 @@ void makeParse(char *path) } // ==== Runtime ==== + +// ==== MAKE ==== + +void make(char *path, int flags) +{ + if (flags & FLAGS_PRINT) + errx(GENERIC_ERR, "Not Implemented"); + + makeParse(path); +} + +// ==== Misc ==== + +// static void free_all() +// { +// hashMapFree(rules); +// hashMapFree(variables); +// } diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index b5cf465..55910e8 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -1,6 +1,17 @@ #ifndef MINIMAKE_H #define MINIMAKE_H +// Error Codes +#define INVALID_ARG 2 +#define GENERIC_ERR 2 + +// Flags +#define FLAGS_CUSTOM_FILE 1 +#define FLAGS_PRINT 2 + +// Default values +#define DEFAULT_MAKEFILE "Makefile" +#define DEFAULT_MAKEFILE_2 "makefile" #define BUFFER_SIZE 1024 #define HASHMAP_SIZE 32 @@ -25,6 +36,6 @@ struct rule struct list *recipe; }; -int make(char *path, int flags); +void make(char *path, int flags); #endif // ! MINIMAKE_H diff --git a/minimake/tests/Makefile.syntax-test b/minimake/tests/Makefile.syntax-test deleted file mode 100644 index fff0427..0000000 --- a/minimake/tests/Makefile.syntax-test +++ /dev/null @@ -1,35 +0,0 @@ -SIMPLE_VAR = coucou -SIMPLE_VAR_COMMENT = the comment is gone # comment - -# the following line starts with a space then a tab - SPACES_BEFORE_TAB = var_beginning var_end - -sparse_rule: depa depb - - command 1 - - command 2 - - B = B_var_beginning B_var_end - -packed_rule: depa depb - command 1 - command 2 - -silent_rule: depa depb - @ command 1 - @command 2 - -rule_comment: depa depb # comment - -command_space_rule: depa depb - echo spaces before - echo spaces after - echo this is a # comment - -simple_rule: simple_dep - -no_dep_rule: - -variable_rule: beginning $(SIMPLE_VAR) end - echo "shouldn't be expanded: $(SIMPLE_VAR)" From 5f4d6af9c0b03fd2c31909410a08f4a6d29fa30c Mon Sep 17 00:00:00 2001 From: Guillem George Date: Mon, 27 Oct 2025 19:56:40 +0100 Subject: [PATCH 10/23] DEMENTOOOOR --- minimake/Makefile | 3 +++ minimake/src/lines/lines.h | 1 + minimake/src/minimake.h | 1 + 3 files changed, 5 insertions(+) diff --git a/minimake/Makefile b/minimake/Makefile index fa1a362..c12a97e 100644 --- a/minimake/Makefile +++ b/minimake/Makefile @@ -26,6 +26,9 @@ debug: LDFLAGS += $(DBG_LDFLAGS) debug: $(OBJS) $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) +check: + dash ./tests/run.sh + clean: $(RM) $(TARGET) $(RM) $(OBJS) diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h index 99e7f10..8ac1d73 100644 --- a/minimake/src/lines/lines.h +++ b/minimake/src/lines/lines.h @@ -4,6 +4,7 @@ #define STRING_BUFFER_SIZE 32 #include +#include #include // Holds line information diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index 55910e8..374eca4 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -16,6 +16,7 @@ #define HASHMAP_SIZE 32 #include +#include #include "lists/lists.h" From afe78e44017cf4039c9f80ef8625520ca2faaa86 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Tue, 28 Oct 2025 19:38:32 +0100 Subject: [PATCH 11/23] ' --- minimake/src/hash_maps/hash_maps.c | 23 +++-- minimake/src/hash_maps/hash_maps.h | 26 ++--- minimake/src/lines/lines.c | 10 +- minimake/src/lines/lines.h | 8 +- minimake/src/main.c | 2 +- minimake/src/minimake.c | 152 +++++++++++++++++------------ minimake/src/minimake.h | 3 +- 7 files changed, 131 insertions(+), 93 deletions(-) diff --git a/minimake/src/hash_maps/hash_maps.c b/minimake/src/hash_maps/hash_maps.c index d97a420..405a0f9 100644 --- a/minimake/src/hash_maps/hash_maps.c +++ b/minimake/src/hash_maps/hash_maps.c @@ -27,7 +27,7 @@ size_t hash(const char *key) return hash; } -struct hash_map *hashMapInit(size_t size) +struct hash_map *hashmap_init(size_t size) { struct pair_list **data = calloc(size, sizeof(struct pair_list)); struct hash_map *map = malloc(sizeof(struct hash_map)); @@ -36,8 +36,8 @@ struct hash_map *hashMapInit(size_t size) return map; } -bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, - bool *updated) +bool hashmap_insert(struct hash_map *hash_map, char *key, void *value, + bool *updated) { if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) { @@ -79,7 +79,7 @@ bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, return true; } -void hashMapFree(struct hash_map *hash_map) +void hashmap_free(struct hash_map *hash_map) { if (hash_map == NULL) return; @@ -100,7 +100,10 @@ void hashMapFree(struct hash_map *hash_map) free(hash_map); } -void hashMapDump(struct hash_map *hash_map) +// WARNING +// Will only work with string values +// DO NOT attempt to call it with anything else +void hashmap_dump(struct hash_map *hash_map) { for (size_t i = 0; i < hash_map->size; i++) { @@ -109,12 +112,14 @@ void hashMapDump(struct hash_map *hash_map) if (entry != NULL) { is_null = false; - printf("%s: %s", entry->key, entry->value); + char *val = entry->value; + printf("%s: %s", entry->key, val); entry = entry->next; } while (entry != NULL) { - printf(", %s: %s", entry->key, entry->value); + char *val = entry->value; + printf(", %s: %s", entry->key, val); entry = entry->next; } if (!is_null) @@ -122,7 +127,7 @@ void hashMapDump(struct hash_map *hash_map) } } -const char *hashMapGet(const struct hash_map *hash_map, const char *key) +void *hashmap_get(const struct hash_map *hash_map, char *key) { if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) return NULL; @@ -139,7 +144,7 @@ const char *hashMapGet(const struct hash_map *hash_map, const char *key) return entry->value; } -bool hashMapRemove(struct hash_map *hash_map, const char *key) +bool hashmap_remove(struct hash_map *hash_map, char *key) { if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) return false; diff --git a/minimake/src/hash_maps/hash_maps.h b/minimake/src/hash_maps/hash_maps.h index ca21916..97a84da 100644 --- a/minimake/src/hash_maps/hash_maps.h +++ b/minimake/src/hash_maps/hash_maps.h @@ -1,13 +1,17 @@ -#ifndef HASH_MAP_H -#define HASH_MAP_H +#ifndef HASH_MAPS_H +#define HASH_MAPS_H #include #include +// WARNING I made the choice to discard the const qualifier of the key argument +// To add the possibility to free it. +// Note that key should *NEVER* be changed once it has been added to the hashmap + struct pair_list { - const char *key; - char *value; + char *key; + void *value; struct pair_list *next; }; @@ -18,12 +22,12 @@ struct hash_map }; size_t hash(const char *str); -struct hash_map *hashMapInit(size_t size); -bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, +struct hash_map *hashmap_init(size_t size); +bool hashmap_insert(struct hash_map *hash_map, char *key, void *value, bool *updated); -void hashMapFree(struct hash_map *hash_map); -void hashMapDump(struct hash_map *hash_map); -const char *hashMapGet(const struct hash_map *hash_map, const char *key); -bool hashMapRemove(struct hash_map *hash_map, const char *key); +void hashmap_free(struct hash_map *hash_map); +void hashmap_dump(struct hash_map *hash_map); +void *hashmap_get(const struct hash_map *hash_map, char *key); +bool hashmap_remove(struct hash_map *hash_map, char *key); -#endif /* ! HASH_MAP_H */ +#endif /* ! HASH_MAPS_H */ diff --git a/minimake/src/lines/lines.c b/minimake/src/lines/lines.c index bf82c56..dcf0c19 100644 --- a/minimake/src/lines/lines.c +++ b/minimake/src/lines/lines.c @@ -7,13 +7,13 @@ #include // Helps to match a string (excludes blanks and special characters) -int isChar(char c) +int ischar(char c) { return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#' && c != '\n'; } -int skipBlanks(char *buf, size_t buf_len) +int skipblanks(char *buf, size_t buf_len) { size_t i = 0; while (i < buf_len && (isblank(buf[i]) || buf[i] == '\n')) @@ -22,7 +22,7 @@ int skipBlanks(char *buf, size_t buf_len) } // Returns 1 if line is blank -int isBlankLine(struct line *l) +int isblankline(struct line *l) { size_t line_size = l->length; char *buf = l->buffer; @@ -42,12 +42,12 @@ int isBlankLine(struct line *l) // Returns the next word from buf until buf_len, // and the numbers of read characters in *read_chars // WARNING allocates the result on the heap -size_t readWord(char *buf, size_t buf_len, char **word) +size_t readword(char *buf, size_t buf_len, char **word) { size_t i = 0; size_t res_size = STRING_BUFFER_SIZE; char *res = malloc(sizeof(char) * res_size); - while (i < buf_len && isChar(buf[i])) + while (i < buf_len && ischar(buf[i])) { // Reallocate more space if necessary if (i >= res_size - 1) diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h index 8ac1d73..01ace9d 100644 --- a/minimake/src/lines/lines.h +++ b/minimake/src/lines/lines.h @@ -18,9 +18,9 @@ struct line FILE* file_stream; // Full file stream }; -int isChar(char c); -int isBlankLine(struct line *l); -int skipBlanks(char *buf, size_t buf_len); -size_t readWord(char *buf, size_t buf_len, char **word); +int ischar(char c); +int isblankline(struct line *l); +int skipblanks(char *buf, size_t buf_len); +size_t readword(char *buf, size_t buf_len, char **word); #endif // LINES_H diff --git a/minimake/src/main.c b/minimake/src/main.c index c2d7a0b..07ee99d 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -123,5 +123,5 @@ int main(int argc, char **argv) if (filename == NULL) errx(GENERIC_ERR, "No Makefile found"); - make(filename, flags); + make(filename, flags, argv[0]); } diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index c8d66be..6e23a75 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -15,50 +15,81 @@ // Static variables struct hash_map *variables = NULL; struct hash_map *rules = NULL; +char *program_name; + +// ==== Misc ==== + +static void hashmap_deep_free(struct hash_map *hash_map) +{ + if (hash_map == NULL) + return; + if (hash_map->data == NULL) + return; + + for (size_t i = 0; i < hash_map->size; i++) + { + struct pair_list *entry = hash_map->data[i]; + while (entry != NULL) + { + struct pair_list *next = entry->next; + free(entry->key); + free(entry->value); + free(entry); + entry = next; + } + } + free(hash_map->data); + free(hash_map); +} + +static void free_all() +{ + hashmap_deep_free(rules); + hashmap_deep_free(variables); +} + +// static void dump_database() +// { +// hashmap_dump(variables); +// hashmap_dump(rules); +// } // ==== Parsing ==== -// Registers a new variable and returns its pointer +// Registers a new rule in the hashmap // WARNING Allocates memory on the heap, -// the variables hashmap should be freed before exit -static struct variable *createVariable(char *name) +// the rules hashmap should be freed before exit +static void register_rule(char *name, struct list *dependencies, + struct list *recipe) { - struct variable *res = malloc(sizeof(struct variable)); - res->name = name; - res->value = NULL; + struct rule *rule = malloc(sizeof(struct rule)); + rule->name = name; + rule->dependencies = dependencies; + rule->recipe = recipe; - int err = hashMapInsert(variables, name, NULL, NULL); + int err = hashmap_insert(variables, name, rule, NULL); + if (!err) + { + errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", + name); + } +} + +// Registers a new variable in the hashmap +// WARNING Allocates memory on the heap, +// the variables hashmap should be freed before exit +static void register_variable(char *name, char *value) +{ + int err = hashmap_insert(variables, name, value, NULL); if (!err) { - // free(name); - free(res); errx(2, "Internal Error: Couln't add entry for '%s' in the hashmap", name); } - - return res; -} - -// Registers a new rule and returns its pointer -// WARNING Allocates memory on the heap, -// the rules hashmap should be freed before exit -static struct rule *createRule(char *name) -{ - struct rule *res = malloc(sizeof(struct rule)); - res->name = name; - res->dependencies = NULL; - res->recipe = NULL; - - int err = hashMapInsert(variables, name, NULL, NULL); - if (!err) - errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", - name); - - return res; } // Parse dependencies from buf and returns them inside a chained list -static struct list *readDependencies(struct line *l, size_t offset) +static struct list *read_deps(struct line *l, size_t offset) { size_t i = offset; size_t buf_size = l->length; @@ -67,11 +98,11 @@ static struct list *readDependencies(struct line *l, size_t offset) while (i < buf_size) { - i += skipBlanks(buf + i, buf_size - i); + i += skipblanks(buf + i, buf_size - i); // Read word char *dep_name; - i += readWord(buf + i, buf_size - i, &dep_name); + i += readword(buf + i, buf_size - i, &dep_name); if (dep_name != NULL) // Add to list res = list_append(res, dep_name); @@ -81,7 +112,7 @@ static struct list *readDependencies(struct line *l, size_t offset) return res; // Unknown chars - if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' + if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' && buf[i] != '\n') { printf("DEBUG: line: %s", l->buffer); @@ -97,7 +128,7 @@ static struct list *readDependencies(struct line *l, size_t offset) // Searches the following lines for recipes and returns them in the form of a // list // WARNING begins to read the following line -static struct list *readRecipe(struct line *l) +static struct list *read_recipe(struct line *l) { FILE *stream = l->file_stream; char *buf = l->buffer; @@ -111,7 +142,7 @@ static struct list *readRecipe(struct line *l) l->number++; // Skip blank lines and comments - if (isBlankLine(l)) + if (isblankline(l)) continue; else if (buf[0] != '\t') // Not a recipe { @@ -134,7 +165,7 @@ static struct list *readRecipe(struct line *l) } // Reads the value after a variable declaration -static char *readValue(char *buf, size_t buf_size) +static char *read_value(char *buf, size_t buf_size) { size_t i = 0; size_t str_buf_size = STRING_BUFFER_SIZE; @@ -164,48 +195,49 @@ static char *readValue(char *buf, size_t buf_size) // Takes a buffer containing the line to parse and it length // As well as the line number in the file for error handling -static void parseLine(struct line *current_line) +static void parse_line(struct line *current_line) { char *buf = current_line->buffer; size_t line_size = current_line->length; size_t i = 0; - i += skipBlanks(buf + i, line_size - i); + i += skipblanks(buf + i, line_size - i); // Read name char *name; - i += readWord(buf + i, line_size - i, &name); + i += readword(buf + i, line_size - i, &name); // if (name == NULL) // errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu", // current_line->number, i); - i += skipBlanks(buf + i, line_size - i); + i += skipblanks(buf + i, line_size - i); // Potential elements - struct rule *new_rule; - struct variable *new_variable; + struct list *dependencies; + struct list *recipe; + char *value; // Definition type switch (buf[i]) { // Variable case '=': - new_variable = createVariable(name); - new_variable->value = readValue(buf + i, line_size); + value = read_value(buf + i, line_size); + register_variable(name, value); break; // Rule case ':': - new_rule = createRule(name); - new_rule->dependencies = readDependencies(current_line, i + 1); - new_rule->recipe = readRecipe(current_line); + dependencies = read_deps(current_line, i + 1); + recipe = read_recipe(current_line); + register_rule(name, dependencies, recipe); // Check for EOF if (current_line->length == -1) return; - parseLine(current_line); + parse_line(current_line); // TODO: check for loooooops break; @@ -228,7 +260,7 @@ static void parseLine(struct line *current_line) // free(name); } -void makeParse(char *path) +void make_parse(char *path) { // Open file FILE *stream = fopen(path, "r"); @@ -236,8 +268,8 @@ void makeParse(char *path) errx(2, "Could not open file: %s", path); // Init hash maps - variables = hashMapInit(HASHMAP_SIZE); - rules = hashMapInit(HASHMAP_SIZE); + variables = hashmap_init(HASHMAP_SIZE); + rules = hashmap_init(HASHMAP_SIZE); if (variables == NULL || rules == NULL) errx(1, "Internal error: Failed to initiate hash maps"); @@ -260,7 +292,7 @@ void makeParse(char *path) current_line.buffer = buf; current_line.length = nread; - parseLine(¤t_line); + parse_line(¤t_line); current_line.number += 1; } @@ -274,18 +306,14 @@ void makeParse(char *path) // ==== MAKE ==== -void make(char *path, int flags) +void make(char *path, int flags, char *argv0) { + program_name = argv0; + if (flags & FLAGS_PRINT) errx(GENERIC_ERR, "Not Implemented"); - makeParse(path); + make_parse(path); + // dump_database(); + free_all(); } - -// ==== Misc ==== - -// static void free_all() -// { -// hashMapFree(rules); -// hashMapFree(variables); -// } diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index 374eca4..ccd5f08 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -37,6 +37,7 @@ struct rule struct list *recipe; }; -void make(char *path, int flags); +void make(char *path, int flags, char* program_name); +void make_parse(char *path); #endif // ! MINIMAKE_H From 8e227e429893799407e44902cefc459275595771 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Tue, 28 Oct 2025 20:13:22 +0100 Subject: [PATCH 12/23] ' --- minimake/src/minimake.c | 112 +++++++++++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 20 deletions(-) diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 6e23a75..3e37319 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "hash_maps/hash_maps.h" #include "lines/lines.h" @@ -32,8 +33,32 @@ static void hashmap_deep_free(struct hash_map *hash_map) while (entry != NULL) { struct pair_list *next = entry->next; - free(entry->key); - free(entry->value); + // Ok c moche mais eh, ça fonctionne + if (hash_map == rules) + { + struct rule *r = entry->value; + free(r->name); + list_destroy(r->dependencies); + list_destroy(r->recipe); + free(r); + free(entry->key); + } + if (hash_map == variables) + { + struct variable *v = entry->value; + free(v->name); + free(v->value); + + free(entry->key); + free(entry->value); + } + else + { + printf("DEBUG: attempting to free a generic hashmap"); + free(entry->key); + free(entry->value); + } + free(entry); entry = next; } @@ -54,6 +79,21 @@ static void free_all() // hashmap_dump(rules); // } +static void exit_on_error(int status, char *message) +{ + char *full_msg; + int err = sprintf(full_msg, "%s: %s\n", program_name, message); + free(message); + if (err == -1) + exit(status); + + write(STDERR_FILENO, full_msg, strlen(full_msg)); + + free(full_msg); + free_all(); + exit(status); +} + // ==== Parsing ==== // Registers a new rule in the hashmap @@ -70,8 +110,11 @@ static void register_rule(char *name, struct list *dependencies, int err = hashmap_insert(variables, name, rule, NULL); if (!err) { - errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", - name); + char *err_msg; + sprintf(err_msg, + "Internal Error: Couln't add entry for '%s' in the hashmap", + name); + exit_on_error(GENERIC_ERR, err_msg); } } @@ -83,8 +126,11 @@ static void register_variable(char *name, char *value) int err = hashmap_insert(variables, name, value, NULL); if (!err) { - errx(2, "Internal Error: Couln't add entry for '%s' in the hashmap", - name); + char *err_msg; + sprintf(err_msg, + "Internal Error: Couln't add entry for '%s' in the hashmap", + name); + exit_on_error(GENERIC_ERR, err_msg); } } @@ -115,10 +161,12 @@ static struct list *read_deps(struct line *l, size_t offset) if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' && buf[i] != '\n') { - printf("DEBUG: line: %s", l->buffer); - errx(2, - "Unexpected character '%c' after rule declaration at %lu:%lu", - buf[i], l->number, i); + char *err_msg; + sprintf( + err_msg, + "Unexpected character '%c' after rule declaration at %lu:%lu", + buf[i], l->number, i); + exit_on_error(GENERIC_ERR, err_msg); } } @@ -153,8 +201,13 @@ static struct list *read_recipe(struct line *l) { char *command = strdup(buf + 1); if (command == NULL) - errx(1, "Internal error: couldn't duplicate string (%lu:1)", - l->number); + { + char *err_msg; + sprintf(err_msg, + "Internal error: couldn't duplicate string (%lu:1)", + l->number); + exit_on_error(GENERIC_ERR, err_msg); + } res = list_append(res, command); } @@ -179,7 +232,11 @@ static char *read_value(char *buf, size_t buf_size) str_buf_size += STRING_BUFFER_SIZE; str_buf = realloc(str_buf, str_buf_size); if (str_buf == NULL) - errx(2, "Could not realloc"); + { + char *err_msg; + sprintf(err_msg, "Could not realloc"); + exit_on_error(GENERIC_ERR, err_msg); + } } str_buf[i] = buf[i]; @@ -217,6 +274,7 @@ static void parse_line(struct line *current_line) struct list *dependencies; struct list *recipe; char *value; + char *err_msg; // Definition type switch (buf[i]) @@ -246,15 +304,21 @@ static void parse_line(struct line *current_line) case '\0': case '#': if (name != NULL) - errx(2, - "Unexpected character '%c' after declaration '%s' at line %lu", - buf[i], name, current_line->number); + { + sprintf( + err_msg, + "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); + exit_on_error(GENERIC_ERR, err_msg); + } else break; default: - errx(2, "Unexpected character '%c' after declaration '%s' at line %lu", - buf[i], name, current_line->number); + sprintf(err_msg, + "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); + exit_on_error(GENERIC_ERR, err_msg); } // free(name); @@ -277,7 +341,11 @@ void make_parse(char *path) size_t buf_size = BUFFER_SIZE; char *buf = malloc(sizeof(char) * buf_size); if (buf == NULL) - errx(2, "Could not allocate more memory"); + { + char *err_msg; + sprintf(err_msg, "Could not allocate more memory"); + exit_on_error(GENERIC_ERR, err_msg); + } // Parse line by line ssize_t nread; @@ -287,7 +355,11 @@ void make_parse(char *path) while ((nread = getline(&buf, &buf_size, stream)) != -1) { if (nread == -1) - errx(1, "Could not get line %lu", current_line.number); + { + char *err_msg; + sprintf(err_msg, "Could not get line %lu", current_line.number); + exit_on_error(GENERIC_ERR, err_msg); + } current_line.buffer = buf; current_line.length = nread; From 4013a4a154381e5f5d90a451a741505b3be6557e Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Wed, 29 Oct 2025 23:15:11 +0100 Subject: [PATCH 13/23] DEMENTOOOOOOR --- .gitignore | 2 +- AUTHORS | 1 + minimake/src/main.c | 13 +- minimake/src/minimake.c | 316 +++++++++++++++++++++------- minimake/tests/Makefile.syntax-test | 35 +++ minimake/tests/run.sh | 77 +++++++ 6 files changed, 360 insertions(+), 84 deletions(-) create mode 100644 minimake/tests/Makefile.syntax-test create mode 100644 minimake/tests/run.sh diff --git a/.gitignore b/.gitignore index 14c96f3..d535e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ *.class *.log *.core -minimake +minimake/minimake diff --git a/AUTHORS b/AUTHORS index 69b5c09..d5e33a8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,3 +3,4 @@ guillem.george Special thanks to - Timothée Battefort for the parser +- Amadéo Heaulme for the error handling diff --git a/minimake/src/main.c b/minimake/src/main.c index 07ee99d..4ace197 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -88,7 +88,7 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, return flags; } -char *getMakefile(struct list *files) +char *get_makefile(struct list *files) { struct list *file = files; int found = 0; @@ -98,11 +98,14 @@ char *getMakefile(struct list *files) { FILE *test = fopen(file->data, "r"); if (test != NULL) + { + fclose(test); found = 1; - - fclose(test); - if (!found) + } + else + { file = file->next; + } } char *res = NULL; @@ -119,7 +122,7 @@ int main(int argc, char **argv) struct list *rules; int flags = handle_args(argc, argv, &files, &rules); - char *filename = getMakefile(files); + char *filename = get_makefile(files); if (filename == NULL) errx(GENERIC_ERR, "No Makefile found"); diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 3e37319..fa8697b 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -14,12 +15,34 @@ #include "lists/lists.h" // Static variables -struct hash_map *variables = NULL; -struct hash_map *rules = NULL; + char *program_name; +struct hash_map *variables = NULL; +struct hash_map *rules = NULL; + +// Keeps track of variables and rules order +struct list *variables_list = NULL; +struct list *rules_list = NULL; + // ==== Misc ==== +#define FLAGS_FREE_RULES 1 +#define FLAGS_FREE_VARIABLES 2 + +static void list_deep_destroy(struct list *l) +{ + struct list *elt = l; + struct list *next_elt; + while (elt != NULL) + { + next_elt = elt->next; + free(elt->data); + free(elt); + elt = next_elt; + } +} + static void hashmap_deep_free(struct hash_map *hash_map) { if (hash_map == NULL) @@ -36,25 +59,26 @@ static void hashmap_deep_free(struct hash_map *hash_map) // Ok c moche mais eh, ça fonctionne if (hash_map == rules) { + // printf("DEBUG: %s\n", entry->key); struct rule *r = entry->value; free(r->name); - list_destroy(r->dependencies); - list_destroy(r->recipe); + list_deep_destroy(r->dependencies); + list_deep_destroy(r->recipe); free(r); - free(entry->key); + // free(entry->key); } - if (hash_map == variables) + else if (hash_map == variables) { - struct variable *v = entry->value; - free(v->name); - free(v->value); + // struct variable *v = entry->value; + // free(v->name); + // free(v->value); free(entry->key); free(entry->value); } else { - printf("DEBUG: attempting to free a generic hashmap"); + printf("DEBUG: attempting to free a generic hashmap\n"); free(entry->key); free(entry->value); } @@ -69,31 +93,84 @@ static void hashmap_deep_free(struct hash_map *hash_map) static void free_all() { + list_destroy(rules_list); + list_destroy(variables_list); hashmap_deep_free(rules); hashmap_deep_free(variables); } -// static void dump_database() -// { -// hashmap_dump(variables); -// hashmap_dump(rules); -// } - -static void exit_on_error(int status, char *message) +static void exit_on_error(int status, char *format, ...) { - char *full_msg; - int err = sprintf(full_msg, "%s: %s\n", program_name, message); - free(message); - if (err == -1) - exit(status); + // Print + va_list args; + va_start(args, format); + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + va_end(args); - write(STDERR_FILENO, full_msg, strlen(full_msg)); - - free(full_msg); free_all(); exit(status); } +static void dump_database() +{ + struct list *elt; + + // Dump variables + elt = variables_list; + puts("# variables"); + while (elt != NULL) + { + // Get var + char *val = hashmap_get(variables, elt->data); + if (val == NULL) + exit_on_error(GENERIC_ERR, + "Could not get variable '%s' in database", elt->data); + + // Print + char *key = elt->data; + printf("%s = %s\n", key, val); + + elt = elt->next; + } + // Dump rules + elt = rules_list; + puts("# rules"); + while (elt != NULL) + { + // Get rule + struct rule *rule = hashmap_get(rules, elt->data); + if (rule == NULL) + exit_on_error(GENERIC_ERR, "Could not get rule '%s' in database", + elt->data); + + // Print name + printf("(%s) :", rule->name); + + // Print dependencies + struct list *dep = rule->dependencies; + while (dep != NULL) + { + char *dep_str = dep->data; + printf(" [%s]", dep_str); + dep = dep->next; + } + putchar('\n'); + + // Print recipe + struct list *rcp = rule->recipe; + while (rcp != NULL) + { + char *rcp_str = rcp->data; + printf("\t'%s'\n", rcp_str); + rcp = rcp->next; + } + + elt = elt->next; + } +} + // ==== Parsing ==== // Registers a new rule in the hashmap @@ -107,15 +184,15 @@ static void register_rule(char *name, struct list *dependencies, rule->dependencies = dependencies; rule->recipe = recipe; - int err = hashmap_insert(variables, name, rule, NULL); + int err = hashmap_insert(rules, name, rule, NULL); if (!err) { - char *err_msg; - sprintf(err_msg, - "Internal Error: Couln't add entry for '%s' in the hashmap", - name); - exit_on_error(GENERIC_ERR, err_msg); + exit_on_error( + GENERIC_ERR, + "Internal Error: Couln't add entry for '%s' in the hashmap", name); } + + rules_list = list_append(rules_list, name); } // Registers a new variable in the hashmap @@ -126,12 +203,12 @@ static void register_variable(char *name, char *value) int err = hashmap_insert(variables, name, value, NULL); if (!err) { - char *err_msg; - sprintf(err_msg, - "Internal Error: Couln't add entry for '%s' in the hashmap", - name); - exit_on_error(GENERIC_ERR, err_msg); + exit_on_error( + GENERIC_ERR, + "Internal Error: Couln't add entry for '%s' in the hashmap", name); } + + variables_list = list_append(variables_list, name); } // Parse dependencies from buf and returns them inside a chained list @@ -161,12 +238,10 @@ static struct list *read_deps(struct line *l, size_t offset) if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' && buf[i] != '\n') { - char *err_msg; - sprintf( - err_msg, + exit_on_error( + GENERIC_ERR, "Unexpected character '%c' after rule declaration at %lu:%lu", buf[i], l->number, i); - exit_on_error(GENERIC_ERR, err_msg); } } @@ -202,13 +277,13 @@ static struct list *read_recipe(struct line *l) char *command = strdup(buf + 1); if (command == NULL) { - char *err_msg; - sprintf(err_msg, - "Internal error: couldn't duplicate string (%lu:1)", - l->number); - exit_on_error(GENERIC_ERR, err_msg); + exit_on_error( + GENERIC_ERR, + "Internal error: couldn't duplicate string (%lu:1)", + l->number); } + command[l->length - 2] = '\0'; res = list_append(res, command); } } @@ -218,13 +293,13 @@ static struct list *read_recipe(struct line *l) } // Reads the value after a variable declaration -static char *read_value(char *buf, size_t buf_size) +static char *read_value(char *buf, size_t buf_len) { size_t i = 0; size_t str_buf_size = STRING_BUFFER_SIZE; char *str_buf = malloc(sizeof(char) * str_buf_size); - while (i < buf_size && buf[i] != '\0' && buf[i] != '#') + while (i < buf_len && buf[i] != '\n' && buf[i] != '#' && buf[i] != '\0') { // Reallocate more space if necessary if (i >= str_buf_size - 1) @@ -232,11 +307,7 @@ static char *read_value(char *buf, size_t buf_size) str_buf_size += STRING_BUFFER_SIZE; str_buf = realloc(str_buf, str_buf_size); if (str_buf == NULL) - { - char *err_msg; - sprintf(err_msg, "Could not realloc"); - exit_on_error(GENERIC_ERR, err_msg); - } + exit_on_error(GENERIC_ERR, "Could not realloc"); } str_buf[i] = buf[i]; @@ -248,7 +319,104 @@ static char *read_value(char *buf, size_t buf_size) return str_buf; } -// static char *expand_variable(); +// Gets the corresponding value of the variable and stores it in *value +// Returns the number of skipped characters +// static size_t expand_variable(char *buf, size_t line_number, char **value) +// { +// size_t i = 0; +// if (buf[i] == '(') +// { +// // Read Value + +// size_t tmp_buf_size = STRING_BUFFER_SIZE; +// char *tmp_buf = malloc(sizeof(char) * tmp_buf_size); +// // TODO free on err + +// while (buf[i] != '\n' && buf[i] != '\0' && buf[i] != '#' +// && buf[i] != ')') +// { +// // Reallocate more space if necessary +// if (i >= tmp_buf_size - 1) +// { +// tmp_buf_size += STRING_BUFFER_SIZE; +// tmp_buf = realloc(tmp_buf, tmp_buf_size); +// if (tmp_buf == NULL) +// exit_on_error(GENERIC_ERR, "Could not realloc"); +// } + +// // Copy +// tmp_buf[i] = buf[i]; +// i++; +// } + +// // End +// tmp_buf[i] = '\0'; + +// // Check for mismatched parenthesis +// if (buf[i] == ')') +// { +// // Get corresponding value +// char *val = hashmap_get(variables, tmp_buf); +// if (val == NULL) +// { +// // Adds tmp_buf to the list of items to free +// variables_list = list_append(variables_list, tmp_buf); +// exit_on_error(GENERIC_ERR, +// "Could not find specified variable '%s' at +// line", tmp_buf, line_number); +// } + +// free(tmp_buf); +// *value = val; +// return i + 1; +// } +// else +// { +// free(tmp_buf); +// exit_on_error(GENERIC_ERR, "Mismatched parenthesis"); +// } +// } +// else +// { +// if (isblank(buf[i]) || isspace(buf[i])) +// { +// exit_on_error(GENERIC_ERR, +// "Special character '$' cannot be used alone"); +// } +// else if (buf[i] == '$') +// { +// *value = "$"; +// return 2; +// } +// else +// { +// // Get corresponding value +// char *tmp_buf = malloc(2 * sizeof(char)); +// if (tmp_buf == NULL) +// exit_on_error(GENERIC_ERR, +// "Could not allocate memory (seriously, not even +// " "two bytes)"); +// tmp_buf[0] = buf[i]; +// tmp_buf[1] = '\0'; +// char *val = hashmap_get(variables, tmp_buf); +// if (val == NULL) +// { +// // Adds tmp_buf to the list of items to free +// variables_list = list_append(variables_list, tmp_buf); +// exit_on_error(GENERIC_ERR, +// "Could not find specified variable '%s' at +// line", tmp_buf, line_number); +// } + +// free(tmp_buf); +// *value = val; +// return 2; +// } + +// return 1; // Discard warnings +// } +// return 1; // Discard warnings +// } // Takes a buffer containing the line to parse and it length // As well as the line number in the file for error handling @@ -274,14 +442,14 @@ static void parse_line(struct line *current_line) struct list *dependencies; struct list *recipe; char *value; - char *err_msg; // Definition type switch (buf[i]) { // Variable case '=': - value = read_value(buf + i, line_size); + i += skipblanks(buf + i + 1, line_size - i) + 1; + value = read_value(buf + i, line_size - i); register_variable(name, value); break; @@ -305,20 +473,18 @@ static void parse_line(struct line *current_line) case '#': if (name != NULL) { - sprintf( - err_msg, + exit_on_error( + GENERIC_ERR, "Unexpected character '%c' after declaration '%s' at line %lu", buf[i], name, current_line->number); - exit_on_error(GENERIC_ERR, err_msg); } - else - break; + break; default: - sprintf(err_msg, - "Unexpected character '%c' after declaration '%s' at line %lu", - buf[i], name, current_line->number); - exit_on_error(GENERIC_ERR, err_msg); + exit_on_error( + GENERIC_ERR, + "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); } // free(name); @@ -341,11 +507,7 @@ void make_parse(char *path) size_t buf_size = BUFFER_SIZE; char *buf = malloc(sizeof(char) * buf_size); if (buf == NULL) - { - char *err_msg; - sprintf(err_msg, "Could not allocate more memory"); - exit_on_error(GENERIC_ERR, err_msg); - } + exit_on_error(GENERIC_ERR, "Could not allocate more memory"); // Parse line by line ssize_t nread; @@ -355,11 +517,8 @@ void make_parse(char *path) while ((nread = getline(&buf, &buf_size, stream)) != -1) { if (nread == -1) - { - char *err_msg; - sprintf(err_msg, "Could not get line %lu", current_line.number); - exit_on_error(GENERIC_ERR, err_msg); - } + exit_on_error(GENERIC_ERR, "Could not get line %lu", + current_line.number); current_line.buffer = buf; current_line.length = nread; @@ -382,10 +541,11 @@ void make(char *path, int flags, char *argv0) { program_name = argv0; - if (flags & FLAGS_PRINT) - errx(GENERIC_ERR, "Not Implemented"); - make_parse(path); - // dump_database(); + + if (flags & FLAGS_PRINT) + // errx(GENERIC_ERR, "Not Implemented"); + dump_database(); + free_all(); } diff --git a/minimake/tests/Makefile.syntax-test b/minimake/tests/Makefile.syntax-test new file mode 100644 index 0000000..fff0427 --- /dev/null +++ b/minimake/tests/Makefile.syntax-test @@ -0,0 +1,35 @@ +SIMPLE_VAR = coucou +SIMPLE_VAR_COMMENT = the comment is gone # comment + +# the following line starts with a space then a tab + SPACES_BEFORE_TAB = var_beginning var_end + +sparse_rule: depa depb + + command 1 + + command 2 + + B = B_var_beginning B_var_end + +packed_rule: depa depb + command 1 + command 2 + +silent_rule: depa depb + @ command 1 + @command 2 + +rule_comment: depa depb # comment + +command_space_rule: depa depb + echo spaces before + echo spaces after + echo this is a # comment + +simple_rule: simple_dep + +no_dep_rule: + +variable_rule: beginning $(SIMPLE_VAR) end + echo "shouldn't be expanded: $(SIMPLE_VAR)" diff --git a/minimake/tests/run.sh b/minimake/tests/run.sh new file mode 100644 index 0000000..0fe1e07 --- /dev/null +++ b/minimake/tests/run.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +########################################### +# PIERRE PAGNOUX EXPERIENCE TESTSUITE # +########################################### + +#----------------- COLOR -----------------# +# 0 - No style | 1 - Bold +RED="\e[0;31m" +BRED="\e[1;31m" +GRN="\e[0;32m" +BGRN="\e[1;32m" +YEL="\e[0;33m" +BYEL="\e[1;33m" +BLU="\e[0;34m" +BBLU="\e[1;34m" +PUR="\e[0;35m" +BPUR="\e[1;35m" +CYA="\e[0;36m" +BCYA="\e[1;36m" +WHI="\e[0;37m" +BWHI="\e[1;37m" +GRE="\e[2;37m" + +#----------------- GLOBV -----------------# +ref_out=/tmp/ref_out.out +my_out=/tmp/my_out.out + +#----------------- TESTS -----------------# + +tit_wrap() +{ + echo -e $@$WHI +} + +func_test() +{ + tit_wrap - $PUR $1 + shift + printf $@ > $ref_out + ../../tinyprintf $@ > $my_out + + diff $ref_out $my_out > /tmp/null + + if [ $? -eq 0 ]; then + tit_wrap $GRN GOOD + else + tit_wrap $RED EXPECTED: $BRED$(cat $ref_out) \|$RED GOT: $BRED$(cat $my_out) + fi +} + +func_file() +{ + for file in *; do + if [ -f $file ]; then + func_test $file $(cat $file) + fi + done +} + +func_dir() +{ + cd tests + for dir in *; do + if [ -d $dir ]; then + tit_wrap == $dir == + cd $dir + func_file + cd .. + fi + done + cd .. +} + +# func_dir + +echo "Tests should be here" From c358562ecc709831dad989ee963a96c6e92e73e3 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Thu, 30 Oct 2025 21:14:53 +0100 Subject: [PATCH 14/23] EXPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnd --- minimake/src/lines/lines.c | 160 +++++++++- minimake/src/lines/lines.h | 4 + minimake/src/lists/lists.c | 13 + minimake/src/lists/lists.h | 14 +- minimake/src/main.c | 14 +- minimake/src/minimake.c | 428 +++++++++++++-------------- minimake/src/minimake.h | 4 + minimake/tests/Makefile2.syntax-test | 36 +++ 8 files changed, 443 insertions(+), 230 deletions(-) create mode 100644 minimake/tests/Makefile2.syntax-test diff --git a/minimake/src/lines/lines.c b/minimake/src/lines/lines.c index dcf0c19..fcd33e1 100644 --- a/minimake/src/lines/lines.c +++ b/minimake/src/lines/lines.c @@ -4,8 +4,11 @@ #include #include #include +#include #include +#include "../minimake.h" + // Helps to match a string (excludes blanks and special characters) int ischar(char c) { @@ -50,13 +53,7 @@ size_t readword(char *buf, size_t buf_len, char **word) while (i < buf_len && ischar(buf[i])) { // Reallocate more space if necessary - if (i >= res_size - 1) - { - res_size += STRING_BUFFER_SIZE; - res = realloc(res, res_size); - if (res == NULL) - errx(2, "Could not realloc"); - } + resize_buf(&res, res_size, i); res[i] = buf[i]; i++; @@ -73,3 +70,152 @@ size_t readword(char *buf, size_t buf_len, char **word) *word = res; return i; } + +// Resizes buf if index is greater or equal than buf_size-1 +// Returns new buffer size +size_t resize_buf(char **buf, size_t buf_size, size_t index) +{ + if (index >= buf_size - 1) + { + buf_size += BUFFER_SIZE; + *buf = realloc(*buf, buf_size); + if (buf == NULL) + drop(2, "Could not realloc"); + } + return buf_size; +} + +// Inserts str into base at index and returns the resulting string +// WARNING allocates the result on the heap, do not forget to free it +char *insert_str(char *base, char *str, size_t index) +{ + size_t res_size = BUFFER_SIZE; + char *res = malloc(res_size * sizeof(char)); + if (res == NULL) + drop(GENERIC_ERR, "Could not allocate more memory"); + + // Copy until index + size_t i = 0; + while (i < index) + { + // Reallocate more space if necessary + res_size = resize_buf(&res, res_size, i); + + res[i] = base[i]; + i++; + } + + // Copy str + size_t str_i = 0; + while (str[str_i] != '\0') + { + // Reallocate more space if necessary + res_size = resize_buf(&res, res_size, i); + + res[i] = str[str_i]; + i++; + str_i++; + } + + // Copy rest + while (base[i] != '\0') + { + // Reallocate more space if necessary + res_size = resize_buf(&res, res_size, i); + + res[i] = base[i]; + i++; + } + + res[i] = '\0'; + return res; +} + +// Appends str into base at index and stores the resulting string in *result +// Returns the size of the resulting buffer +// WARNING allocates the result on the heap, do not forget to free it +size_t append_str(char *base, char *str, size_t index, char **result) +{ + size_t res_size = BUFFER_SIZE; + char *res = malloc(res_size * sizeof(char)); + if (res == NULL) + drop(GENERIC_ERR, "Could not allocate more memory"); + + // Copy until index + size_t i = 0; + while (i < index) + { + // Reallocate more space if necessary + res_size = resize_buf(&res, res_size, i); + + res[i] = base[i]; + i++; + } + + // Copy str + size_t str_i = 0; + while (str[str_i] != '\0') + { + // Reallocate more space if necessary + res_size = resize_buf(&res, res_size, i); + + res[i] = str[str_i]; + i++; + str_i++; + } + res[i] = '\0'; + + *result = res; + return res_size; +} + +// Read word until ':', '=' and blanks and expands variable if any is found +// Returns the number of skipped chars and stores the resulting string in word +size_t read_declaration(struct line *line, size_t index, char **word) +{ + size_t i = index; + size_t buf_len = line->length; + char *buf = line->buffer; + + size_t res_size = STRING_BUFFER_SIZE; + char *res = malloc(sizeof(char) * res_size); + if (res == NULL) + drop(GENERIC_ERR, "Could not allocate more memory"); + + size_t res_i = 0; + while (i < buf_len && ischar(buf[i])) + { + // Reallocate more space if necessary + res_size = resize_buf(&res, res_size, i); + + // Expand variable + if (buf[i] == '$') + { + char *expanded_var; + char *tmp_res_buf; + i += expand_variable(line, i + 1, &expanded_var); + res_size = append_str(res, expanded_var, i, &tmp_res_buf); + // Replace res with res + expanded_variable + res_i = strlen(tmp_res_buf); + free(res); + // free(expanded_var); + res = tmp_res_buf; + continue; + } + + res[res_i] = buf[i]; + i++; + res_i++; + } + res[res_i] = '\0'; + + if (i == index) + { + free(res); + *word = NULL; + return i - index; + } + + *word = res; + return i - index; +} diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h index 01ace9d..081d305 100644 --- a/minimake/src/lines/lines.h +++ b/minimake/src/lines/lines.h @@ -22,5 +22,9 @@ int ischar(char c); int isblankline(struct line *l); int skipblanks(char *buf, size_t buf_len); size_t readword(char *buf, size_t buf_len, char **word); +size_t resize_buf(char** buf, size_t buf_size, size_t index); +char *insert_str(char *base, char *str, size_t index); +size_t read_declaration(struct line *line, size_t index, char **word); +size_t append_str(char *base, char *str, size_t index, char **res); #endif // LINES_H diff --git a/minimake/src/lists/lists.c b/minimake/src/lists/lists.c index aa355a1..e8a681b 100644 --- a/minimake/src/lists/lists.c +++ b/minimake/src/lists/lists.c @@ -331,3 +331,16 @@ struct list *list_split(struct list *list, size_t index) elt->next = NULL; return res; } + +void list_deep_destroy(struct list *l) +{ + struct list *elt = l; + struct list *next_elt; + while (elt != NULL) + { + next_elt = elt->next; + free(elt->data); + free(elt); + elt = next_elt; + } +} diff --git a/minimake/src/lists/lists.h b/minimake/src/lists/lists.h index a8f9b10..8c4114f 100644 --- a/minimake/src/lists/lists.h +++ b/minimake/src/lists/lists.h @@ -33,6 +33,12 @@ void list_print(struct list *list); */ void list_destroy(struct list *list); +/* +** Release the memory used by the list and its content +** Does nothing if `list` is `NULL`. +*/ +void list_deep_destroy(struct list *l); + /* ** Append a node containing `value` at the end of the list. ** Return `NULL` if an error occured. @@ -72,7 +78,7 @@ int list_find(struct list *list, void* value); ** Return `list2` if `list` is `NULL`. */ // START PROTO list_concat -struct list *list_concat(struct list *list, struct list *list2); +// struct list *list_concat(struct list *list, struct list *list2); // END PROTO list_concat /* @@ -80,7 +86,7 @@ struct list *list_concat(struct list *list, struct list *list2); ** Return the new list. */ // START PROTO list_sort -struct list *list_sort(struct list *list); +// struct list *list_sort(struct list *list); // END PROTO list_sort /* @@ -88,7 +94,7 @@ struct list *list_sort(struct list *list); ** Return the new list. */ // START PROTO list_reverse -struct list *list_reverse(struct list *list); +// struct list *list_reverse(struct list *list); // END PROTO list_reverse /* @@ -98,7 +104,7 @@ struct list *list_reverse(struct list *list); ** Return `NULL` if `list` is `NULL` or `index` is invalid. */ // START PROTO list_split -struct list *list_split(struct list *list, size_t index); +// struct list *list_split(struct list *list, size_t index); // END PROTO list_split #endif /* ! LIST_H */ diff --git a/minimake/src/main.c b/minimake/src/main.c index 4ace197..9ab0ada 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -40,7 +40,7 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, // Treat as rules for (int j = i; j < argc; j++) { - files = list_append(rules, argv[i]); + rules = list_append(rules, argv[i]); } *minimake_files = files; *minimake_rules = rules; @@ -50,6 +50,8 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, else if (strcmp(argv[i], "-h") == 0) { print_help(argv[0]); + list_destroy(files); + list_destroy(rules); exit(0); } // Custom file @@ -59,7 +61,7 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, if (i + 1 == argc || argv[i + 1][0] == '-') errx(INVALID_ARG, "No file specified after '-f'"); - files = list_prepend(files, argv[i]); + files = list_prepend(files, argv[i + 1]); } // Print else if (strcmp(argv[i], "-p") == 0) @@ -71,12 +73,14 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, { printf("Unknown option '%s'", argv[i]); print_help(argv[0]); + list_destroy(files); + list_destroy(rules); exit(INVALID_ARG); } } else // Rules { - files = list_append(rules, argv[i]); + rules = list_append(rules, argv[i]); } } @@ -112,7 +116,6 @@ char *get_makefile(struct list *files) if (found) res = file->data; - list_destroy(files); return res; } @@ -127,4 +130,7 @@ int main(int argc, char **argv) errx(GENERIC_ERR, "No Makefile found"); make(filename, flags, argv[0]); + list_destroy(files); + list_destroy(rules); + return 0; } diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index fa8697b..8bfee8e 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -27,22 +27,6 @@ struct list *rules_list = NULL; // ==== Misc ==== -#define FLAGS_FREE_RULES 1 -#define FLAGS_FREE_VARIABLES 2 - -static void list_deep_destroy(struct list *l) -{ - struct list *elt = l; - struct list *next_elt; - while (elt != NULL) - { - next_elt = elt->next; - free(elt->data); - free(elt); - elt = next_elt; - } -} - static void hashmap_deep_free(struct hash_map *hash_map) { if (hash_map == NULL) @@ -59,20 +43,15 @@ static void hashmap_deep_free(struct hash_map *hash_map) // Ok c moche mais eh, ça fonctionne if (hash_map == rules) { - // printf("DEBUG: %s\n", entry->key); struct rule *r = entry->value; free(r->name); list_deep_destroy(r->dependencies); list_deep_destroy(r->recipe); free(r); - // free(entry->key); } else if (hash_map == variables) { - // struct variable *v = entry->value; - // free(v->name); - // free(v->value); - + // printf("Att to free: %s\n", entry->key); free(entry->key); free(entry->value); } @@ -91,7 +70,7 @@ static void hashmap_deep_free(struct hash_map *hash_map) free(hash_map); } -static void free_all() +static void free_all(void) { list_destroy(rules_list); list_destroy(variables_list); @@ -99,78 +78,6 @@ static void free_all() hashmap_deep_free(variables); } -static void exit_on_error(int status, char *format, ...) -{ - // Print - va_list args; - va_start(args, format); - fprintf(stderr, "%s: ", program_name); - vfprintf(stderr, format, args); - fprintf(stderr, "\n"); - va_end(args); - - free_all(); - exit(status); -} - -static void dump_database() -{ - struct list *elt; - - // Dump variables - elt = variables_list; - puts("# variables"); - while (elt != NULL) - { - // Get var - char *val = hashmap_get(variables, elt->data); - if (val == NULL) - exit_on_error(GENERIC_ERR, - "Could not get variable '%s' in database", elt->data); - - // Print - char *key = elt->data; - printf("%s = %s\n", key, val); - - elt = elt->next; - } - // Dump rules - elt = rules_list; - puts("# rules"); - while (elt != NULL) - { - // Get rule - struct rule *rule = hashmap_get(rules, elt->data); - if (rule == NULL) - exit_on_error(GENERIC_ERR, "Could not get rule '%s' in database", - elt->data); - - // Print name - printf("(%s) :", rule->name); - - // Print dependencies - struct list *dep = rule->dependencies; - while (dep != NULL) - { - char *dep_str = dep->data; - printf(" [%s]", dep_str); - dep = dep->next; - } - putchar('\n'); - - // Print recipe - struct list *rcp = rule->recipe; - while (rcp != NULL) - { - char *rcp_str = rcp->data; - printf("\t'%s'\n", rcp_str); - rcp = rcp->next; - } - - elt = elt->next; - } -} - // ==== Parsing ==== // Registers a new rule in the hashmap @@ -187,9 +94,8 @@ static void register_rule(char *name, struct list *dependencies, int err = hashmap_insert(rules, name, rule, NULL); if (!err) { - exit_on_error( - GENERIC_ERR, - "Internal Error: Couln't add entry for '%s' in the hashmap", name); + drop(GENERIC_ERR, + "Internal Error: Couln't add entry for '%s' in the hashmap", name); } rules_list = list_append(rules_list, name); @@ -203,9 +109,8 @@ static void register_variable(char *name, char *value) int err = hashmap_insert(variables, name, value, NULL); if (!err) { - exit_on_error( - GENERIC_ERR, - "Internal Error: Couln't add entry for '%s' in the hashmap", name); + drop(GENERIC_ERR, + "Internal Error: Couln't add entry for '%s' in the hashmap", name); } variables_list = list_append(variables_list, name); @@ -238,10 +143,9 @@ static struct list *read_deps(struct line *l, size_t offset) if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' && buf[i] != '\n') { - exit_on_error( - GENERIC_ERR, - "Unexpected character '%c' after rule declaration at %lu:%lu", - buf[i], l->number, i); + drop(GENERIC_ERR, + "Unexpected character '%c' after rule declaration at %lu:%lu", + buf[i], l->number, i); } } @@ -274,16 +178,17 @@ static struct list *read_recipe(struct line *l) } else // Add recipe to list { - char *command = strdup(buf + 1); + size_t offset = 1 + skipblanks(buf + 1, l->length - 1); + + char *command = strdup(buf + offset); if (command == NULL) { - exit_on_error( - GENERIC_ERR, - "Internal error: couldn't duplicate string (%lu:1)", - l->number); + drop(GENERIC_ERR, + "Internal error: couldn't duplicate string (%lu:1)", + l->number); } - command[l->length - 2] = '\0'; + command[l->length - offset - 1] = '\0'; res = list_append(res, command); } } @@ -292,8 +197,10 @@ static struct list *read_recipe(struct line *l) return res; } +// === Variable Expansion === + // Reads the value after a variable declaration -static char *read_value(char *buf, size_t buf_len) +static char *read_variable_value(char *buf, size_t buf_len) { size_t i = 0; size_t str_buf_size = STRING_BUFFER_SIZE; @@ -307,7 +214,7 @@ static char *read_value(char *buf, size_t buf_len) str_buf_size += STRING_BUFFER_SIZE; str_buf = realloc(str_buf, str_buf_size); if (str_buf == NULL) - exit_on_error(GENERIC_ERR, "Could not realloc"); + drop(GENERIC_ERR, "Could not realloc"); } str_buf[i] = buf[i]; @@ -319,104 +226,123 @@ static char *read_value(char *buf, size_t buf_len) return str_buf; } +// Reads variable name from buf until ')' and stores it into *result +// Returns its length on success and -1 on fail +// WARNING allocates memory on the heap, free *result after use +static size_t read_variable_name(struct line *line, size_t index, char **result) +{ + size_t i = index; + char *buf = line->buffer; + + // Alloc var_buf + size_t var_buf_size = STRING_BUFFER_SIZE; + char *var_buf = malloc(sizeof(char) * var_buf_size); + if (var_buf == NULL) + drop(GENERIC_ERR, "Could not allocate more memory"); + + size_t var_i = 0; + while (buf[i] != '\n' && buf[i] != '\0' && buf[i] != '#' && buf[i] != ')') + { + // Reallocate more space if necessary + var_buf_size = resize_buf(&var_buf, var_buf_size, i); + + // Copy + var_buf[var_i] = buf[i]; + i++; + var_i++; + } + var_buf[var_i] = '\0'; + + // Mismatched parenthesis + if (buf[i] != ')') + { + free(var_buf); + *result = NULL; + return 0; + } + + i += 2; + *result = var_buf; + return i - index; +} + +// Searches for variable in database and returns its value +// if no value is found, it drops an error and exit the program +// WARNING variable must be allocated on the heap as this function may attempt +// to free it +// NOTE Takes line_number to print an helpful error message +static char *get_variable_value(char *variable_name, size_t line_number) +{ + char *value = hashmap_get(variables, variable_name); + if (value == NULL) + { + // Adds tmp_buf to the list of items to free + variables_list = list_append(variables_list, variable_name); + drop(GENERIC_ERR, "Could not find specified variable '%s' at line %lu", + variable_name, line_number); + } + + free(variable_name); + return value; +} + // Gets the corresponding value of the variable and stores it in *value // Returns the number of skipped characters -// static size_t expand_variable(char *buf, size_t line_number, char **value) -// { -// size_t i = 0; -// if (buf[i] == '(') -// { -// // Read Value +size_t expand_variable(struct line *line, size_t index, char **value) +{ + size_t i = index; + char *buf = line->buffer; -// size_t tmp_buf_size = STRING_BUFFER_SIZE; -// char *tmp_buf = malloc(sizeof(char) * tmp_buf_size); -// // TODO free on err + // Name in parenthesis + if (buf[i] == '(') + { + // Read variable + char *var_name; + i++; + i += read_variable_name(line, i, &var_name); + if (var_name == NULL) + drop(GENERIC_ERR, "Mismatched parenthesis at %lu:%lu", i, + line->number); -// while (buf[i] != '\n' && buf[i] != '\0' && buf[i] != '#' -// && buf[i] != ')') -// { -// // Reallocate more space if necessary -// if (i >= tmp_buf_size - 1) -// { -// tmp_buf_size += STRING_BUFFER_SIZE; -// tmp_buf = realloc(tmp_buf, tmp_buf_size); -// if (tmp_buf == NULL) -// exit_on_error(GENERIC_ERR, "Could not realloc"); -// } + // Get corresponding value + *value = get_variable_value(var_name, line->number); -// // Copy -// tmp_buf[i] = buf[i]; -// i++; -// } + // Return + return i - index; + } + else // Single char variable + { + // '$ ' + if (isblank(buf[i]) || isspace(buf[i])) + drop(2, "Unauthorized character '%c' at %lu:%lu", buf[i], + line->number, i); + else + { + // Allocate temporary buffer to hold variable name + char *var_name = malloc(2 * sizeof(char)); + if (var_name == NULL) + // Seriously, not even two bytes + drop(GENERIC_ERR, "Could not allocate memory"); -// // End -// tmp_buf[i] = '\0'; + var_name[0] = buf[i]; + var_name[1] = '\0'; -// // Check for mismatched parenthesis -// if (buf[i] == ')') -// { -// // Get corresponding value -// char *val = hashmap_get(variables, tmp_buf); -// if (val == NULL) -// { -// // Adds tmp_buf to the list of items to free -// variables_list = list_append(variables_list, tmp_buf); -// exit_on_error(GENERIC_ERR, -// "Could not find specified variable '%s' at -// line", tmp_buf, line_number); -// } + // Escape '$$' + if (buf[i] == '$') + { + *value = var_name; + return 2; + } -// free(tmp_buf); -// *value = val; -// return i + 1; -// } -// else -// { -// free(tmp_buf); -// exit_on_error(GENERIC_ERR, "Mismatched parenthesis"); -// } -// } -// else -// { -// if (isblank(buf[i]) || isspace(buf[i])) -// { -// exit_on_error(GENERIC_ERR, -// "Special character '$' cannot be used alone"); -// } -// else if (buf[i] == '$') -// { -// *value = "$"; -// return 2; -// } -// else -// { -// // Get corresponding value -// char *tmp_buf = malloc(2 * sizeof(char)); -// if (tmp_buf == NULL) -// exit_on_error(GENERIC_ERR, -// "Could not allocate memory (seriously, not even -// " "two bytes)"); -// tmp_buf[0] = buf[i]; -// tmp_buf[1] = '\0'; -// char *val = hashmap_get(variables, tmp_buf); -// if (val == NULL) -// { -// // Adds tmp_buf to the list of items to free -// variables_list = list_append(variables_list, tmp_buf); -// exit_on_error(GENERIC_ERR, -// "Could not find specified variable '%s' at -// line", tmp_buf, line_number); -// } + // Get corresponding value + *value = get_variable_value(var_name, line->number); + } -// free(tmp_buf); -// *value = val; -// return 2; -// } + return 2; + } +} -// return 1; // Discard warnings -// } -// return 1; // Discard warnings -// } +// ================= // Takes a buffer containing the line to parse and it length // As well as the line number in the file for error handling @@ -431,7 +357,8 @@ static void parse_line(struct line *current_line) // Read name char *name; - i += readword(buf + i, line_size - i, &name); + // i += readword(buf + i, line_size - i, &name); + i += read_declaration(current_line, i, &name); // if (name == NULL) // errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu", // current_line->number, i); @@ -449,7 +376,7 @@ static void parse_line(struct line *current_line) // Variable case '=': i += skipblanks(buf + i + 1, line_size - i) + 1; - value = read_value(buf + i, line_size - i); + value = read_variable_value(buf + i, line_size - i); register_variable(name, value); break; @@ -473,18 +400,16 @@ static void parse_line(struct line *current_line) case '#': if (name != NULL) { - exit_on_error( - GENERIC_ERR, - "Unexpected character '%c' after declaration '%s' at line %lu", - buf[i], name, current_line->number); + drop(GENERIC_ERR, + "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); } break; default: - exit_on_error( - GENERIC_ERR, - "Unexpected character '%c' after declaration '%s' at line %lu", - buf[i], name, current_line->number); + drop(GENERIC_ERR, + "Unexpected character '%c' after declaration '%s' at line %lu", + buf[i], name, current_line->number); } // free(name); @@ -507,7 +432,7 @@ void make_parse(char *path) size_t buf_size = BUFFER_SIZE; char *buf = malloc(sizeof(char) * buf_size); if (buf == NULL) - exit_on_error(GENERIC_ERR, "Could not allocate more memory"); + drop(GENERIC_ERR, "Could not allocate more memory"); // Parse line by line ssize_t nread; @@ -517,8 +442,7 @@ void make_parse(char *path) while ((nread = getline(&buf, &buf_size, stream)) != -1) { if (nread == -1) - exit_on_error(GENERIC_ERR, "Could not get line %lu", - current_line.number); + drop(GENERIC_ERR, "Could not get line %lu", current_line.number); current_line.buffer = buf; current_line.length = nread; @@ -535,6 +459,9 @@ void make_parse(char *path) // ==== Runtime ==== +// static void make_run(void) +// {} + // ==== MAKE ==== void make(char *path, int flags, char *argv0) @@ -544,8 +471,79 @@ void make(char *path, int flags, char *argv0) make_parse(path); if (flags & FLAGS_PRINT) - // errx(GENERIC_ERR, "Not Implemented"); dump_database(); free_all(); } + +// Prints an error message before exiting gracefully (by freeing all variables) +void drop(int status, char *format, ...) +{ + // Print + va_list args; + va_start(args, format); + fprintf(stderr, "%s: ", program_name); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + va_end(args); + + free_all(); + exit(status); +} + +void dump_database(void) +{ + struct list *elt; + + // Dump variables + elt = variables_list; + puts("# variables"); + while (elt != NULL) + { + // Get var + char *val = hashmap_get(variables, elt->data); + if (val == NULL) + drop(GENERIC_ERR, "Could not get variable '%s' in database", + elt->data); + + // Print + char *key = elt->data; + printf("%s = %s\n", key, val); + + elt = elt->next; + } + // Dump rules + elt = rules_list; + puts("# rules"); + while (elt != NULL) + { + // Get rule + struct rule *rule = hashmap_get(rules, elt->data); + if (rule == NULL) + drop(GENERIC_ERR, "Could not get rule '%s' in database", elt->data); + + // Print name + printf("(%s) :", rule->name); + + // Print dependencies + struct list *dep = rule->dependencies; + while (dep != NULL) + { + char *dep_str = dep->data; + printf(" [%s]", dep_str); + dep = dep->next; + } + putchar('\n'); + + // Print recipe + struct list *rcp = rule->recipe; + while (rcp != NULL) + { + char *rcp_str = rcp->data; + printf("\t'%s'\n", rcp_str); + rcp = rcp->next; + } + + elt = elt->next; + } +} diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index ccd5f08..98f4ccb 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -19,6 +19,7 @@ #include #include "lists/lists.h" +#include "lines/lines.h" // Holds variable information // WARNING its values must be freed after use @@ -39,5 +40,8 @@ struct rule void make(char *path, int flags, char* program_name); void make_parse(char *path); +void drop(int status, char *format, ...); +void dump_database(void); +size_t expand_variable(struct line *line, size_t index, char **value); #endif // ! MINIMAKE_H diff --git a/minimake/tests/Makefile2.syntax-test b/minimake/tests/Makefile2.syntax-test new file mode 100644 index 0000000..ac3c606 --- /dev/null +++ b/minimake/tests/Makefile2.syntax-test @@ -0,0 +1,36 @@ +SIMPLE_VAR = coucou +SIMPLE_VAR_COMMENT = the comment is gone # comment +$(SIMPLE_VAR) = 1 + +# the following line starts with a space then a tab + SPACES_BEFORE_TAB = var_beginning var_end + +sparse_rule: depa depb + + command 1 + + command 2 + + B = B_var_beginning B_var_end + +packed_rule: depa depb + command 1 + command 2 + +silent_rule: depa depb + @ command 1 + @command 2 + +rule_comment: depa depb # comment + +command_space_rule: depa depb + echo spaces before + echo spaces after + echo this is a # comment + +simple_rule: simple_dep + +no_dep_rule: + +variable_rule: beginning $(SIMPLE_VAR) end + echo "shouldn't be expanded: $(SIMPLE_VAR)" From a8ca407247dac93024c549aac7fab333cb265d72 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 31 Oct 2025 21:34:09 +0100 Subject: [PATCH 15/23] JUSTOCASOU --- minimake/Makefile | 2 +- minimake/src/files/files.c | 99 +++++++++++++++++++++++++++++++++++ minimake/src/files/files.h | 14 +++++ minimake/src/main.c | 38 +++----------- minimake/src/minimake.c | 95 ++++++++++++++++++++++++++++++--- minimake/src/minimake.h | 7 +-- minimake/tests/Makefile.test3 | 1 + minimake/tests/Makefile.test4 | 5 ++ 8 files changed, 220 insertions(+), 41 deletions(-) create mode 100644 minimake/src/files/files.c create mode 100644 minimake/src/files/files.h create mode 100644 minimake/tests/Makefile.test3 create mode 100644 minimake/tests/Makefile.test4 diff --git a/minimake/Makefile b/minimake/Makefile index c12a97e..db29234 100644 --- a/minimake/Makefile +++ b/minimake/Makefile @@ -7,7 +7,7 @@ DBG_LDFLAGS= -fsanitize=address SRC_DIR = src -LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c +LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c files/files.c MAIN_SRCS = main.c minimake.c # SRCS = $(patsubst %,$(SRC_DIR)/%, $(MAIN_SRCS)) diff --git a/minimake/src/files/files.c b/minimake/src/files/files.c new file mode 100644 index 0000000..2d46ecb --- /dev/null +++ b/minimake/src/files/files.c @@ -0,0 +1,99 @@ +#include "files.h" + +#include +#include +#include +#include +#include +#include + +// #include "../lines/lines.h" + +char *get_makefile(struct list *files) +{ + struct list *file = files; + int found = 0; + + // Test file presence + while (file != NULL && !found) + { + FILE *test = fopen(file->data, "r"); + if (test != NULL) + { + fclose(test); + found = 1; + } + else + { + file = file->next; + } + } + + char *res = NULL; + if (found) + res = file->data; + + return res; +} + +ssize_t get_file_lastmodiftime(char *filename) +{ + struct stat stat; + if (lstat(filename, &stat) == -1) + return -1; + return stat.st_mtime; +} + +// Calls a shell that will run the given command +// It will first print the command to run unless the it starts with '@' +// Returns the return code o the command or -1 if a syscall fails +int run_command(char *command) +{ + if (command[0] == '@') + command++; + else + { + puts(command); + } + + // Just in case + fflush(stdout); + fflush(stderr); + + // char *executable; + // size_t args_offset = readword(command, strlen(command), &executable); + + int id = fork(); + if (id < 0) + { + perror("fork"); + return -1; + } + + if (id == 0) + { + int res = 0; + wait(&res); + // printf("Got return code: %d\n", res); + return res; + } + else + { + int res = execl("/bin/sh", "(make)", "-c", command, NULL); + return res; + } +} + +// Returns 1 if file exists (and is readable), 0 otherwise +int file_exists(char *filename) +{ + if (filename == NULL) + return 0; + + FILE *test = fopen(filename, "r"); + if (test == NULL) + return 0; + + fclose(test); + return 1; +} diff --git a/minimake/src/files/files.h b/minimake/src/files/files.h new file mode 100644 index 0000000..da7c555 --- /dev/null +++ b/minimake/src/files/files.h @@ -0,0 +1,14 @@ +#ifndef FILES_H +#define FILES_H + +#define _XOPEN_SOURCE 500 + +#include "../lists/lists.h" +#include + +char* get_makefile(struct list *files); +ssize_t get_file_lastmodiftime(char* filename); +int run_command(char *command); +int file_exists(char *filename); + +#endif // FILES_H diff --git a/minimake/src/main.c b/minimake/src/main.c index 9ab0ada..ec0473f 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -5,6 +5,7 @@ #include #include +#include "files/files.h" #include "lists/lists.h" #include "minimake.h" @@ -58,10 +59,12 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, else if (strcmp(argv[i], "-f") == 0) { flags |= FLAGS_CUSTOM_FILE; - if (i + 1 == argc || argv[i + 1][0] == '-') + i++; + + if (i == argc || argv[i][0] == '-') errx(INVALID_ARG, "No file specified after '-f'"); - files = list_prepend(files, argv[i + 1]); + files = list_prepend(files, argv[i]); } // Print else if (strcmp(argv[i], "-p") == 0) @@ -92,33 +95,6 @@ static int handle_args(int argc, char **argv, struct list **minimake_files, return flags; } -char *get_makefile(struct list *files) -{ - struct list *file = files; - int found = 0; - - // Test file presence - while (file != NULL && !found) - { - FILE *test = fopen(file->data, "r"); - if (test != NULL) - { - fclose(test); - found = 1; - } - else - { - file = file->next; - } - } - - char *res = NULL; - if (found) - res = file->data; - - return res; -} - int main(int argc, char **argv) { struct list *files; @@ -129,8 +105,8 @@ int main(int argc, char **argv) if (filename == NULL) errx(GENERIC_ERR, "No Makefile found"); - make(filename, flags, argv[0]); + int res = make(filename, rules, argv[0], flags); list_destroy(files); list_destroy(rules); - return 0; + return res; } diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 8bfee8e..675702c 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -10,6 +10,7 @@ #include #include +#include "files/files.h" #include "hash_maps/hash_maps.h" #include "lines/lines.h" #include "lists/lists.h" @@ -459,21 +460,103 @@ void make_parse(char *path) // ==== Runtime ==== -// static void make_run(void) -// {} +// Expands and run a specified rule +static int run_rule(struct rule *rule) +{ + struct list *commands = rule->recipe; + struct list *dependencies = rule->dependencies; + + // Expand dependencies variables + // TODO + + // Build dependencies + while (dependencies != NULL) + { + // Check file existence + if (!file_exists(dependencies->data)) + { + // Check rule existence instead + struct rule *dep_rule = hashmap_get(rules, dependencies->data); + if (dep_rule != NULL) + { + int res = run_rule(dep_rule); + if (res != 0) // Exit on error + return res; + } + else + { + drop(GENERIC_ERR, "No rule to make target '%s'", + dependencies->data); + } + } + } + + while (commands != NULL) + { + // Expand command variables + // TODO + + // Run + int res = run_command(commands->data); + if (res != 0) // Exit on error + return res; + + commands = commands->next; + } + + return 0; +} + +// Run the given rules after parsing +int make_run(struct list *given_rules) +{ + if (given_rules == NULL) + { + // No rule specified => run first rule found in the Makefile + if (rules_list == NULL) + drop(GENERIC_ERR, "No targets"); + + struct rule *full_rule = hashmap_get(rules, rules_list->data); + if (full_rule == NULL) + drop(GENERIC_ERR, + "Internal error: Could not retrieve target '%s' in database", + rules_list->data); + + return run_rule(full_rule); + } + else + { + while (given_rules != NULL) + { + struct rule *full_rule = hashmap_get(rules, given_rules->data); + if (full_rule == NULL) + drop(GENERIC_ERR, "No rule to make target '%s'", + given_rules->data); + + int res = run_rule(full_rule); + if (res != 0) + return res; + + given_rules = given_rules->next; + } + return 0; + } +} // ==== MAKE ==== -void make(char *path, int flags, char *argv0) +int make(char *path, struct list *rules, char *exec_name, int flags) { - program_name = argv0; + program_name = exec_name; make_parse(path); if (flags & FLAGS_PRINT) dump_database(); + int status = make_run(rules); free_all(); + return status; } // Prints an error message before exiting gracefully (by freeing all variables) @@ -482,9 +565,9 @@ void drop(int status, char *format, ...) // Print va_list args; va_start(args, format); - fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "%s: *** ", program_name); vfprintf(stderr, format, args); - fprintf(stderr, "\n"); + fprintf(stderr, ". Stop.\n"); va_end(args); free_all(); diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index 98f4ccb..f6ed073 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -10,8 +10,8 @@ #define FLAGS_PRINT 2 // Default values -#define DEFAULT_MAKEFILE "Makefile" -#define DEFAULT_MAKEFILE_2 "makefile" +#define DEFAULT_MAKEFILE "makefile" +#define DEFAULT_MAKEFILE_2 "Makefile" #define BUFFER_SIZE 1024 #define HASHMAP_SIZE 32 @@ -38,8 +38,9 @@ struct rule struct list *recipe; }; -void make(char *path, int flags, char* program_name); +int make(char *path, struct list* rules, char *argv0, int flags); void make_parse(char *path); +int make_run(struct list *rules); void drop(int status, char *format, ...); void dump_database(void); size_t expand_variable(struct line *line, size_t index, char **value); diff --git a/minimake/tests/Makefile.test3 b/minimake/tests/Makefile.test3 new file mode 100644 index 0000000..7a42836 --- /dev/null +++ b/minimake/tests/Makefile.test3 @@ -0,0 +1 @@ +VAR = 1 diff --git a/minimake/tests/Makefile.test4 b/minimake/tests/Makefile.test4 new file mode 100644 index 0000000..45ee423 --- /dev/null +++ b/minimake/tests/Makefile.test4 @@ -0,0 +1,5 @@ +rule1: + echo Toto + +rule2: + @echo Toto From 1efc35a59ec7c8617378e5765c61e7c831d8c640 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 31 Oct 2025 22:31:08 +0100 Subject: [PATCH 16/23] JUSTOCASOUUUU --- minimake/Makefile | 8 +++--- minimake/src/files/files.h | 7 ++--- minimake/src/hash_maps/hash_maps.h | 2 +- minimake/src/lines/lines.c | 42 ++++++++++++++++++++++++++++++ minimake/src/lines/lines.h | 12 ++++----- minimake/src/lists/.gitignore | 1 - minimake/src/lists/lists.h | 16 ++++++------ minimake/src/minimake.c | 5 ++-- minimake/src/minimake.h | 6 ++--- 9 files changed, 70 insertions(+), 29 deletions(-) delete mode 100644 minimake/src/lists/.gitignore diff --git a/minimake/Makefile b/minimake/Makefile index db29234..cb0ae0a 100644 --- a/minimake/Makefile +++ b/minimake/Makefile @@ -21,10 +21,10 @@ $(TARGET): $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) @echo $(OBJS) -debug: CFLAGS += $(DBG_CFLAGS) -debug: LDFLAGS += $(DBG_LDFLAGS) -debug: $(OBJS) - $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) +# debug: CFLAGS += $(DBG_CFLAGS) +# debug: LDFLAGS += $(DBG_LDFLAGS) +# debug: $(OBJS) +# $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) check: dash ./tests/run.sh diff --git a/minimake/src/files/files.h b/minimake/src/files/files.h index da7c555..d4893c3 100644 --- a/minimake/src/files/files.h +++ b/minimake/src/files/files.h @@ -3,11 +3,12 @@ #define _XOPEN_SOURCE 500 -#include "../lists/lists.h" #include -char* get_makefile(struct list *files); -ssize_t get_file_lastmodiftime(char* filename); +#include "../lists/lists.h" + +char *get_makefile(struct list *files); +ssize_t get_file_lastmodiftime(char *filename); int run_command(char *command); int file_exists(char *filename); diff --git a/minimake/src/hash_maps/hash_maps.h b/minimake/src/hash_maps/hash_maps.h index 97a84da..634c993 100644 --- a/minimake/src/hash_maps/hash_maps.h +++ b/minimake/src/hash_maps/hash_maps.h @@ -24,7 +24,7 @@ struct hash_map size_t hash(const char *str); struct hash_map *hashmap_init(size_t size); bool hashmap_insert(struct hash_map *hash_map, char *key, void *value, - bool *updated); + bool *updated); void hashmap_free(struct hash_map *hash_map); void hashmap_dump(struct hash_map *hash_map); void *hashmap_get(const struct hash_map *hash_map, char *key); diff --git a/minimake/src/lines/lines.c b/minimake/src/lines/lines.c index fcd33e1..238b576 100644 --- a/minimake/src/lines/lines.c +++ b/minimake/src/lines/lines.c @@ -219,3 +219,45 @@ size_t read_declaration(struct line *line, size_t index, char **word) *word = res; return i - index; } + +// Takes a string, expands its variables and returns the resulting buffer +// WARNING allocates the result on the heap, free result after use +char *expand_str(char *str) +{ + size_t str_i = 0; + size_t buf_i = 0; + size_t buf_size = BUFFER_SIZE; + char *buf = malloc(BUFFER_SIZE * sizeof(char)); + while (str[str_i] != '\0') + { + // Reallocate more space if necessary + resize_buf(&buf, buf_size, buf_i); + + // Expand variable + if (buf[buf_i] == '$') + { + // Temporary variables + char *expanded_var; + char *tmp_res_buf; + struct line false_line = { + .buffer = buf, .file_stream = NULL, .length = 0, .number = 0 + }; + str_i += expand_variable(&false_line, str_i + 1, &expanded_var); + buf_size = append_str(buf, expanded_var, buf_i, &tmp_res_buf); + // Replace buf with buf + expanded_variable + buf_i = strlen(tmp_res_buf); + free(buf); + // free(expanded_var); + buf = tmp_res_buf; + continue; + } + + buf[buf_i] = str[str_i]; + buf_i++; + str_i++; + } + + buf[buf_i] = '\0'; + + return buf; +} diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h index 081d305..5782327 100644 --- a/minimake/src/lines/lines.h +++ b/minimake/src/lines/lines.h @@ -4,25 +4,25 @@ #define STRING_BUFFER_SIZE 32 #include -#include #include +#include // Holds line information // Exists only because of EPITA's annoying 4 parameters limit // WARNING buffer must be freed after use struct line { - char* buffer; // Line content - ssize_t length; // Line length - size_t number; // Line number in file - FILE* file_stream; // Full file stream + char *buffer; // Line content + ssize_t length; // Line length + size_t number; // Line number in file + FILE *file_stream; // Full file stream }; int ischar(char c); int isblankline(struct line *l); int skipblanks(char *buf, size_t buf_len); size_t readword(char *buf, size_t buf_len, char **word); -size_t resize_buf(char** buf, size_t buf_size, size_t index); +size_t resize_buf(char **buf, size_t buf_size, size_t index); char *insert_str(char *base, char *str, size_t index); size_t read_declaration(struct line *line, size_t index, char **word); size_t append_str(char *base, char *str, size_t index, char **res); diff --git a/minimake/src/lists/.gitignore b/minimake/src/lists/.gitignore deleted file mode 100644 index 3309b20..0000000 --- a/minimake/src/lists/.gitignore +++ /dev/null @@ -1 +0,0 @@ -list.c diff --git a/minimake/src/lists/lists.h b/minimake/src/lists/lists.h index 8c4114f..116bd1f 100644 --- a/minimake/src/lists/lists.h +++ b/minimake/src/lists/lists.h @@ -1,11 +1,11 @@ -#ifndef LIST_H -#define LIST_H +#ifndef LISTS_H +#define LISTS_H #include struct list { - void* data; + void *data; struct list *next; }; @@ -13,7 +13,7 @@ struct list ** Insert a node containing `value` at the beginning of the list. ** Return `NULL` if an error occured. */ -struct list *list_prepend(struct list *list, void* value); +struct list *list_prepend(struct list *list, void *value); /* ** Return the lenght of the list. @@ -44,7 +44,7 @@ void list_deep_destroy(struct list *l); ** Return `NULL` if an error occured. */ // START PROTO list_append -struct list *list_append(struct list *list, void* value); +struct list *list_append(struct list *list, void *value); // END PROTO list_append /* @@ -54,7 +54,7 @@ struct list *list_append(struct list *list, void* value); ** Return `NULL` if an error occured. */ // START PROTO list_insert -struct list *list_insert(struct list *list, void* value, size_t index); +struct list *list_insert(struct list *list, void *value, size_t index); // END PROTO list_insert /* @@ -70,7 +70,7 @@ struct list *list_remove(struct list *list, size_t index); ** Return `-1` if nothing is found. */ // START PROTO list_find -int list_find(struct list *list, void* value); +int list_find(struct list *list, void *value); // END PROTO list_find /* @@ -107,4 +107,4 @@ int list_find(struct list *list, void* value); // struct list *list_split(struct list *list, size_t index); // END PROTO list_split -#endif /* ! LIST_H */ +#endif /* ! LISTS_H */ diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 675702c..c28aed3 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -466,12 +466,11 @@ static int run_rule(struct rule *rule) struct list *commands = rule->recipe; struct list *dependencies = rule->dependencies; - // Expand dependencies variables - // TODO - // Build dependencies while (dependencies != NULL) { + // Expand variables + // Check file existence if (!file_exists(dependencies->data)) { diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index f6ed073..7bb5f39 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -18,8 +18,8 @@ #include #include -#include "lists/lists.h" #include "lines/lines.h" +#include "lists/lists.h" // Holds variable information // WARNING its values must be freed after use @@ -33,12 +33,12 @@ struct variable // WARNING its values must be freed after use struct rule { - char* name; + char *name; struct list *dependencies; struct list *recipe; }; -int make(char *path, struct list* rules, char *argv0, int flags); +int make(char *path, struct list *rules, char *argv0, int flags); void make_parse(char *path); int make_run(struct list *rules); void drop(int status, char *format, ...); From 4b3df88e8a3268c2bb20329639d1031363952f86 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 31 Oct 2025 22:48:30 +0100 Subject: [PATCH 17/23] fixed print --- minimake/src/minimake.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index c28aed3..468ce23 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -488,6 +488,8 @@ static int run_rule(struct rule *rule) dependencies->data); } } + + dependencies = dependencies->next; } while (commands != NULL) @@ -550,9 +552,15 @@ int make(char *path, struct list *rules, char *exec_name, int flags) make_parse(path); + // Print if (flags & FLAGS_PRINT) + { dump_database(); + free_all(); + return 0; + } + // Run int status = make_run(rules); free_all(); return status; @@ -590,7 +598,7 @@ void dump_database(void) // Print char *key = elt->data; - printf("%s = %s\n", key, val); + printf("'%s' = '%s'\n", key, val); elt = elt->next; } @@ -605,7 +613,7 @@ void dump_database(void) drop(GENERIC_ERR, "Could not get rule '%s' in database", elt->data); // Print name - printf("(%s) :", rule->name); + printf("(%s):", rule->name); // Print dependencies struct list *dep = rule->dependencies; From db4bf470ffa31d61bca5f8986a69d277143aea74 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 31 Oct 2025 23:12:01 +0100 Subject: [PATCH 18/23] even more fixes --- minimake/Makefile | 8 ++++---- minimake/src/files/files.c | 12 ++++-------- minimake/tests/Makefile.test4 | 4 +++- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/minimake/Makefile b/minimake/Makefile index cb0ae0a..db29234 100644 --- a/minimake/Makefile +++ b/minimake/Makefile @@ -21,10 +21,10 @@ $(TARGET): $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) @echo $(OBJS) -# debug: CFLAGS += $(DBG_CFLAGS) -# debug: LDFLAGS += $(DBG_LDFLAGS) -# debug: $(OBJS) -# $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) +debug: CFLAGS += $(DBG_CFLAGS) +debug: LDFLAGS += $(DBG_LDFLAGS) +debug: $(OBJS) + $(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS) check: dash ./tests/run.sh diff --git a/minimake/src/files/files.c b/minimake/src/files/files.c index 2d46ecb..ef00e46 100644 --- a/minimake/src/files/files.c +++ b/minimake/src/files/files.c @@ -60,9 +60,6 @@ int run_command(char *command) fflush(stdout); fflush(stderr); - // char *executable; - // size_t args_offset = readword(command, strlen(command), &executable); - int id = fork(); if (id < 0) { @@ -72,14 +69,13 @@ int run_command(char *command) if (id == 0) { - int res = 0; - wait(&res); - // printf("Got return code: %d\n", res); - return res; + int res = execl("/bin/sh", "(make)", "-c", command, NULL); + exit(res); } else { - int res = execl("/bin/sh", "(make)", "-c", command, NULL); + int res = 0; + wait(&res); return res; } } diff --git a/minimake/tests/Makefile.test4 b/minimake/tests/Makefile.test4 index 45ee423..4da97dd 100644 --- a/minimake/tests/Makefile.test4 +++ b/minimake/tests/Makefile.test4 @@ -1,5 +1,7 @@ rule1: echo Toto + echo Tata + echo Tutu rule2: - @echo Toto + @echo Toto encore From 7acbfd6c9fb554746a847184713666bdcc4b21ce Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 31 Oct 2025 23:14:34 +0100 Subject: [PATCH 19/23] hmmmm --- minimake/src/files/files.c | 1 - 1 file changed, 1 deletion(-) diff --git a/minimake/src/files/files.c b/minimake/src/files/files.c index ef00e46..b27627d 100644 --- a/minimake/src/files/files.c +++ b/minimake/src/files/files.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include From bb1591a96ae4ff91b2cd4e87458e57791189b8fc Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Thu, 18 Dec 2025 13:17:48 +0100 Subject: [PATCH 20/23] nothing to be done reload --- minimake/src/minimake.c | 10 +++++++++- minimake/tests/Makefile.empty | 1 + minimake/tests/Makefile.vars | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 minimake/tests/Makefile.empty create mode 100644 minimake/tests/Makefile.vars diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index 468ce23..e76e664 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -469,7 +469,8 @@ static int run_rule(struct rule *rule) // Build dependencies while (dependencies != NULL) { - // Expand variables + // Expand variable + // TODO // Check file existence if (!file_exists(dependencies->data)) @@ -492,6 +493,13 @@ static int run_rule(struct rule *rule) dependencies = dependencies->next; } + // Empty recipe + if (commands == NULL) + { + printf("%s: Nothing to be done for '%s'.\n", program_name, rule->name); + return 0; + } + while (commands != NULL) { // Expand command variables diff --git a/minimake/tests/Makefile.empty b/minimake/tests/Makefile.empty new file mode 100644 index 0000000..e9228f2 --- /dev/null +++ b/minimake/tests/Makefile.empty @@ -0,0 +1 @@ +empty_target: diff --git a/minimake/tests/Makefile.vars b/minimake/tests/Makefile.vars new file mode 100644 index 0000000..b5ce417 --- /dev/null +++ b/minimake/tests/Makefile.vars @@ -0,0 +1,4 @@ +V=2 + +main: + echo $V From 57c7743ba07eb45a566497789604b3502f9663ae Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 19 Dec 2025 20:12:03 +0100 Subject: [PATCH 21/23] si ca passe pas jsui cuit --- minimake/src/minimake.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index e76e664..ff913ab 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "files/files.h" @@ -337,6 +338,7 @@ size_t expand_variable(struct line *line, size_t index, char **value) // Get corresponding value *value = get_variable_value(var_name, line->number); + free(var_name); } return 2; @@ -460,9 +462,34 @@ void make_parse(char *path) // ==== Runtime ==== +// Return 1 if rule is up to date, 0 otherwise +static int uptodate(struct rule *rule) +{ + struct stat path_stat; + + if (lstat(rule->name, &path_stat) != 0) // target doesn't exists + return 0; + + struct list *dependencies = rule->dependencies; + while (dependencies != NULL) + { + char *depname = dependencies->data; + if (lstat(depname, &path_stat) != 0) // Dependecy doesn't exists + return 0; + } + return 1; +} + // Expands and run a specified rule static int run_rule(struct rule *rule) { + // Check if p to date + if (uptodate(rule)) + { + printf("%s: '%s' is up to date.", program_name, rule->name); + return 0; + } + struct list *commands = rule->recipe; struct list *dependencies = rule->dependencies; From 018bae577a9ba0abafe5d8176e55ed4fc1f523a9 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 19 Dec 2025 20:13:58 +0100 Subject: [PATCH 22/23] et on dis ciao aux clang format --- minimake/src/minimake.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index ff913ab..4368296 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -18,14 +18,14 @@ // Static variables -char *program_name; +static char *program_name; -struct hash_map *variables = NULL; -struct hash_map *rules = NULL; +static struct hash_map *variables = NULL; +static struct hash_map *rules = NULL; // Keeps track of variables and rules order -struct list *variables_list = NULL; -struct list *rules_list = NULL; +static struct list *variables_list = NULL; +static struct list *rules_list = NULL; // ==== Misc ==== From 9731ba9a7a6edb6adf287558157414924d6b63ef Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Fri, 19 Jun 2026 11:11:29 +0200 Subject: [PATCH 23/23] New presentation and organization --- minimake/Makefile => Makefile | 0 README.md | 73 +++++++++++ micromake/src/Microfile | 3 - micromake/src/micromake.c | 119 ------------------ microshell/microshell.c | 30 ----- simple_ls/simple_ls.c | 37 ------ {minimake/src => src}/files/files.c | 0 {minimake/src => src}/files/files.h | 0 {minimake/src => src}/hash_maps/hash_maps.c | 0 {minimake/src => src}/hash_maps/hash_maps.h | 0 {minimake/src => src}/lines/lines.c | 0 {minimake/src => src}/lines/lines.h | 0 {minimake/src => src}/lists/lists.c | 0 {minimake/src => src}/lists/lists.h | 0 {minimake/src => src}/main.c | 0 {minimake/src => src}/minimake.c | 0 {minimake/src => src}/minimake.h | 0 {minimake/tests => tests}/Makefile.empty | 0 .../tests => tests}/Makefile.syntax-test | 0 {minimake/tests => tests}/Makefile.test3 | 0 {minimake/tests => tests}/Makefile.test4 | 0 {minimake/tests => tests}/Makefile.vars | 0 .../tests => tests}/Makefile2.syntax-test | 0 {minimake/tests => tests}/run.sh | 0 24 files changed, 73 insertions(+), 189 deletions(-) rename minimake/Makefile => Makefile (100%) create mode 100644 README.md delete mode 100644 micromake/src/Microfile delete mode 100644 micromake/src/micromake.c delete mode 100644 microshell/microshell.c delete mode 100644 simple_ls/simple_ls.c rename {minimake/src => src}/files/files.c (100%) rename {minimake/src => src}/files/files.h (100%) rename {minimake/src => src}/hash_maps/hash_maps.c (100%) rename {minimake/src => src}/hash_maps/hash_maps.h (100%) rename {minimake/src => src}/lines/lines.c (100%) rename {minimake/src => src}/lines/lines.h (100%) rename {minimake/src => src}/lists/lists.c (100%) rename {minimake/src => src}/lists/lists.h (100%) rename {minimake/src => src}/main.c (100%) rename {minimake/src => src}/minimake.c (100%) rename {minimake/src => src}/minimake.h (100%) rename {minimake/tests => tests}/Makefile.empty (100%) rename {minimake/tests => tests}/Makefile.syntax-test (100%) rename {minimake/tests => tests}/Makefile.test3 (100%) rename {minimake/tests => tests}/Makefile.test4 (100%) rename {minimake/tests => tests}/Makefile.vars (100%) rename {minimake/tests => tests}/Makefile2.syntax-test (100%) rename {minimake/tests => tests}/run.sh (100%) diff --git a/minimake/Makefile b/Makefile similarity index 100% rename from minimake/Makefile rename to Makefile diff --git a/README.md b/README.md new file mode 100644 index 0000000..7cc185b --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Minimake + +Minimake is a small project written in about a week in C99. Its goal was to reproduce the main features of the well known GNU Make utility. + +> **Note** This is a school project, therefore it probably won't interest you if you are looking for something useful. + +## Build + +```sh +make +``` +or even better +```sh +minimake +``` + +## How it works + +If you're not familiar with Make, what it does is that it reads a file named +`Makefile` in the current directory which contains instructions to build a +project in the form of recipes. It includes support for variables, dependencies +, implicit rules and more. + +Then depending on the user input it automatically executes a recipe with its dependencies. + + +Here is what a basic one can look like +```make +BENCH_FLAGS = --all + +test_and_bench: + bash ./runtests.sh + bash ./runbenchs.sh $(BENCH_FLAGS) +``` + +But it will more realisticly look like that + +```make +CC = gcc +CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla +LDFLAGS= + +DBG_CFLAGS = -fsanitize=address -g +DBG_LDFLAGS= -fsanitize=address + + +SRC_DIR = src +LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c files/files.c +MAIN_SRCS = main.c minimake.c + +SRCS = $(MAIN_SRCS:%=$(SRC_DIR)/%) $(LIB_SRCS:%=$(SRC_DIR)/%) +OBJS = $(SRCS:.c=.o) + +TARGET= minimake +DBG_TARGET = minimake-dbg + +$(TARGET): $(OBJS) + $(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS) + @echo $(OBJS) + +debug: CFLAGS += $(DBG_CFLAGS) +debug: LDFLAGS += $(DBG_LDFLAGS) +debug: $(OBJS) + $(CC) -o $(DBG_TARGET) $^ $(LDFLAGS) $(LDLIBS) + +check: + dash ./tests/run.sh + +clean: + $(RM) $(TARGET) + $(RM) $(OBJS) + +``` diff --git a/micromake/src/Microfile b/micromake/src/Microfile deleted file mode 100644 index 607b02a..0000000 --- a/micromake/src/Microfile +++ /dev/null @@ -1,3 +0,0 @@ -qwertyu: -cbejw: a bc d -dmwq :d wdwd diff --git a/micromake/src/micromake.c b/micromake/src/micromake.c deleted file mode 100644 index fda3fe2..0000000 --- a/micromake/src/micromake.c +++ /dev/null @@ -1,119 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#define BUFFER_SIZE 1024 -#define STRING_BUFFER_SIZE 32 - -#include -#include -#include -#include - -// Helps to match a string (excludes blanks and special characters) -static int is_char(char c) -{ - return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'; -} - -// Returns the next word from buf until buf_len, -// and the numbers of read characters in *read_chars -// WARNING allocates the result on the heap -static char *readWord(char *buf, size_t buf_len, size_t *read_chars) -{ - size_t i = 0; - size_t str_buf_size = STRING_BUFFER_SIZE; - char *str_buf = malloc(sizeof(char) * str_buf_size); - while (i < buf_len && is_char(buf[i])) - { - // Reallocate more space if necessary - if (i >= str_buf_size - 1) - { - str_buf_size += STRING_BUFFER_SIZE; - str_buf = realloc(str_buf, str_buf_size); - if (str_buf == NULL) - errx(2, "Could not realloc"); - } - - str_buf[i] = buf[i]; - i++; - } - - str_buf[i] = '\0'; - *read_chars = i; - - return str_buf; -} - -int skip_blanks(char *buf, size_t buf_len) -{ - size_t i = 0; - while (i < buf_len && isblank(buf[i])) - i++; - return i; -} - -int main(int argc, char **argv) -{ - if (argc < 2) - errx(2, "Not enough arguments"); - if (argc > 2) - errx(2, "Not enough arguments"); - - // Open file - FILE *stream = fopen(argv[1], "r"); - if (stream == 0) - errx(2, "Could not open file"); - - // Allocate buffer - size_t buf_size = BUFFER_SIZE; - char *buf = malloc(sizeof(char) * buf_size); - if (buf == NULL) - errx(2, "Could not allocate more memory"); - - // Read - ssize_t nread; - while ((nread = getline(&buf, &buf_size, stream)) != -1) - { - size_t u_nread = nread; - size_t i = 0; - // Skip blanks - i += skip_blanks(buf + i, nread - i); - - // Read target name - size_t skipped_chars = 0; - char *rule_name = readWord(buf + i, nread - i, &skipped_chars); - if (skipped_chars != 0) - printf("%s:", rule_name); - i += skipped_chars; - - // Skip until ':' - i += skip_blanks(buf + i, nread - i); - if (buf[i] != ':') - errx(2, "Unexpected character '%c' after rule declaration '%s'", - buf[i], rule_name); - i++; - - // Read deps - while (i < u_nread) - { - // Skip blanks - i += skip_blanks(buf + i, nread - i); - - // Read word - size_t skipped_chars = 0; - char *dep_name = readWord(buf + i, nread - i, &skipped_chars); - if (skipped_chars != 0) - printf(" %s", dep_name); - free(dep_name); - i += skipped_chars; - - if (!is_char(buf[i]) && !isblank(buf[i]) && buf[i] != '\0') - errx(2, "Unexpected character '%c'", buf[i]); - } - - i++; - free(rule_name); - } - - free(buf); - fclose(stream); - return 0; -} diff --git a/microshell/microshell.c b/microshell/microshell.c deleted file mode 100644 index 4a7b661..0000000 --- a/microshell/microshell.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - if (argc < 2) - err(1, "Not enough args"); - - int id = fork(); - if (id < 0) - err(1, "Cannot fork"); - - if (id == 0) - { - int res = 0; - wait(&res); - // printf("%d\n", res); - return res; - } - else - { - int res = execl("/bin/sh", "supershell", "-c", argv[1], NULL); - printf("process exit status: %d\n", res); - // exit(res); - return res; - } -} diff --git a/simple_ls/simple_ls.c b/simple_ls/simple_ls.c deleted file mode 100644 index 508c5df..0000000 --- a/simple_ls/simple_ls.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include - -static void simple_ls(char *path) -{ - if (path == NULL) - errx(1, "Internal error: Passed NULL path"); - - DIR *dir = opendir(path); - if (dir == NULL) - errx(1, "Internal error: cannot open directory"); - - struct dirent *element; - while ((element = readdir(dir))) - { - puts(element->d_name); - } - - int res = closedir(dir); - if (res == -1) - errx(1, "Could not close dir"); -} - -int main(int argc, char **argv) -{ - if (argc < 2) - simple_ls("."); - else - { - for (int i = 1; i < argc; i++) - { - simple_ls(argv[i]); - } - } - return 0; -} diff --git a/minimake/src/files/files.c b/src/files/files.c similarity index 100% rename from minimake/src/files/files.c rename to src/files/files.c diff --git a/minimake/src/files/files.h b/src/files/files.h similarity index 100% rename from minimake/src/files/files.h rename to src/files/files.h diff --git a/minimake/src/hash_maps/hash_maps.c b/src/hash_maps/hash_maps.c similarity index 100% rename from minimake/src/hash_maps/hash_maps.c rename to src/hash_maps/hash_maps.c diff --git a/minimake/src/hash_maps/hash_maps.h b/src/hash_maps/hash_maps.h similarity index 100% rename from minimake/src/hash_maps/hash_maps.h rename to src/hash_maps/hash_maps.h diff --git a/minimake/src/lines/lines.c b/src/lines/lines.c similarity index 100% rename from minimake/src/lines/lines.c rename to src/lines/lines.c diff --git a/minimake/src/lines/lines.h b/src/lines/lines.h similarity index 100% rename from minimake/src/lines/lines.h rename to src/lines/lines.h diff --git a/minimake/src/lists/lists.c b/src/lists/lists.c similarity index 100% rename from minimake/src/lists/lists.c rename to src/lists/lists.c diff --git a/minimake/src/lists/lists.h b/src/lists/lists.h similarity index 100% rename from minimake/src/lists/lists.h rename to src/lists/lists.h diff --git a/minimake/src/main.c b/src/main.c similarity index 100% rename from minimake/src/main.c rename to src/main.c diff --git a/minimake/src/minimake.c b/src/minimake.c similarity index 100% rename from minimake/src/minimake.c rename to src/minimake.c diff --git a/minimake/src/minimake.h b/src/minimake.h similarity index 100% rename from minimake/src/minimake.h rename to src/minimake.h diff --git a/minimake/tests/Makefile.empty b/tests/Makefile.empty similarity index 100% rename from minimake/tests/Makefile.empty rename to tests/Makefile.empty diff --git a/minimake/tests/Makefile.syntax-test b/tests/Makefile.syntax-test similarity index 100% rename from minimake/tests/Makefile.syntax-test rename to tests/Makefile.syntax-test diff --git a/minimake/tests/Makefile.test3 b/tests/Makefile.test3 similarity index 100% rename from minimake/tests/Makefile.test3 rename to tests/Makefile.test3 diff --git a/minimake/tests/Makefile.test4 b/tests/Makefile.test4 similarity index 100% rename from minimake/tests/Makefile.test4 rename to tests/Makefile.test4 diff --git a/minimake/tests/Makefile.vars b/tests/Makefile.vars similarity index 100% rename from minimake/tests/Makefile.vars rename to tests/Makefile.vars diff --git a/minimake/tests/Makefile2.syntax-test b/tests/Makefile2.syntax-test similarity index 100% rename from minimake/tests/Makefile2.syntax-test rename to tests/Makefile2.syntax-test diff --git a/minimake/tests/run.sh b/tests/run.sh similarity index 100% rename from minimake/tests/run.sh rename to tests/run.sh