From 6bca1e84fb2081650e09bd62ad6c4505a062f2e0 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Sat, 25 Oct 2025 14:19:33 +0200 Subject: [PATCH] ' --- 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