DEMENTOOOOOOR

This commit is contained in:
Gu://em_ 2025-10-29 23:15:11 +01:00
parent 8e227e4298
commit 4013a4a154
6 changed files with 360 additions and 84 deletions

2
.gitignore vendored
View file

@ -7,4 +7,4 @@
*.class
*.log
*.core
minimake
minimake/minimake

View file

@ -3,3 +3,4 @@ guillem.george
Special thanks to
- Timothée Battefort for the parser
- Amadéo Heaulme for the error handling

View file

@ -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");

View file

@ -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();
}

View 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
View 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"