backup
This commit is contained in:
parent
ad6f81afc0
commit
e106a4ca66
12 changed files with 355 additions and 328 deletions
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,133 +1,172 @@
|
||||||
#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) {
|
/*
|
||||||
struct pair_list **data = calloc(size, sizeof(struct pair_list));
|
** Hash the key using FNV-1a 32 bits hash algorithm.
|
||||||
struct hash_map *map = malloc(sizeof(struct hash_map));
|
*/
|
||||||
map->data = data;
|
size_t hash(const char *key)
|
||||||
map->size = size;
|
{
|
||||||
return map;
|
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 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)
|
||||||
|
*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)
|
if (updated)
|
||||||
*updated = false;
|
*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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->next == NULL)
|
void hashMapFree(struct hash_map *hash_map)
|
||||||
return false;
|
{
|
||||||
while (strcmp(entry->next->key, key) != 0) {
|
if (hash_map == NULL)
|
||||||
entry = entry->next;
|
return;
|
||||||
if (entry->next == NULL)
|
if (hash_map->data == NULL)
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
|
for (size_t i = 0; i < hash_map->size; i++)
|
||||||
struct pair_list *elt_to_free = entry->next;
|
{
|
||||||
entry->next = entry->next->next;
|
struct pair_list *entry = hash_map->data[i];
|
||||||
free(elt_to_free);
|
while (entry != NULL)
|
||||||
return true;
|
{
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
68
minimake/src/lines/lines.c
Normal file
68
minimake/src/lines/lines.c
Normal 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;
|
||||||
|
}
|
||||||
25
minimake/src/lines/lines.h
Normal file
25
minimake/src/lines/lines.h
Normal 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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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 */
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
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
|
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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue