diff --git a/minimake/src/hash_maps/hash_maps.c b/minimake/src/hash_maps/hash_maps.c index d97a420..405a0f9 100644 --- a/minimake/src/hash_maps/hash_maps.c +++ b/minimake/src/hash_maps/hash_maps.c @@ -27,7 +27,7 @@ size_t hash(const char *key) return hash; } -struct hash_map *hashMapInit(size_t size) +struct hash_map *hashmap_init(size_t size) { struct pair_list **data = calloc(size, sizeof(struct pair_list)); struct hash_map *map = malloc(sizeof(struct hash_map)); @@ -36,8 +36,8 @@ struct hash_map *hashMapInit(size_t size) return map; } -bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, - bool *updated) +bool hashmap_insert(struct hash_map *hash_map, char *key, void *value, + bool *updated) { if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) { @@ -79,7 +79,7 @@ bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, return true; } -void hashMapFree(struct hash_map *hash_map) +void hashmap_free(struct hash_map *hash_map) { if (hash_map == NULL) return; @@ -100,7 +100,10 @@ void hashMapFree(struct hash_map *hash_map) free(hash_map); } -void hashMapDump(struct hash_map *hash_map) +// WARNING +// Will only work with string values +// DO NOT attempt to call it with anything else +void hashmap_dump(struct hash_map *hash_map) { for (size_t i = 0; i < hash_map->size; i++) { @@ -109,12 +112,14 @@ void hashMapDump(struct hash_map *hash_map) if (entry != NULL) { is_null = false; - printf("%s: %s", entry->key, entry->value); + char *val = entry->value; + printf("%s: %s", entry->key, val); entry = entry->next; } while (entry != NULL) { - printf(", %s: %s", entry->key, entry->value); + char *val = entry->value; + printf(", %s: %s", entry->key, val); entry = entry->next; } if (!is_null) @@ -122,7 +127,7 @@ void hashMapDump(struct hash_map *hash_map) } } -const char *hashMapGet(const struct hash_map *hash_map, const char *key) +void *hashmap_get(const struct hash_map *hash_map, char *key) { if (hash_map == NULL || hash_map->data == NULL || hash_map->size == 0) return NULL; @@ -139,7 +144,7 @@ const char *hashMapGet(const struct hash_map *hash_map, const char *key) return entry->value; } -bool hashMapRemove(struct hash_map *hash_map, const char *key) +bool hashmap_remove(struct hash_map *hash_map, char *key) { if (hash_map == NULL || hash_map->size == 0 || hash_map->data == NULL) return false; diff --git a/minimake/src/hash_maps/hash_maps.h b/minimake/src/hash_maps/hash_maps.h index ca21916..97a84da 100644 --- a/minimake/src/hash_maps/hash_maps.h +++ b/minimake/src/hash_maps/hash_maps.h @@ -1,13 +1,17 @@ -#ifndef HASH_MAP_H -#define HASH_MAP_H +#ifndef HASH_MAPS_H +#define HASH_MAPS_H #include #include +// WARNING I made the choice to discard the const qualifier of the key argument +// To add the possibility to free it. +// Note that key should *NEVER* be changed once it has been added to the hashmap + struct pair_list { - const char *key; - char *value; + char *key; + void *value; struct pair_list *next; }; @@ -18,12 +22,12 @@ struct hash_map }; size_t hash(const char *str); -struct hash_map *hashMapInit(size_t size); -bool hashMapInsert(struct hash_map *hash_map, const char *key, char *value, +struct hash_map *hashmap_init(size_t size); +bool hashmap_insert(struct hash_map *hash_map, char *key, void *value, bool *updated); -void hashMapFree(struct hash_map *hash_map); -void hashMapDump(struct hash_map *hash_map); -const char *hashMapGet(const struct hash_map *hash_map, const char *key); -bool hashMapRemove(struct hash_map *hash_map, const char *key); +void hashmap_free(struct hash_map *hash_map); +void hashmap_dump(struct hash_map *hash_map); +void *hashmap_get(const struct hash_map *hash_map, char *key); +bool hashmap_remove(struct hash_map *hash_map, char *key); -#endif /* ! HASH_MAP_H */ +#endif /* ! HASH_MAPS_H */ diff --git a/minimake/src/lines/lines.c b/minimake/src/lines/lines.c index bf82c56..dcf0c19 100644 --- a/minimake/src/lines/lines.c +++ b/minimake/src/lines/lines.c @@ -7,13 +7,13 @@ #include // Helps to match a string (excludes blanks and special characters) -int isChar(char c) +int ischar(char c) { return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#' && c != '\n'; } -int skipBlanks(char *buf, size_t buf_len) +int skipblanks(char *buf, size_t buf_len) { size_t i = 0; while (i < buf_len && (isblank(buf[i]) || buf[i] == '\n')) @@ -22,7 +22,7 @@ int skipBlanks(char *buf, size_t buf_len) } // Returns 1 if line is blank -int isBlankLine(struct line *l) +int isblankline(struct line *l) { size_t line_size = l->length; char *buf = l->buffer; @@ -42,12 +42,12 @@ int isBlankLine(struct line *l) // 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 -size_t readWord(char *buf, size_t buf_len, char **word) +size_t readword(char *buf, size_t buf_len, char **word) { size_t i = 0; size_t res_size = STRING_BUFFER_SIZE; char *res = malloc(sizeof(char) * res_size); - while (i < buf_len && isChar(buf[i])) + while (i < buf_len && ischar(buf[i])) { // Reallocate more space if necessary if (i >= res_size - 1) diff --git a/minimake/src/lines/lines.h b/minimake/src/lines/lines.h index 8ac1d73..01ace9d 100644 --- a/minimake/src/lines/lines.h +++ b/minimake/src/lines/lines.h @@ -18,9 +18,9 @@ struct line FILE* file_stream; // Full file stream }; -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); +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); #endif // LINES_H diff --git a/minimake/src/main.c b/minimake/src/main.c index c2d7a0b..07ee99d 100644 --- a/minimake/src/main.c +++ b/minimake/src/main.c @@ -123,5 +123,5 @@ int main(int argc, char **argv) if (filename == NULL) errx(GENERIC_ERR, "No Makefile found"); - make(filename, flags); + make(filename, flags, argv[0]); } diff --git a/minimake/src/minimake.c b/minimake/src/minimake.c index c8d66be..6e23a75 100644 --- a/minimake/src/minimake.c +++ b/minimake/src/minimake.c @@ -15,50 +15,81 @@ // Static variables struct hash_map *variables = NULL; struct hash_map *rules = NULL; +char *program_name; + +// ==== Misc ==== + +static void hashmap_deep_free(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->key); + free(entry->value); + free(entry); + entry = next; + } + } + free(hash_map->data); + free(hash_map); +} + +static void free_all() +{ + hashmap_deep_free(rules); + hashmap_deep_free(variables); +} + +// static void dump_database() +// { +// hashmap_dump(variables); +// hashmap_dump(rules); +// } // ==== Parsing ==== -// Registers a new variable and returns its pointer +// Registers a new rule in the hashmap // WARNING Allocates memory on the heap, -// the variables hashmap should be freed before exit -static struct variable *createVariable(char *name) +// the rules hashmap should be freed before exit +static void register_rule(char *name, struct list *dependencies, + struct list *recipe) { - struct variable *res = malloc(sizeof(struct variable)); - res->name = name; - res->value = NULL; + struct rule *rule = malloc(sizeof(struct rule)); + rule->name = name; + rule->dependencies = dependencies; + rule->recipe = recipe; - int err = hashMapInsert(variables, name, NULL, NULL); + int err = hashmap_insert(variables, name, rule, NULL); + if (!err) + { + errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap", + name); + } +} + +// Registers a new variable in the hashmap +// WARNING Allocates memory on the heap, +// the variables hashmap should be freed before exit +static void register_variable(char *name, char *value) +{ + int err = hashmap_insert(variables, name, value, NULL); if (!err) { - // free(name); - free(res); errx(2, "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(struct line *l, size_t offset) +static struct list *read_deps(struct line *l, size_t offset) { size_t i = offset; size_t buf_size = l->length; @@ -67,11 +98,11 @@ static struct list *readDependencies(struct line *l, size_t offset) while (i < buf_size) { - i += skipBlanks(buf + i, buf_size - i); + i += skipblanks(buf + i, buf_size - i); // Read word char *dep_name; - i += readWord(buf + i, buf_size - i, &dep_name); + i += readword(buf + i, buf_size - i, &dep_name); if (dep_name != NULL) // Add to list res = list_append(res, dep_name); @@ -81,7 +112,7 @@ static struct list *readDependencies(struct line *l, size_t offset) return res; // Unknown chars - if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' + if (!ischar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0' && buf[i] != '\n') { printf("DEBUG: line: %s", l->buffer); @@ -97,7 +128,7 @@ static struct list *readDependencies(struct line *l, size_t offset) // 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) +static struct list *read_recipe(struct line *l) { FILE *stream = l->file_stream; char *buf = l->buffer; @@ -111,7 +142,7 @@ static struct list *readRecipe(struct line *l) l->number++; // Skip blank lines and comments - if (isBlankLine(l)) + if (isblankline(l)) continue; else if (buf[0] != '\t') // Not a recipe { @@ -134,7 +165,7 @@ static struct list *readRecipe(struct line *l) } // Reads the value after a variable declaration -static char *readValue(char *buf, size_t buf_size) +static char *read_value(char *buf, size_t buf_size) { size_t i = 0; size_t str_buf_size = STRING_BUFFER_SIZE; @@ -164,48 +195,49 @@ static char *readValue(char *buf, size_t buf_size) // 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(struct line *current_line) +static void parse_line(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); + i += skipblanks(buf + i, line_size - i); // Read name char *name; - i += readWord(buf + i, line_size - i, &name); + i += readword(buf + i, line_size - i, &name); // if (name == NULL) // errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu", // current_line->number, i); - i += skipBlanks(buf + i, line_size - i); + i += skipblanks(buf + i, line_size - i); // Potential elements - struct rule *new_rule; - struct variable *new_variable; + struct list *dependencies; + struct list *recipe; + char *value; // Definition type switch (buf[i]) { // Variable case '=': - new_variable = createVariable(name); - new_variable->value = readValue(buf + i, line_size); + value = read_value(buf + i, line_size); + register_variable(name, value); break; // Rule case ':': - new_rule = createRule(name); - new_rule->dependencies = readDependencies(current_line, i + 1); - new_rule->recipe = readRecipe(current_line); + dependencies = read_deps(current_line, i + 1); + recipe = read_recipe(current_line); + register_rule(name, dependencies, recipe); // Check for EOF if (current_line->length == -1) return; - parseLine(current_line); + parse_line(current_line); // TODO: check for loooooops break; @@ -228,7 +260,7 @@ static void parseLine(struct line *current_line) // free(name); } -void makeParse(char *path) +void make_parse(char *path) { // Open file FILE *stream = fopen(path, "r"); @@ -236,8 +268,8 @@ void makeParse(char *path) errx(2, "Could not open file: %s", path); // Init hash maps - variables = hashMapInit(HASHMAP_SIZE); - rules = hashMapInit(HASHMAP_SIZE); + variables = hashmap_init(HASHMAP_SIZE); + rules = hashmap_init(HASHMAP_SIZE); if (variables == NULL || rules == NULL) errx(1, "Internal error: Failed to initiate hash maps"); @@ -260,7 +292,7 @@ void makeParse(char *path) current_line.buffer = buf; current_line.length = nread; - parseLine(¤t_line); + parse_line(¤t_line); current_line.number += 1; } @@ -274,18 +306,14 @@ void makeParse(char *path) // ==== MAKE ==== -void make(char *path, int flags) +void make(char *path, int flags, char *argv0) { + program_name = argv0; + if (flags & FLAGS_PRINT) errx(GENERIC_ERR, "Not Implemented"); - makeParse(path); + make_parse(path); + // dump_database(); + free_all(); } - -// ==== Misc ==== - -// static void free_all() -// { -// hashMapFree(rules); -// hashMapFree(variables); -// } diff --git a/minimake/src/minimake.h b/minimake/src/minimake.h index 374eca4..ccd5f08 100644 --- a/minimake/src/minimake.h +++ b/minimake/src/minimake.h @@ -37,6 +37,7 @@ struct rule struct list *recipe; }; -void make(char *path, int flags); +void make(char *path, int flags, char* program_name); +void make_parse(char *path); #endif // ! MINIMAKE_H