This commit is contained in:
Guillem George 2025-10-25 21:56:43 +02:00
parent ad6f81afc0
commit e106a4ca66
12 changed files with 355 additions and 328 deletions

View file

@ -1,27 +0,0 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}

View file

@ -1,11 +1,34 @@
#include "hash_map.h" #include "hash_map.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct hash_map *hashMapInit(size_t size) { /*
** 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 pair_list **data = calloc(size, sizeof(struct pair_list));
struct hash_map *map = malloc(sizeof(struct hash_map)); struct hash_map *map = malloc(sizeof(struct hash_map));
map->data = data; map->data = data;
@ -14,8 +37,10 @@ struct hash_map *hashMapInit(size_t size) {
} }
bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value,
bool *updated) { bool *updated)
if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) { {
if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0)
{
if (updated) if (updated)
*updated = false; *updated = false;
return false; return false;
@ -26,8 +51,10 @@ bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value,
size_t entry_hash = hash(key) % hash_map->size; size_t entry_hash = hash(key) % hash_map->size;
// Search if key is already present // Search if key is already present
struct pair_list *elt = hash_map->data[entry_hash]; struct pair_list *elt = hash_map->data[entry_hash];
while (elt != NULL) { while (elt != NULL)
if (strcmp(elt->key, key) == 0) { {
if (strcmp(elt->key, key) == 0)
{
elt->value = value; elt->value = value;
if (updated) if (updated)
*updated = true; *updated = true;
@ -52,15 +79,18 @@ bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value,
return true; return true;
} }
void hashMapFree(struct hash_map *hash_map) { void hashMapFree(struct hash_map *hash_map)
{
if (hash_map == NULL) if (hash_map == NULL)
return; return;
if (hash_map->data == NULL) if (hash_map->data == NULL)
return; return;
for (size_t i = 0; i < hash_map->size; i++) { for (size_t i = 0; i < hash_map->size; i++)
{
struct pair_list *entry = hash_map->data[i]; struct pair_list *entry = hash_map->data[i];
while (entry != NULL) { while (entry != NULL)
{
struct pair_list *next = entry->next; struct pair_list *next = entry->next;
free(entry); free(entry);
entry = next; entry = next;
@ -70,16 +100,20 @@ void hashMapFree(struct hash_map *hash_map) {
free(hash_map); free(hash_map);
} }
void hashMapDump(struct hash_map *hash_map) { void hashMapDump(struct hash_map *hash_map)
for (size_t i = 0; i < hash_map->size; i++) { {
for (size_t i = 0; i < hash_map->size; i++)
{
struct pair_list *entry = hash_map->data[i]; struct pair_list *entry = hash_map->data[i];
bool is_null = true; bool is_null = true;
if (entry != NULL) { if (entry != NULL)
{
is_null = false; is_null = false;
printf("%s: %s", entry->key, entry->value); printf("%s: %s", entry->key, entry->value);
entry = entry->next; entry = entry->next;
} }
while (entry != NULL) { while (entry != NULL)
{
printf(", %s: %s", entry->key, entry->value); printf(", %s: %s", entry->key, entry->value);
entry = entry->next; entry = entry->next;
} }
@ -88,13 +122,15 @@ void hashMapDump(struct hash_map *hash_map) {
} }
} }
const char *hashMapGet(const struct hash_map *hash_map, const char *key) { const char *hashMapGet(const struct hash_map *hash_map, const char *key)
{
if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0)
return NULL; return NULL;
size_t entry_hash = hash(key) % hash_map->size; size_t entry_hash = hash(key) % hash_map->size;
struct pair_list *entry = hash_map->data[entry_hash]; struct pair_list *entry = hash_map->data[entry_hash];
while (entry != NULL && strcmp(entry->key, key) != 0) { while (entry != NULL && strcmp(entry->key, key) != 0)
{
entry = entry->next; entry = entry->next;
} }
if (entry == NULL) if (entry == NULL)
@ -103,7 +139,8 @@ const char *hashMapGet(const struct hash_map *hash_map, const char *key) {
return entry->value; return entry->value;
} }
bool hashMapRemove(struct hash_map *hash_map, const char *key) { bool hashMapRemove(struct hash_map *hash_map, const char *key)
{
if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL)
return false; return false;
@ -112,7 +149,8 @@ bool hashMapRemove(struct hash_map *hash_map, const char *key) {
if (entry == NULL) if (entry == NULL)
return false; return false;
if (strcmp(entry->key, key) == 0) { if (strcmp(entry->key, key) == 0)
{
hash_map->data[entry_hash] = entry->next; hash_map->data[entry_hash] = entry->next;
free(entry); free(entry);
return true; return true;
@ -120,7 +158,8 @@ bool hashMapRemove(struct hash_map *hash_map, const char *key) {
if (entry->next == NULL) if (entry->next == NULL)
return false; return false;
while (strcmp(entry->next->key, key) != 0) { while (strcmp(entry->next->key, key) != 0)
{
entry = entry->next; entry = entry->next;
if (entry->next == NULL) if (entry->next == NULL)
return false; return false;

View file

@ -0,0 +1,68 @@
#include "lines.h"
#include <ctype.h>
#include <err.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
// 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;
}

View file

@ -0,0 +1,25 @@
#ifndef LINES_H
#define LINES_H
#define STRING_BUFFER_SIZE 32
#include <stddef.h>
#include <stdio.h>
// 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

View file

@ -5,7 +5,7 @@
struct list struct list
{ {
int data; void* data;
struct list *next; struct list *next;
}; };
@ -13,7 +13,7 @@ struct list
** Insert a node containing `value` at the beginning of the list. ** Insert a node containing `value` at the beginning of the list.
** Return `NULL` if an error occured. ** 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. ** Return the lenght of the list.
@ -38,7 +38,7 @@ void list_destroy(struct list *list);
** Return `NULL` if an error occured. ** Return `NULL` if an error occured.
*/ */
// START PROTO list_append // 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 // END PROTO list_append
/* /*
@ -48,7 +48,7 @@ struct list *list_append(struct list *list, int value);
** Return `NULL` if an error occured. ** Return `NULL` if an error occured.
*/ */
// START PROTO list_insert // 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 // END PROTO list_insert
/* /*
@ -64,7 +64,7 @@ struct list *list_remove(struct list *list, size_t index);
** Return `-1` if nothing is found. ** Return `-1` if nothing is found.
*/ */
// START PROTO list_find // START PROTO list_find
int list_find(struct list *list, int value); int list_find(struct list *list, void* value);
// END PROTO list_find // END PROTO list_find
/* /*

View file

@ -4,7 +4,7 @@
#include "list.h" #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) if (list == NULL || index == 0)
{ {
@ -65,7 +65,7 @@ struct list *list_remove(struct list *list, size_t index)
return list; return list;
} }
int list_find(struct list *list, int value) int list_find(struct list *list, void *value)
{ {
if (list == NULL) if (list == NULL)
{ {

View file

@ -3,7 +3,7 @@
#include "list.h" #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)); struct list *new_elt = malloc(sizeof(struct list));
if (new_elt == NULL) if (new_elt == NULL)
@ -27,26 +27,26 @@ size_t list_length(struct list *list)
return len; return len;
} }
void list_print(struct list *list) // void list_print(struct list *list)
{ // {
if (list == NULL) // if (list == NULL)
{ // {
return; // return;
} // }
while (list != NULL) // while (list != NULL)
{ // {
if (list->next != NULL) // if (list->next != NULL)
{ // {
printf("%d ", list->data); // printf("%p ", list->data);
} // }
else // else
{ // {
printf("%d\n", list->data); // printf("%p\n", list->data);
} // }
list = list->next; // list = list->next;
} // }
} // }
void list_destroy(struct list *list) 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) if (list == NULL)
{ {

View file

@ -5,7 +5,7 @@
void swap_next(struct list *elt) void swap_next(struct list *elt)
{ {
int c = elt->next->data; void *c = elt->next->data;
elt->next->data = elt->data; elt->next->data = elt->data;
elt->data = c; elt->data = c;
} }

View file

@ -1,46 +0,0 @@
#include "list.h"
#include <stdlib.h>
#include <string.h>
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;
}
}

View file

@ -1,31 +0,0 @@
#ifndef LIST_H
#define LIST_H
#include <stddef.h>
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 */

View file

@ -1,18 +1,16 @@
#include "list/list.h"
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
// Default values #include "minimake.h"
#define BUFFER_SIZE 1024
#define STRING_BUFFER_SIZE 32
#define HASHMAP_SIZE 32
#include <ctype.h> #include <ctype.h>
#include <err.h> #include <err.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "hash_map/hash_map.h" #include "hash_map/hash_map.h"
#include "minimake.h" #include "lines/lines.h"
#include "list/list.h"
// Static variables // Static variables
struct hash_map *variables = NULL; struct hash_map *variables = NULL;
@ -20,49 +18,6 @@ struct hash_map *rules = NULL;
// ==== Parsing ==== // ==== 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 // Registers a new variable and returns its pointer
// WARNING Allocates memory on the heap, // WARNING Allocates memory on the heap,
// the variables hashmap should be freed before exit // 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); res = list_append(res, dep_name);
i += skipped_chars; 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') if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0')
errx(2, "Unexpected character '%c'", buf[i]); errx(2, "Unexpected character '%c'", buf[i]);
} }
@ -124,27 +82,70 @@ static struct list *readDependencies(char *buf, size_t buf_size)
return res; 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; char *buf = l->buffer;
size_t buf_size = BUFFER_SIZE;
size_t i = 0; struct list *res = NULL;
while (i < line_size)
// Getline
while ((l->length = getline(&buf, &buf_size, stream)))
{ {
if (!isblank(buf[i])) l->number++;
return 0;
if (buf[i] == '#') // Comment // Skip blank lines and comments
return 1; if (isBlankLine(l))
continue;
else if (buf[0] != '\t') // Not a recipe
{
l->buffer = buf; // Update buffer !
return res;
} }
return 1; 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);
}
}
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 size_t i = 0;
// Skip blank lines and comments 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 // Takes a buffer containing the line to parse and it length
@ -175,14 +176,16 @@ static void parseLine(struct line *current_line)
// Variable // Variable
case '=': case '=':
new_variable = createVariable(name); new_variable = createVariable(name);
// Read value new_variable->value = readValue(buf + i, line_size);
break; break;
// Rule // Rule
case ':': case ':':
new_rule = createRule(name); new_rule = createRule(name);
// Read dependencies new_rule->dependencies = readDependencies(buf + i, line_size);
// Read recipe new_rule->recipe = readRecipe(current_line);
parseLine(current_line);
// TODO: check for loooooops
break; break;
// Blank line // Blank line
@ -226,6 +229,7 @@ void makeParse(char *path)
ssize_t nread; ssize_t nread;
struct line current_line; struct line current_line;
current_line.number = 1; current_line.number = 1;
current_line.file_stream = stream;
while ((nread = getline(&buf, &buf_size, stream)) != -1) while ((nread = getline(&buf, &buf_size, stream)) != -1)
{ {
if (nread == -1) if (nread == -1)

View file

@ -1,6 +1,11 @@
#ifndef MINIMAKE_H #ifndef MINIMAKE_H
#define MINIMAKE_H #define MINIMAKE_H
#define BUFFER_SIZE 1024
#define HASHMAP_SIZE 32
#include <stdio.h>
#include "list/list.h" #include "list/list.h"
// Holds variable information // Holds variable information
@ -20,16 +25,6 @@ struct rule
struct list *recipe; 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); int make(char *path, int flags);
#endif // ! MINIMAKE_H #endif // ! MINIMAKE_H