DEMENTOOOOOOR
This commit is contained in:
parent
8e227e4298
commit
4013a4a154
6 changed files with 360 additions and 84 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -7,4 +7,4 @@
|
|||
*.class
|
||||
*.log
|
||||
*.core
|
||||
minimake
|
||||
minimake/minimake
|
||||
|
|
|
|||
1
AUTHORS
1
AUTHORS
|
|
@ -3,3 +3,4 @@ guillem.george
|
|||
Special thanks to
|
||||
|
||||
- Timothée Battefort for the parser
|
||||
- Amadéo Heaulme for the error handling
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
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)"
|
||||
77
minimake/tests/run.sh
Normal file
77
minimake/tests/run.sh
Normal file
|
|
@ -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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue