From 1162201323719e9841fc70128a933fadd417a72e Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 31 Oct 2026 14:30:27 -0700 Subject: Move cgit.c's own helpers out of shared.c --- source/cgit.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- source/shared.c | 68 ---------------------------------------------- source/shared.h | 12 --------- 3 files changed, 78 insertions(+), 86 deletions(-) diff --git a/source/cgit.c b/source/cgit.c index dd90fed..3ae895d 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -86,6 +86,13 @@ static NORETURN void die_routine(const char *msg, va_list params) exit(0); } +static char *ensure_end(const char *str, char c) +{ + size_t len = strlen(str); + + return len && str[len - 1] == c ? xstrdup(str) : xstrfmt("%s%c", str, c); +} + static void prepare_context(void) { const char *script_name = getenv("SCRIPT_NAME"); @@ -154,7 +161,7 @@ static void prepare_context(void) string_list_init_dup(&ctx.cfg.mimetypes); if (script_name) ctx.cfg.script_name = xstrdup(script_name); - ctx.cfg.virtual_root = cgit_ensure_end(ctx.cfg.script_name, '/'); + ctx.cfg.virtual_root = ensure_end(ctx.cfg.script_name, '/'); if (ctx.env.query_string) ctx.qry.raw = xstrdup(ctx.env.query_string); if (!ctx.env.cgit_config) @@ -463,6 +470,46 @@ static void add_mimetype(const char *name, const char *value) item->util = xstrdup(value); } +/* + * Accept only the date formats cgit documents, leaving mode unchanged for + * anything else. Git's parse_date_format dies on anything unknown, which would + * turn a cgitrc typo into a failed request. + */ +static void parse_date_setting(const char *format, struct date_mode *mode) +{ + static const char * const names[] = { + "default", "human", "iso", "iso-strict", "iso8601", + "iso8601-strict", "raw", "relative", "rfc", + "rfc2822", "short", "unix", + }; + const char *rest; + size_t i; + + if (skip_prefix(format, "format:", &rest)) { + // An empty strftime format would render every date blank. + if (*rest) + parse_date_format(format, mode); + return; + } + + // git reads local only as a whole alias of default-local, and dies on + // it with a suffix of its own. + if (!strcmp(format, "local")) { + parse_date_format(format, mode); + return; + } + + for (i = 0; i < ARRAY_SIZE(names); i++) { + if (!skip_prefix(format, names[i], &rest)) + continue; + // "iso" also prefixes "iso8601", so a partial hit is skipped. + if (*rest && strcmp(rest, "-local")) + continue; + parse_date_format(format, mode); + return; + } +} + static void apply_config(const char *name, const char *value) { const char *arg; @@ -504,7 +551,7 @@ static void apply_config(const char *name, const char *value) else if (!strcmp(name, "strict-export")) ctx.cfg.strict_export = cgit_strdup_first_line(value); else if (!strcmp(name, "virtual-root")) - ctx.cfg.virtual_root = cgit_ensure_end(value, '/'); + ctx.cfg.virtual_root = ensure_end(value, '/'); else if (!strcmp(name, "enable-plain-email")) ctx.cfg.enable_plain_email = atoi(value); else if (!strcmp(name, "enable-header")) @@ -656,7 +703,7 @@ static void apply_config(const char *name, const char *value) else if (!strcmp(name, "local-time")) ctx.cfg.local_time = atoi(value); else if (!strcmp(name, "date-format")) - cgit_parse_date_format(value, &ctx.cfg.date_mode); + parse_date_setting(value, &ctx.cfg.date_mode); else if (!strcmp(name, "commit-sort")) { if (!strcmp(value, "date")) ctx.cfg.commit_sort = 1; @@ -1024,6 +1071,31 @@ static void choose_readme(struct cgit_repo *repo) string_list_append(&repo->readme, filename)->util = ref; } +/* + * Export the CGIT_REPO_* variables that filters and hooks read. + */ +static void prepare_repo_env(struct cgit_repo *repo) +{ + const struct { + const char *name; + const char *value; + } 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 } + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(vars); i++) + if (vars[i].value && setenv(vars[i].name, vars[i].value, 1)) + fprintf(stderr, "[cgit] Unable to set %s=%s: %s (%d)\n", + vars[i].name, vars[i].value, strerror(errno), errno); +} + static void open_repo(int *nongit, int *err) { // A repository configured without a path has nothing to open. @@ -1085,14 +1157,14 @@ static int prepare_repo_cmd(int nongit, int err, int clone) // The dumb transport serves refs and objects off the disk and // asks nothing of the head, and an empty repository clones. if (clone) { - cgit_prepare_repo_env(ctx.repo); + prepare_repo_env(ctx.repo); return 0; } ctx.empty_repo = 1; // Before the document starts, since the carries // and those clone urls expand macros such // as $CGIT_REPO_URL out of this environment. - cgit_prepare_repo_env(ctx.repo); + prepare_repo_env(ctx.repo); cgit_print_layout_start(); cgit_print_empty_repo(); cgit_print_layout_end(); @@ -1116,7 +1188,7 @@ static int prepare_repo_cmd(int nongit, int err, int clone) return 1; } string_list_sort(&ctx.repo->submodules); - cgit_prepare_repo_env(ctx.repo); + prepare_repo_env(ctx.repo); choose_readme(ctx.repo); return 0; } diff --git a/source/shared.c b/source/shared.c index 5c5e65c..72ec2d1 100644 --- a/source/shared.c +++ b/source/shared.c @@ -204,13 +204,6 @@ char *cgit_trim_end(const char *str, char c) return xstrndup(str, len); } -char *cgit_ensure_end(const char *str, char c) -{ - size_t len = strlen(str); - - return len && str[len - 1] == c ? xstrdup(str) : xstrfmt("%s%c", str, c); -} - void strbuf_ensure_end(struct strbuf *sb, char c) { if (!sb->len || sb->buf[sb->len - 1] != c) @@ -366,67 +359,6 @@ void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix) cgit_diff_tree(old_oid, &commit->object.oid, fn, prefix, ctx.qry.ignorews); } -/* - * Git's parse_date_format dies on anything unknown, which would turn a - * cgitrc typo into a failed request, so only documented formats reach it. - */ -void cgit_parse_date_format(const char *format, struct date_mode *mode) -{ - static const char * const names[] = { - "default", "human", "iso", "iso-strict", "iso8601", - "iso8601-strict", "raw", "relative", "rfc", - "rfc2822", "short", "unix", - }; - const char *rest; - size_t i; - - if (skip_prefix(format, "format:", &rest)) { - // An empty strftime format would render every date blank. - if (*rest) - parse_date_format(format, mode); - return; - } - - // git reads local only as a whole alias of default-local, and dies on - // it with a suffix of its own. - if (!strcmp(format, "local")) { - parse_date_format(format, mode); - return; - } - - for (i = 0; i < ARRAY_SIZE(names); i++) { - if (!skip_prefix(format, names[i], &rest)) - continue; - // "iso" also prefixes "iso8601", so a partial hit is skipped. - if (*rest && strcmp(rest, "-local")) - continue; - parse_date_format(format, mode); - return; - } -} - -void cgit_prepare_repo_env(struct cgit_repo *repo) -{ - const struct { - const char *name; - const char *value; - } 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 } - }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(vars); i++) - if (vars[i].value && setenv(vars[i].name, vars[i].value, 1)) - fprintf(stderr, "[cgit] Unable to set %s=%s: %s (%d)\n", - vars[i].name, vars[i].value, strerror(errno), errno); -} - int cgit_read_first_line(const char *path, char **buf) { int fd, err; diff --git a/source/shared.h b/source/shared.h index e1eb39b..909f9f2 100644 --- a/source/shared.h +++ b/source/shared.h @@ -24,11 +24,6 @@ typedef void (*linediff_fn)(char *line, int len); extern struct cgit_repo *cgit_add_repo(const char *url); extern struct cgit_repo *cgit_get_repoinfo(const char *url); -/* - * Export the CGIT_REPO_* variables that filters and hooks read. - */ -extern void cgit_prepare_repo_env(struct cgit_repo *repo); - extern void cgit_free_commitinfo(struct commitinfo *info); extern void cgit_free_taginfo(struct taginfo *info); @@ -71,17 +66,10 @@ extern void cgit_diff_tree(const struct object_id *old_oid, const struct object_ filepair_fn fn, const char *prefix, int ignorews); extern void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix); -/* - * Accept only the date formats cgit documents, leaving mode unchanged for - * anything else. - */ -extern void cgit_parse_date_format(const char *format, struct date_mode *mode); - /* * Copy str without its trailing runs of c, returning NULL if nothing is left. */ extern char *cgit_trim_end(const char *str, char c); -extern char *cgit_ensure_end(const char *str, char c); extern void strbuf_ensure_end(struct strbuf *sb, char c); /* -- cgit