diff options
| author | Joseph Hunkeler <jhunkeler@gmail.com> | 2026-03-25 13:22:42 -0400 |
|---|---|---|
| committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2026-03-25 13:22:42 -0400 |
| commit | 44342619d43375313b56f7c530c4532b0f69be25 (patch) | |
| tree | cbb68df916001a3b6c3ea17eeea40e28cdc8f307 /targetlist.c | |
| parent | d79588bdf85b8c1514019e679c7eefbc9014edd9 (diff) | |
| download | do-44342619d43375313b56f7c530c4532b0f69be25.tar.gz | |
Refactor program structure
Diffstat (limited to 'targetlist.c')
| -rw-r--r-- | targetlist.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/targetlist.c b/targetlist.c new file mode 100644 index 0000000..574376d --- /dev/null +++ b/targetlist.c @@ -0,0 +1,301 @@ +#include "common.h" + +struct TargetList *target_list_new(const size_t len) { + struct TargetList *list = calloc(1, sizeof(struct TargetList)); + if (!list) { + fprintf(stderr, "unable to allocate memory for list\n"); + return NULL; + } + + list->count_alloc = len; + list->targets = calloc(list->count_alloc + 1, sizeof(struct Target *)); + if (!list->targets) { + fprintf(stderr, "unable to allocate memory for list->targets\n"); + safe_free(list); + return NULL; + } + + return list; +} + +// Append a target list to an existing target list +int target_list_append(struct TargetList **dest, const struct TargetList *src) { + for (size_t i = 0; i < src->count_used; i++) { + struct Target *t = src->targets[i]; + if (!t) { + return -1; + } + target_list_add((*dest), t); + } + return 0; +} + +// Add target to list +int target_list_add(struct TargetList *list, struct Target *t) { + if (list->count_used >= list->count_alloc) { + fprintf(stderr, "%p: growing list from %zu records ", list, list->count_alloc); + list->count_alloc *= 2; + fprintf(stderr, "to %zu records\n", list->count_alloc); + struct Target **tmp = realloc(list->targets, list->count_alloc * sizeof(*list->targets)); + if (!tmp) { + fprintf(stderr, "unable to reallocate memory for target list\n"); + return -1; + } + list->targets = tmp; + } + list->targets[list->count_used] = t; + list->count_used++; + return 0; +} + +void target_list_free(struct TargetList **list) { + if (!list || !*list) { + return; + } + for (size_t i = 0; i < (*list)->count_used; i++) { + target_free(&(*list)->targets[i]); + } + safe_free((*list)->targets); + safe_free(*list); +} + +struct Target *target_list_get(const struct TargetList *list, const char *id) { + for (size_t i = 0; i < list->count_used; i++) { + struct Target *t = list->targets[i]; + if (strcmp(t->id, id) == 0) { + return t; + } + } + return NULL; +} + +struct TargetList *target_list_from_file(const char *filename) { + struct TargetList *list = target_list_new(TARGETLIST_INITIAL_COUNT); + if (!list) { + return NULL; + } + + FILE *fp = fopen(filename, "r"); + if (!fp) { + target_list_free(&list); + return NULL; + } + + char *line = calloc(BUFSIZ + 1, sizeof(char)); + if (!line) { + target_list_free(&list); + return NULL; + } + + size_t buffer_size = BUFSIZ; + struct Target *t = NULL; + size_t line_no = 0; + while (getline(&line, &buffer_size, fp) > 0) { + // Skip comments + if (line[0] == '#') { + line_no++; + continue; + } + + char *deps_delim = strchr(line, ':'); + const char *deps = deps_delim ? deps_delim + 1 : NULL; + char *var_delim = strchr(line, '='); + const int is_var = isalpha(line[0]) && var_delim != NULL; + const int is_target = isalnum(line[0]) && deps_delim != NULL; + const int is_script = isspace(line[0]); + const int is_include = strncmp(line, "include", strlen("include")) == 0; + + if (t && is_script) { + if (!t->script) { + t->script = calloc(BUFSIZ + 1, sizeof(char)); + if (!t->script) { + fprintf(stderr, "unable to allocate memory for script data\n"); + safe_free(line); + target_list_free(&list); + return NULL; + } + t->info.filename = strdup(filename); + if (!t->info.filename) { + fprintf(stderr, "unable to allocate memory for info.filename\n"); + safe_free(line); + target_list_free(&list); + return NULL; + } + } + char *buf_start = line; + for (size_t i = 0; i < strlen(line); i++) { + if (line[i] == '\t' && i < 4) { + continue; + } + if (isspace(line[i]) && i < 4) { + continue; + } + buf_start = &line[i]; + break; + } + strcat(t->script, buf_start); + } else if (is_target) { + t = target_new(); + if (!t) { + fprintf(stderr, "unable to allocate memory for new target\n"); + safe_free(line); + target_free(&t); + target_list_free(&list); + return NULL; + } + t->info.line_no = line_no; + t->info.line = strdup(line); + + if (!deps_delim) { + fprintf(stderr, "%s: line %lu: invalid target definition: %s\n", filename, t->info.line_no, line); + fprintf(stderr, ">>> %s\n", t->info.line); + safe_free(line); + target_free(&t); + target_list_free(&list); + return NULL; + } + *deps_delim = '\0'; + t->id = strdup(line); + if (deps) { + t->_tmp_deps = strdup(deps); + if (!t->_tmp_deps) { + fprintf(stderr, "unable to allocate memory for temporary dependency data\n"); + safe_free(line); + target_free(&t); + target_list_free(&list); + return NULL; + } + if (t->_tmp_deps[strlen(t->_tmp_deps) ? strlen(t->_tmp_deps) - 1 : 0] == '\n') { + t->_tmp_deps[strlen(t->_tmp_deps) ? strlen(t->_tmp_deps) - 1 : 0] = '\0'; + } + } + target_list_add(list, t); + } else if (is_var) { + printf("variable detected\n"); + size_t num_split = 0; + char **pair = split(line, "=", 1, &num_split); + if (num_split < 2) { + fprintf(stderr, "%s: line: %lu: invalid variable definition: %s\n", filename, line_no, line); + fprintf(stderr, ">>> %s\n", line); + safe_free(line); + target_free(&t); + target_list_free(&list); + return NULL; + } + safe_free_array(pair, num_split); + } else if (is_include) { + size_t num_split = 0; + char **pair = split(line, " ", 1, &num_split); + if (!pair) { + fprintf(stderr, "%s: line: %lu: invalid include definition: %s\n", filename, line_no, line); + fprintf(stderr, ">>> %s\n", line); + safe_free(line); + target_free(&t); + target_list_free(&list); + return NULL; + } + if (pair[1][strlen(pair[1]) ? strlen(pair[1]) - 1 : 0] == '\n') { + pair[1][strlen(pair[1]) ? strlen(pair[1]) - 1 : 0] = '\0'; + } + + printf("Including file: %s\n", pair[1]); + struct TargetList *included_targets = target_list_from_file(pair[1]); + if (included_targets) { + if (target_list_append(&list, included_targets)) { + fprintf(stderr, "unable to append to target list %p\n", list); + safe_free(line); + target_list_free(&list); + return NULL; + } + for (size_t i = 0; i < list->count_used; i++) { + included_targets->targets[i] = NULL; + } + free(included_targets->targets); + free(included_targets); + } else { + fprintf(stderr, "%s: line %lu: failed to include file: %s\n", filename, line_no, pair[1]); + safe_free(line); + safe_free_array(pair, num_split); + target_free(&t); + target_list_free(&list); + return NULL; + } + safe_free_array(pair, num_split); + } + line_no++; + } + + // Add dependencies + for (size_t i = 0; i < list->count_used; i++) { + if (!list->targets[i]->_tmp_deps || !strlen(list->targets[i]->_tmp_deps)) { + continue; + } + char *_tmp_deps_orig = list->targets[i]->_tmp_deps; + list->targets[i]->dependencies = target_list_new(TARGETLIST_INITIAL_COUNT); + const char *token = NULL; + while ((token = strsep(&list->targets[i]->_tmp_deps, " ")) != NULL) { + char *data = strdup(token); + if (!strlen(data)) { + safe_free(data); + continue; + } + + if (data[strlen(data) ? strlen(data) - 1 : 0] == '\n') { + data[strlen(data) ? strlen(data) - 1 : 0] = '\0'; + } + + const int target_exists = target_list_get(list, data) != NULL; + if (!target_exists) { + fprintf(stderr, "%s: line %lu: target not found: %s\n", filename, line_no, data); + fprintf(stderr, ">>> %s\n", list->targets[i]->info.line); + safe_free(data); + safe_free(line); + target_list_free(&list); + return NULL; + } + + for (size_t j = 0; j < list->count_used; j++) { + if (strcmp(list->targets[j]->id, data) == 0) { + if (list->targets[i]->id == list->targets[j]->id) { + fprintf(stderr, "%s: line %lu: target '%s' cannot target itself (circular dependency)\n", filename, list->targets[i]->info.line_no + 1, list->targets[i]->id); + fprintf(stderr, ">>> %s\n", list->targets[i]->info.line); + target_free(&t); + target_list_free(&list); + return NULL; + } + target_list_add(list->targets[i]->dependencies, list->targets[j]); + } + } + safe_free(data); + } + list->targets[i]->_tmp_deps = _tmp_deps_orig; + } + + safe_free(line); + fclose(fp); + return list; +} + +void target_list_show(const struct TargetList *list) { + for (size_t i = 0; i < list->count_used; i++) { + const struct Target *t = list->targets[i]; + printf("TARGET: %s\n", t->id); + printf("DEPENDENCIES: "); + if (t->dependencies && t->dependencies->count_used) { + printf("\n"); + for (size_t j = 0; j < t->dependencies->count_used; j++) { + printf(" - %s\n", t->dependencies->targets[j]->id); + } + } else { + printf("N/A\n"); + } + printf("SCRIPT: "); + if (t->script && strlen(t->script)) { + printf("\n%s\n", t->script); + } else { + printf("N/A\n"); + } + printf("\n"); + } +} + |
