X-Git-Url: https://gitweb.ps.run/ps-cgit/blobdiff_plain/d6dc3aee9acadfe368864f24ea18ccd47bbb0b9b..14f28923a2ed31fba9bf7042e8e2dff21717c333:/shared.c diff --git a/shared.c b/shared.c index 8b3a045..8c3d18a 100644 --- a/shared.c +++ b/shared.c @@ -7,10 +7,11 @@ */ #include "cgit.h" +#include +#include struct cgit_repolist cgit_repolist; struct cgit_context ctx; -int cgit_cmd; int chk_zero(int result, char *msg) { @@ -57,13 +58,14 @@ struct cgit_repo *cgit_add_repo(const char *url) ret->section = ctx.cfg.section; ret->defbranch = "master"; ret->snapshots = ctx.cfg.snapshots; + ret->enable_commit_graph = ctx.cfg.enable_commit_graph; ret->enable_log_filecount = ctx.cfg.enable_log_filecount; ret->enable_log_linecount = ctx.cfg.enable_log_linecount; ret->enable_remote_branches = ctx.cfg.enable_remote_branches; ret->enable_subject_links = ctx.cfg.enable_subject_links; ret->max_stats = ctx.cfg.max_stats; ret->module_link = ctx.cfg.module_link; - ret->readme = NULL; + ret->readme = ctx.cfg.readme; ret->mtime = -1; ret->about_filter = ctx.cfg.about_filter; ret->commit_filter = ctx.cfg.commit_filter; @@ -264,7 +266,8 @@ int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) int cgit_diff_files(const unsigned char *old_sha1, const unsigned char *new_sha1, unsigned long *old_size, - unsigned long *new_size, int *binary, linediff_fn fn) + unsigned long *new_size, int *binary, int context, + int ignorews, linediff_fn fn) { mmfile_t file1, file2; xpparam_t diff_params; @@ -291,7 +294,9 @@ int cgit_diff_files(const unsigned char *old_sha1, memset(&emit_params, 0, sizeof(emit_params)); memset(&emit_cb, 0, sizeof(emit_cb)); diff_params.flags = XDF_NEED_MINIMAL; - emit_params.ctxlen = 3; + if (ignorews) + diff_params.flags |= XDF_IGNORE_WHITESPACE; + emit_params.ctxlen = context > 0 ? context : 3; emit_params.flags = XDL_EMIT_FUNCNAMES; emit_cb.outf = filediff_cb; emit_cb.priv = fn; @@ -305,7 +310,7 @@ int cgit_diff_files(const unsigned char *old_sha1, void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, - filepair_fn fn, const char *prefix) + filepair_fn fn, const char *prefix, int ignorews) { struct diff_options opt; int ret; @@ -316,6 +321,8 @@ void cgit_diff_tree(const unsigned char *old_sha1, opt.detect_rename = 1; opt.rename_limit = ctx.cfg.renamelimit; DIFF_OPT_SET(&opt, RECURSIVE); + if (ignorews) + DIFF_XDL_SET(&opt, IGNORE_WHITESPACE); opt.format_callback = cgit_diff_tree_cb; opt.format_callback_data = fn; if (prefix) { @@ -334,13 +341,14 @@ void cgit_diff_tree(const unsigned char *old_sha1, diff_flush(&opt); } -void cgit_diff_commit(struct commit *commit, filepair_fn fn) +void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix) { unsigned char *old_sha1 = NULL; if (commit->parents) old_sha1 = commit->parents->item->object.sha1; - cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL); + cgit_diff_tree(old_sha1, commit->object.sha1, fn, prefix, + ctx.qry.ignorews); } int cgit_parse_snapshots_mask(const char *str) @@ -370,7 +378,71 @@ int cgit_parse_snapshots_mask(const char *str) return rv; } -int cgit_open_filter(struct cgit_filter *filter) +typedef struct { + char * name; + char * value; +} cgit_env_var; + +static char * prepare_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); + long values_space = (env_var_count * (PATH_MAX + 64)); + + void * buffer; + char ** vars; + char * values; + int vars_index = 0; + unsigned int chars_printed; + + /* Allocate buffer for environment variables: first in the buffer is an + * array of pointers to argument strings, terminated with a NULL pointer. + * After that the argument strings are placed after each other */ + buffer = malloc(((env_var_count + 1) * sizeof(char *)) + values_space); + if (!buffer) + return NULL; + + vars = buffer; + values = (char *) &vars[env_var_count + 1]; + + /* loop over all defined environment variables and their values */ + while (vars_index < env_var_count) { + char * name = env_vars[vars_index].name; + char * value = env_vars[vars_index].value; + + if (!value) + value = ""; + + chars_printed = snprintf(values, (values_space - 1), "%s=%s", name, + value); + if (chars_printed > (values_space - 1)) { + /* Buffer space exhausted: stop adding variables. + * Not all environment variables are defined, but the best we can + * do is to provide the ones that _are_ defined */ + break; + } + + values[chars_printed] = '\0'; + *&vars[vars_index] = values; + values += (chars_printed + 1); + values_space -= (chars_printed + 1); + vars_index++; + } + + /* terminate the array with pointers */ + *&vars[vars_index] = NULL; + + return (char *) buffer; +} + +int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo) { filter->old_stdout = chk_positive(dup(STDOUT_FILENO), @@ -378,10 +450,20 @@ int cgit_open_filter(struct cgit_filter *filter) chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess"); filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); if (filter->pid == 0) { + char * env = NULL; + close(filter->pipe_fh[1]); chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), "Unable to use pipe as STDIN"); - execvp(filter->cmd, filter->argv); + + if (repo) + env = prepare_env(repo); + + execve(filter->cmd, filter->argv, (char **)env); + + if (env) + free(env); + die("Unable to exec subprocess %s: %s (%d)", filter->cmd, strerror(errno), errno); } @@ -432,3 +514,74 @@ int readfile(const char *path, char **buf, size_t *size) close(fd); return (*size == st.st_size ? 0 : e); } + +int is_token_char(char c) +{ + return isalnum(c) || c == '_'; +} + +/* Replace name with getenv(name), return pointer to zero-terminating char + */ +char *expand_macro(char *name, int maxlength) +{ + char *value; + int len; + + len = 0; + value = getenv(name); + if (value) { + len = strlen(value); + if (len > maxlength) + len = maxlength; + strncpy(name, value, len); + } + return name + len; +} + +#define EXPBUFSIZE (1024 * 8) + +/* Replace all tokens prefixed by '$' in the specified text with the + * value of the named environment variable. + * NB: the return value is a static buffer, i.e. it must be strdup'd + * by the caller. + */ +char *expand_macros(const char *txt) +{ + static char result[EXPBUFSIZE]; + char *p, *start; + int len; + + p = result; + start = NULL; + while (p < result + EXPBUFSIZE - 1 && txt && *txt) { + *p = *txt; + if (start) { + if (!is_token_char(*txt)) { + if (p - start > 0) { + *p = '\0'; + len = result + EXPBUFSIZE - start - 1; + p = expand_macro(start, len) - 1; + } + start = NULL; + txt--; + } + p++; + txt++; + continue; + } + if (*txt == '$') { + start = p; + txt++; + continue; + } + p++; + txt++; + } + *p = '\0'; + if (start && p - start > 0) { + len = result + EXPBUFSIZE - start - 1; + p = expand_macro(start, len); + *p = '\0'; + } + return result; +}