aboutsummaryrefslogtreecommitdiff
path: root/target.c
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2026-03-25 13:22:42 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2026-03-25 13:22:42 -0400
commit44342619d43375313b56f7c530c4532b0f69be25 (patch)
treecbb68df916001a3b6c3ea17eeea40e28cdc8f307 /target.c
parentd79588bdf85b8c1514019e679c7eefbc9014edd9 (diff)
downloaddo-44342619d43375313b56f7c530c4532b0f69be25.tar.gz
Refactor program structure
Diffstat (limited to 'target.c')
-rw-r--r--target.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/target.c b/target.c
new file mode 100644
index 0000000..bbda4e6
--- /dev/null
+++ b/target.c
@@ -0,0 +1,131 @@
+#include "common.h"
+
+struct Target *target_new() {
+ struct Target *t = calloc(1, sizeof(struct Target));
+ return t;
+}
+
+struct Target *target_clone(const struct Target *src) {
+ struct Target *t = target_new();
+ if (!t) {
+ fprintf(stderr, "unable to allocate memory to clone target\n");
+ return NULL;
+ }
+ t->id = src->id ? strdup(src->id) : NULL;
+ t->_tmp_deps = src->_tmp_deps ? strdup(src->_tmp_deps) : NULL;
+ t->script = src->script ? strdup(src->script) : NULL;
+ t->info.line = src->info.line ? strdup(src->info.line) : NULL;
+ t->info.filename = src->info.filename ? strdup(src->info.filename) : NULL;
+ if (src->dependencies && src->dependencies->count_used) {
+ t->dependencies = target_list_new(src->dependencies->count_alloc);
+ if (!t->dependencies) {
+ fprintf(stderr, "unable to allocate memory to clone target dependencies\n");
+ return NULL;
+ }
+ for (size_t i = 0; i < src->dependencies->count_used; i++) {
+ struct Target *src_target = src->dependencies->targets[i];
+ target_list_add(t->dependencies, src_target);
+ }
+ }
+ return t;
+}
+
+char *target_create_script_file(struct Target *t) {
+ char template[] = TARGET_SCRIPT_FILENAME_TEMPLATE;
+ if (mkstemps(template, 0) < 0) {
+ perror("mkstemps");
+ return NULL;
+ }
+ return strdup(template);
+}
+
+int target_run_all(struct Target *t, size_t *depth) {
+ int fail = 0;
+
+ *depth += 1;
+ if (*depth > TARGET_RUN_MAX_DEPTH) {
+ fprintf(stderr, "maximum recursion depth reached: %d\n", TARGET_RUN_MAX_DEPTH);
+ if (t) {
+ fprintf(stderr, "%s: line %lu: %s\n", t->info.filename ? t->info.filename : "???", t->info.line_no, t->info.line);
+ }
+ *depth -= 1;
+ return -1;
+ }
+
+ if (t && t->dependencies) {
+ for (size_t i = 0; i < t->dependencies->count_used; i++) {
+ struct Target *d = t->dependencies->targets[i];
+
+ if (target_run_all(d, depth)) {
+ fail = 1;
+ *depth -= 1;
+ break;
+ }
+ }
+ }
+ if (!fail) {
+ *depth -= 1;
+ return target_run(t, depth);
+ }
+ *depth -= 1;
+ return -1;
+}
+
+int target_run(struct Target *t, const size_t *depth) {
+ if (!t || *depth > 100) {
+ return -1;
+ }
+ char *filename = target_create_script_file(t);
+ if (!filename) {
+ fprintf(stderr, "failed to create target script\n");
+ return -1;
+ }
+
+ if (chmod(filename, 0750) < 0) {
+ perror("chmod");
+ safe_free(filename);
+ return -1;
+ }
+
+ FILE *fp = fopen(filename, "w+");
+ if (!fp) {
+ perror("unable to open target script for writing");
+ remove(filename);
+ safe_free(filename);
+ return -1;
+ }
+ fprintf(fp, "%s", t->script ? t->script : "");
+ fclose(fp);
+
+ char *cmd = NULL;
+ if (asprintf(&cmd, "bash %s", filename) < 0) {
+ perror("asprintf");
+ remove(filename);
+ safe_free(filename);
+ return -1;
+ }
+
+ printf("==> Running target %s\n", t->id);
+ const int status = system(cmd);
+ remove(filename);
+
+ safe_free(cmd);
+ safe_free(filename);
+
+ return status;
+}
+
+void target_free(struct Target **target) {
+ safe_free((*target)->id);
+ safe_free((*target)->_tmp_deps);
+ safe_free((*target)->script);
+ safe_free((*target)->info.line);
+ safe_free((*target)->info.filename);
+ if ((*target)->dependencies) {
+ // Dependencies are shared between lists. Do not wipe out the targets _here_.
+ safe_free((*target)->dependencies->targets);
+ safe_free((*target)->dependencies);
+ }
+ safe_free((*target));
+}
+