backup
This commit is contained in:
parent
750bf77846
commit
ad6f81afc0
10 changed files with 765 additions and 99 deletions
1
minimake/src/list/.gitignore
vendored
Normal file
1
minimake/src/list/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
list.c
|
||||
104
minimake/src/list/list.h
Normal file
104
minimake/src/list/list.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
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 */
|
||||
101
minimake/src/list/list_advanced.c
Normal file
101
minimake/src/list/list_advanced.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
86
minimake/src/list/list_basic.c
Normal file
86
minimake/src/list/list_basic.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
138
minimake/src/list/list_ultimate.c
Normal file
138
minimake/src/list/list_ultimate.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
46
minimake/src/list_void/list.c
Normal file
46
minimake/src/list_void/list.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
31
minimake/src/list_void/list.h
Normal file
31
minimake/src/list_void/list.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#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,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 <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 ====
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
35
minimake/tests/Makefile.syntax-test
Normal file
35
minimake/tests/Makefile.syntax-test
Normal file
|
|
@ -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)"
|
||||
Loading…
Add table
Add a link
Reference in a new issue