+typedef struct {
+ char * name;
+ char * value;
+} cgit_env_var;
+
+void cgit_prepare_repo_env(struct cgit_repo * repo)
+{
+ cgit_env_var env_vars[] = {
+ { .name = "CGIT_REPO_URL", .value = repo->url },
+ { .name = "CGIT_REPO_NAME", .value = repo->name },
+ { .name = "CGIT_REPO_PATH", .value = repo->path },
+ { .name = "CGIT_REPO_OWNER", .value = repo->owner },
+ { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
+ { .name = "CGIT_REPO_SECTION", .value = repo->section },
+ { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
+ };
+ int env_var_count = ARRAY_SIZE(env_vars);
+ cgit_env_var *p, *q;
+ static char *warn = "cgit warning: failed to set env: %s=%s\n";
+
+ p = env_vars;
+ q = p + env_var_count;
+ for (; p < q; p++)
+ if (p->value && setenv(p->name, p->value, 1))
+ fprintf(stderr, warn, p->name, p->value);
+}
+
+/* Read the content of the specified file into a newly allocated buffer,
+ * zeroterminate the buffer and return 0 on success, errno otherwise.
+ */
+int readfile(const char *path, char **buf, size_t *size)
+{
+ int fd, e;
+ struct stat st;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return errno;
+ if (fstat(fd, &st)) {
+ e = errno;
+ close(fd);
+ return e;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ close(fd);
+ return EISDIR;
+ }
+ *buf = xmalloc(st.st_size + 1);
+ *size = read_in_full(fd, *buf, st.st_size);
+ e = errno;
+ (*buf)[*size] = '\0';
+ close(fd);
+ return (*size == st.st_size ? 0 : e);
+}
+
+static int is_token_char(char c)
+{
+ return isalnum(c) || c == '_';
+}
+
+/* Replace name with getenv(name), return pointer to zero-terminating char
+ */
+static char *expand_macro(char *name, int maxlength)