EXPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnd
This commit is contained in:
parent
4013a4a154
commit
c358562ecc
8 changed files with 443 additions and 230 deletions
|
|
@ -4,8 +4,11 @@
|
|||
#include <err.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../minimake.h"
|
||||
|
||||
// Helps to match a string (excludes blanks and special characters)
|
||||
int ischar(char c)
|
||||
{
|
||||
|
|
@ -50,13 +53,7 @@ size_t readword(char *buf, size_t buf_len, char **word)
|
|||
while (i < buf_len && ischar(buf[i]))
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
if (i >= res_size - 1)
|
||||
{
|
||||
res_size += STRING_BUFFER_SIZE;
|
||||
res = realloc(res, res_size);
|
||||
if (res == NULL)
|
||||
errx(2, "Could not realloc");
|
||||
}
|
||||
resize_buf(&res, res_size, i);
|
||||
|
||||
res[i] = buf[i];
|
||||
i++;
|
||||
|
|
@ -73,3 +70,152 @@ size_t readword(char *buf, size_t buf_len, char **word)
|
|||
*word = res;
|
||||
return i;
|
||||
}
|
||||
|
||||
// Resizes buf if index is greater or equal than buf_size-1
|
||||
// Returns new buffer size
|
||||
size_t resize_buf(char **buf, size_t buf_size, size_t index)
|
||||
{
|
||||
if (index >= buf_size - 1)
|
||||
{
|
||||
buf_size += BUFFER_SIZE;
|
||||
*buf = realloc(*buf, buf_size);
|
||||
if (buf == NULL)
|
||||
drop(2, "Could not realloc");
|
||||
}
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
// Inserts str into base at index and returns the resulting string
|
||||
// WARNING allocates the result on the heap, do not forget to free it
|
||||
char *insert_str(char *base, char *str, size_t index)
|
||||
{
|
||||
size_t res_size = BUFFER_SIZE;
|
||||
char *res = malloc(res_size * sizeof(char));
|
||||
if (res == NULL)
|
||||
drop(GENERIC_ERR, "Could not allocate more memory");
|
||||
|
||||
// Copy until index
|
||||
size_t i = 0;
|
||||
while (i < index)
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
res_size = resize_buf(&res, res_size, i);
|
||||
|
||||
res[i] = base[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
// Copy str
|
||||
size_t str_i = 0;
|
||||
while (str[str_i] != '\0')
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
res_size = resize_buf(&res, res_size, i);
|
||||
|
||||
res[i] = str[str_i];
|
||||
i++;
|
||||
str_i++;
|
||||
}
|
||||
|
||||
// Copy rest
|
||||
while (base[i] != '\0')
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
res_size = resize_buf(&res, res_size, i);
|
||||
|
||||
res[i] = base[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
res[i] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
// Appends str into base at index and stores the resulting string in *result
|
||||
// Returns the size of the resulting buffer
|
||||
// WARNING allocates the result on the heap, do not forget to free it
|
||||
size_t append_str(char *base, char *str, size_t index, char **result)
|
||||
{
|
||||
size_t res_size = BUFFER_SIZE;
|
||||
char *res = malloc(res_size * sizeof(char));
|
||||
if (res == NULL)
|
||||
drop(GENERIC_ERR, "Could not allocate more memory");
|
||||
|
||||
// Copy until index
|
||||
size_t i = 0;
|
||||
while (i < index)
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
res_size = resize_buf(&res, res_size, i);
|
||||
|
||||
res[i] = base[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
// Copy str
|
||||
size_t str_i = 0;
|
||||
while (str[str_i] != '\0')
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
res_size = resize_buf(&res, res_size, i);
|
||||
|
||||
res[i] = str[str_i];
|
||||
i++;
|
||||
str_i++;
|
||||
}
|
||||
res[i] = '\0';
|
||||
|
||||
*result = res;
|
||||
return res_size;
|
||||
}
|
||||
|
||||
// Read word until ':', '=' and blanks and expands variable if any is found
|
||||
// Returns the number of skipped chars and stores the resulting string in word
|
||||
size_t read_declaration(struct line *line, size_t index, char **word)
|
||||
{
|
||||
size_t i = index;
|
||||
size_t buf_len = line->length;
|
||||
char *buf = line->buffer;
|
||||
|
||||
size_t res_size = STRING_BUFFER_SIZE;
|
||||
char *res = malloc(sizeof(char) * res_size);
|
||||
if (res == NULL)
|
||||
drop(GENERIC_ERR, "Could not allocate more memory");
|
||||
|
||||
size_t res_i = 0;
|
||||
while (i < buf_len && ischar(buf[i]))
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
res_size = resize_buf(&res, res_size, i);
|
||||
|
||||
// Expand variable
|
||||
if (buf[i] == '$')
|
||||
{
|
||||
char *expanded_var;
|
||||
char *tmp_res_buf;
|
||||
i += expand_variable(line, i + 1, &expanded_var);
|
||||
res_size = append_str(res, expanded_var, i, &tmp_res_buf);
|
||||
// Replace res with res + expanded_variable
|
||||
res_i = strlen(tmp_res_buf);
|
||||
free(res);
|
||||
// free(expanded_var);
|
||||
res = tmp_res_buf;
|
||||
continue;
|
||||
}
|
||||
|
||||
res[res_i] = buf[i];
|
||||
i++;
|
||||
res_i++;
|
||||
}
|
||||
res[res_i] = '\0';
|
||||
|
||||
if (i == index)
|
||||
{
|
||||
free(res);
|
||||
*word = NULL;
|
||||
return i - index;
|
||||
}
|
||||
|
||||
*word = res;
|
||||
return i - index;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,5 +22,9 @@ int ischar(char c);
|
|||
int isblankline(struct line *l);
|
||||
int skipblanks(char *buf, size_t buf_len);
|
||||
size_t readword(char *buf, size_t buf_len, char **word);
|
||||
size_t resize_buf(char** buf, size_t buf_size, size_t index);
|
||||
char *insert_str(char *base, char *str, size_t index);
|
||||
size_t read_declaration(struct line *line, size_t index, char **word);
|
||||
size_t append_str(char *base, char *str, size_t index, char **res);
|
||||
|
||||
#endif // LINES_H
|
||||
|
|
|
|||
|
|
@ -331,3 +331,16 @@ struct list *list_split(struct list *list, size_t index)
|
|||
elt->next = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@ void list_print(struct list *list);
|
|||
*/
|
||||
void list_destroy(struct list *list);
|
||||
|
||||
/*
|
||||
** Release the memory used by the list and its content
|
||||
** Does nothing if `list` is `NULL`.
|
||||
*/
|
||||
void list_deep_destroy(struct list *l);
|
||||
|
||||
/*
|
||||
** Append a node containing `value` at the end of the list.
|
||||
** Return `NULL` if an error occured.
|
||||
|
|
@ -72,7 +78,7 @@ int list_find(struct list *list, void* value);
|
|||
** Return `list2` if `list` is `NULL`.
|
||||
*/
|
||||
// START PROTO list_concat
|
||||
struct list *list_concat(struct list *list, struct list *list2);
|
||||
// struct list *list_concat(struct list *list, struct list *list2);
|
||||
// END PROTO list_concat
|
||||
|
||||
/*
|
||||
|
|
@ -80,7 +86,7 @@ struct list *list_concat(struct list *list, struct list *list2);
|
|||
** Return the new list.
|
||||
*/
|
||||
// START PROTO list_sort
|
||||
struct list *list_sort(struct list *list);
|
||||
// struct list *list_sort(struct list *list);
|
||||
// END PROTO list_sort
|
||||
|
||||
/*
|
||||
|
|
@ -88,7 +94,7 @@ struct list *list_sort(struct list *list);
|
|||
** Return the new list.
|
||||
*/
|
||||
// START PROTO list_reverse
|
||||
struct list *list_reverse(struct list *list);
|
||||
// struct list *list_reverse(struct list *list);
|
||||
// END PROTO list_reverse
|
||||
|
||||
/*
|
||||
|
|
@ -98,7 +104,7 @@ struct list *list_reverse(struct list *list);
|
|||
** Return `NULL` if `list` is `NULL` or `index` is invalid.
|
||||
*/
|
||||
// START PROTO list_split
|
||||
struct list *list_split(struct list *list, size_t index);
|
||||
// struct list *list_split(struct list *list, size_t index);
|
||||
// END PROTO list_split
|
||||
|
||||
#endif /* ! LIST_H */
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static int handle_args(int argc, char **argv, struct list **minimake_files,
|
|||
// Treat as rules
|
||||
for (int j = i; j < argc; j++)
|
||||
{
|
||||
files = list_append(rules, argv[i]);
|
||||
rules = list_append(rules, argv[i]);
|
||||
}
|
||||
*minimake_files = files;
|
||||
*minimake_rules = rules;
|
||||
|
|
@ -50,6 +50,8 @@ static int handle_args(int argc, char **argv, struct list **minimake_files,
|
|||
else if (strcmp(argv[i], "-h") == 0)
|
||||
{
|
||||
print_help(argv[0]);
|
||||
list_destroy(files);
|
||||
list_destroy(rules);
|
||||
exit(0);
|
||||
}
|
||||
// Custom file
|
||||
|
|
@ -59,7 +61,7 @@ static int handle_args(int argc, char **argv, struct list **minimake_files,
|
|||
if (i + 1 == argc || argv[i + 1][0] == '-')
|
||||
errx(INVALID_ARG, "No file specified after '-f'");
|
||||
|
||||
files = list_prepend(files, argv[i]);
|
||||
files = list_prepend(files, argv[i + 1]);
|
||||
}
|
||||
// Print
|
||||
else if (strcmp(argv[i], "-p") == 0)
|
||||
|
|
@ -71,12 +73,14 @@ static int handle_args(int argc, char **argv, struct list **minimake_files,
|
|||
{
|
||||
printf("Unknown option '%s'", argv[i]);
|
||||
print_help(argv[0]);
|
||||
list_destroy(files);
|
||||
list_destroy(rules);
|
||||
exit(INVALID_ARG);
|
||||
}
|
||||
}
|
||||
else // Rules
|
||||
{
|
||||
files = list_append(rules, argv[i]);
|
||||
rules = list_append(rules, argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +116,6 @@ char *get_makefile(struct list *files)
|
|||
if (found)
|
||||
res = file->data;
|
||||
|
||||
list_destroy(files);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -127,4 +130,7 @@ int main(int argc, char **argv)
|
|||
errx(GENERIC_ERR, "No Makefile found");
|
||||
|
||||
make(filename, flags, argv[0]);
|
||||
list_destroy(files);
|
||||
list_destroy(rules);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,22 +27,6 @@ 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)
|
||||
|
|
@ -59,20 +43,15 @@ 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_deep_destroy(r->dependencies);
|
||||
list_deep_destroy(r->recipe);
|
||||
free(r);
|
||||
// free(entry->key);
|
||||
}
|
||||
else if (hash_map == variables)
|
||||
{
|
||||
// struct variable *v = entry->value;
|
||||
// free(v->name);
|
||||
// free(v->value);
|
||||
|
||||
// printf("Att to free: %s\n", entry->key);
|
||||
free(entry->key);
|
||||
free(entry->value);
|
||||
}
|
||||
|
|
@ -91,7 +70,7 @@ static void hashmap_deep_free(struct hash_map *hash_map)
|
|||
free(hash_map);
|
||||
}
|
||||
|
||||
static void free_all()
|
||||
static void free_all(void)
|
||||
{
|
||||
list_destroy(rules_list);
|
||||
list_destroy(variables_list);
|
||||
|
|
@ -99,78 +78,6 @@ static void free_all()
|
|||
hashmap_deep_free(variables);
|
||||
}
|
||||
|
||||
static void exit_on_error(int status, char *format, ...)
|
||||
{
|
||||
// Print
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fprintf(stderr, "%s: ", program_name);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
|
||||
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
|
||||
|
|
@ -187,9 +94,8 @@ static void register_rule(char *name, struct list *dependencies,
|
|||
int err = hashmap_insert(rules, name, rule, NULL);
|
||||
if (!err)
|
||||
{
|
||||
exit_on_error(
|
||||
GENERIC_ERR,
|
||||
"Internal Error: Couln't add entry for '%s' in the hashmap", name);
|
||||
drop(GENERIC_ERR,
|
||||
"Internal Error: Couln't add entry for '%s' in the hashmap", name);
|
||||
}
|
||||
|
||||
rules_list = list_append(rules_list, name);
|
||||
|
|
@ -203,9 +109,8 @@ static void register_variable(char *name, char *value)
|
|||
int err = hashmap_insert(variables, name, value, NULL);
|
||||
if (!err)
|
||||
{
|
||||
exit_on_error(
|
||||
GENERIC_ERR,
|
||||
"Internal Error: Couln't add entry for '%s' in the hashmap", name);
|
||||
drop(GENERIC_ERR,
|
||||
"Internal Error: Couln't add entry for '%s' in the hashmap", name);
|
||||
}
|
||||
|
||||
variables_list = list_append(variables_list, name);
|
||||
|
|
@ -238,10 +143,9 @@ static struct list *read_deps(struct line *l, size_t offset)
|
|||
if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0'
|
||||
&& buf[i] != '\n')
|
||||
{
|
||||
exit_on_error(
|
||||
GENERIC_ERR,
|
||||
"Unexpected character '%c' after rule declaration at %lu:%lu",
|
||||
buf[i], l->number, i);
|
||||
drop(GENERIC_ERR,
|
||||
"Unexpected character '%c' after rule declaration at %lu:%lu",
|
||||
buf[i], l->number, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,16 +178,17 @@ static struct list *read_recipe(struct line *l)
|
|||
}
|
||||
else // Add recipe to list
|
||||
{
|
||||
char *command = strdup(buf + 1);
|
||||
size_t offset = 1 + skipblanks(buf + 1, l->length - 1);
|
||||
|
||||
char *command = strdup(buf + offset);
|
||||
if (command == NULL)
|
||||
{
|
||||
exit_on_error(
|
||||
GENERIC_ERR,
|
||||
"Internal error: couldn't duplicate string (%lu:1)",
|
||||
l->number);
|
||||
drop(GENERIC_ERR,
|
||||
"Internal error: couldn't duplicate string (%lu:1)",
|
||||
l->number);
|
||||
}
|
||||
|
||||
command[l->length - 2] = '\0';
|
||||
command[l->length - offset - 1] = '\0';
|
||||
res = list_append(res, command);
|
||||
}
|
||||
}
|
||||
|
|
@ -292,8 +197,10 @@ static struct list *read_recipe(struct line *l)
|
|||
return res;
|
||||
}
|
||||
|
||||
// === Variable Expansion ===
|
||||
|
||||
// Reads the value after a variable declaration
|
||||
static char *read_value(char *buf, size_t buf_len)
|
||||
static char *read_variable_value(char *buf, size_t buf_len)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t str_buf_size = STRING_BUFFER_SIZE;
|
||||
|
|
@ -307,7 +214,7 @@ static char *read_value(char *buf, size_t buf_len)
|
|||
str_buf_size += STRING_BUFFER_SIZE;
|
||||
str_buf = realloc(str_buf, str_buf_size);
|
||||
if (str_buf == NULL)
|
||||
exit_on_error(GENERIC_ERR, "Could not realloc");
|
||||
drop(GENERIC_ERR, "Could not realloc");
|
||||
}
|
||||
|
||||
str_buf[i] = buf[i];
|
||||
|
|
@ -319,104 +226,123 @@ static char *read_value(char *buf, size_t buf_len)
|
|||
return str_buf;
|
||||
}
|
||||
|
||||
// Reads variable name from buf until ')' and stores it into *result
|
||||
// Returns its length on success and -1 on fail
|
||||
// WARNING allocates memory on the heap, free *result after use
|
||||
static size_t read_variable_name(struct line *line, size_t index, char **result)
|
||||
{
|
||||
size_t i = index;
|
||||
char *buf = line->buffer;
|
||||
|
||||
// Alloc var_buf
|
||||
size_t var_buf_size = STRING_BUFFER_SIZE;
|
||||
char *var_buf = malloc(sizeof(char) * var_buf_size);
|
||||
if (var_buf == NULL)
|
||||
drop(GENERIC_ERR, "Could not allocate more memory");
|
||||
|
||||
size_t var_i = 0;
|
||||
while (buf[i] != '\n' && buf[i] != '\0' && buf[i] != '#' && buf[i] != ')')
|
||||
{
|
||||
// Reallocate more space if necessary
|
||||
var_buf_size = resize_buf(&var_buf, var_buf_size, i);
|
||||
|
||||
// Copy
|
||||
var_buf[var_i] = buf[i];
|
||||
i++;
|
||||
var_i++;
|
||||
}
|
||||
var_buf[var_i] = '\0';
|
||||
|
||||
// Mismatched parenthesis
|
||||
if (buf[i] != ')')
|
||||
{
|
||||
free(var_buf);
|
||||
*result = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
i += 2;
|
||||
*result = var_buf;
|
||||
return i - index;
|
||||
}
|
||||
|
||||
// Searches for variable in database and returns its value
|
||||
// if no value is found, it drops an error and exit the program
|
||||
// WARNING variable must be allocated on the heap as this function may attempt
|
||||
// to free it
|
||||
// NOTE Takes line_number to print an helpful error message
|
||||
static char *get_variable_value(char *variable_name, size_t line_number)
|
||||
{
|
||||
char *value = hashmap_get(variables, variable_name);
|
||||
if (value == NULL)
|
||||
{
|
||||
// Adds tmp_buf to the list of items to free
|
||||
variables_list = list_append(variables_list, variable_name);
|
||||
drop(GENERIC_ERR, "Could not find specified variable '%s' at line %lu",
|
||||
variable_name, line_number);
|
||||
}
|
||||
|
||||
free(variable_name);
|
||||
return value;
|
||||
}
|
||||
|
||||
// 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 expand_variable(struct line *line, size_t index, char **value)
|
||||
{
|
||||
size_t i = index;
|
||||
char *buf = line->buffer;
|
||||
|
||||
// size_t tmp_buf_size = STRING_BUFFER_SIZE;
|
||||
// char *tmp_buf = malloc(sizeof(char) * tmp_buf_size);
|
||||
// // TODO free on err
|
||||
// Name in parenthesis
|
||||
if (buf[i] == '(')
|
||||
{
|
||||
// Read variable
|
||||
char *var_name;
|
||||
i++;
|
||||
i += read_variable_name(line, i, &var_name);
|
||||
if (var_name == NULL)
|
||||
drop(GENERIC_ERR, "Mismatched parenthesis at %lu:%lu", i,
|
||||
line->number);
|
||||
|
||||
// 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");
|
||||
// }
|
||||
// Get corresponding value
|
||||
*value = get_variable_value(var_name, line->number);
|
||||
|
||||
// // Copy
|
||||
// tmp_buf[i] = buf[i];
|
||||
// i++;
|
||||
// }
|
||||
// Return
|
||||
return i - index;
|
||||
}
|
||||
else // Single char variable
|
||||
{
|
||||
// '$ '
|
||||
if (isblank(buf[i]) || isspace(buf[i]))
|
||||
drop(2, "Unauthorized character '%c' at %lu:%lu", buf[i],
|
||||
line->number, i);
|
||||
else
|
||||
{
|
||||
// Allocate temporary buffer to hold variable name
|
||||
char *var_name = malloc(2 * sizeof(char));
|
||||
if (var_name == NULL)
|
||||
// Seriously, not even two bytes
|
||||
drop(GENERIC_ERR, "Could not allocate memory");
|
||||
|
||||
// // End
|
||||
// tmp_buf[i] = '\0';
|
||||
var_name[0] = buf[i];
|
||||
var_name[1] = '\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);
|
||||
// }
|
||||
// Escape '$$'
|
||||
if (buf[i] == '$')
|
||||
{
|
||||
*value = var_name;
|
||||
return 2;
|
||||
}
|
||||
|
||||
// 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);
|
||||
// }
|
||||
// Get corresponding value
|
||||
*value = get_variable_value(var_name, line->number);
|
||||
}
|
||||
|
||||
// free(tmp_buf);
|
||||
// *value = val;
|
||||
// return 2;
|
||||
// }
|
||||
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
|
||||
|
|
@ -431,7 +357,8 @@ static void parse_line(struct line *current_line)
|
|||
|
||||
// Read name
|
||||
char *name;
|
||||
i += readword(buf + i, line_size - i, &name);
|
||||
// i += readword(buf + i, line_size - i, &name);
|
||||
i += read_declaration(current_line, i, &name);
|
||||
// if (name == NULL)
|
||||
// errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu",
|
||||
// current_line->number, i);
|
||||
|
|
@ -449,7 +376,7 @@ static void parse_line(struct line *current_line)
|
|||
// Variable
|
||||
case '=':
|
||||
i += skipblanks(buf + i + 1, line_size - i) + 1;
|
||||
value = read_value(buf + i, line_size - i);
|
||||
value = read_variable_value(buf + i, line_size - i);
|
||||
register_variable(name, value);
|
||||
break;
|
||||
|
||||
|
|
@ -473,18 +400,16 @@ static void parse_line(struct line *current_line)
|
|||
case '#':
|
||||
if (name != NULL)
|
||||
{
|
||||
exit_on_error(
|
||||
GENERIC_ERR,
|
||||
"Unexpected character '%c' after declaration '%s' at line %lu",
|
||||
buf[i], name, current_line->number);
|
||||
drop(GENERIC_ERR,
|
||||
"Unexpected character '%c' after declaration '%s' at line %lu",
|
||||
buf[i], name, current_line->number);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
exit_on_error(
|
||||
GENERIC_ERR,
|
||||
"Unexpected character '%c' after declaration '%s' at line %lu",
|
||||
buf[i], name, current_line->number);
|
||||
drop(GENERIC_ERR,
|
||||
"Unexpected character '%c' after declaration '%s' at line %lu",
|
||||
buf[i], name, current_line->number);
|
||||
}
|
||||
|
||||
// free(name);
|
||||
|
|
@ -507,7 +432,7 @@ void make_parse(char *path)
|
|||
size_t buf_size = BUFFER_SIZE;
|
||||
char *buf = malloc(sizeof(char) * buf_size);
|
||||
if (buf == NULL)
|
||||
exit_on_error(GENERIC_ERR, "Could not allocate more memory");
|
||||
drop(GENERIC_ERR, "Could not allocate more memory");
|
||||
|
||||
// Parse line by line
|
||||
ssize_t nread;
|
||||
|
|
@ -517,8 +442,7 @@ void make_parse(char *path)
|
|||
while ((nread = getline(&buf, &buf_size, stream)) != -1)
|
||||
{
|
||||
if (nread == -1)
|
||||
exit_on_error(GENERIC_ERR, "Could not get line %lu",
|
||||
current_line.number);
|
||||
drop(GENERIC_ERR, "Could not get line %lu", current_line.number);
|
||||
|
||||
current_line.buffer = buf;
|
||||
current_line.length = nread;
|
||||
|
|
@ -535,6 +459,9 @@ void make_parse(char *path)
|
|||
|
||||
// ==== Runtime ====
|
||||
|
||||
// static void make_run(void)
|
||||
// {}
|
||||
|
||||
// ==== MAKE ====
|
||||
|
||||
void make(char *path, int flags, char *argv0)
|
||||
|
|
@ -544,8 +471,79 @@ void make(char *path, int flags, char *argv0)
|
|||
make_parse(path);
|
||||
|
||||
if (flags & FLAGS_PRINT)
|
||||
// errx(GENERIC_ERR, "Not Implemented");
|
||||
dump_database();
|
||||
|
||||
free_all();
|
||||
}
|
||||
|
||||
// Prints an error message before exiting gracefully (by freeing all variables)
|
||||
void drop(int status, char *format, ...)
|
||||
{
|
||||
// Print
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fprintf(stderr, "%s: ", program_name);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(args);
|
||||
|
||||
free_all();
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void dump_database(void)
|
||||
{
|
||||
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)
|
||||
drop(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)
|
||||
drop(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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "lists/lists.h"
|
||||
#include "lines/lines.h"
|
||||
|
||||
// Holds variable information
|
||||
// WARNING its values must be freed after use
|
||||
|
|
@ -39,5 +40,8 @@ struct rule
|
|||
|
||||
void make(char *path, int flags, char* program_name);
|
||||
void make_parse(char *path);
|
||||
void drop(int status, char *format, ...);
|
||||
void dump_database(void);
|
||||
size_t expand_variable(struct line *line, size_t index, char **value);
|
||||
|
||||
#endif // ! MINIMAKE_H
|
||||
|
|
|
|||
36
minimake/tests/Makefile2.syntax-test
Normal file
36
minimake/tests/Makefile2.syntax-test
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
SIMPLE_VAR = coucou
|
||||
SIMPLE_VAR_COMMENT = the comment is gone # comment
|
||||
$(SIMPLE_VAR) = 1
|
||||
|
||||
# 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