X-Git-Url: https://git.cameronkatri.com/cgit.git/blobdiff_plain/e87e89633383b8b75c68c98be3e0c14212109de2..1b5c336cc99f01a0f8d6668cbfc9273f49a6be25:/shared.c diff --git a/shared.c b/shared.c index f5875e4..7ec2e19 100644 --- a/shared.c +++ b/shared.c @@ -10,7 +10,6 @@ struct cgit_repolist cgit_repolist; struct cgit_context ctx; -int cgit_cmd; int chk_zero(int result, char *msg) { @@ -48,18 +47,27 @@ struct cgit_repo *cgit_add_repo(const char *url) } ret = &cgit_repolist.repos[cgit_repolist.count-1]; + memset(ret, 0, sizeof(struct cgit_repo)); ret->url = trim_end(url, '/'); ret->name = ret->url; ret->path = NULL; ret->desc = "[no description]"; ret->owner = NULL; - ret->group = ctx.cfg.repo_group; + 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; + ret->source_filter = ctx.cfg.source_filter; return ret; } @@ -255,8 +263,9 @@ int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) } int cgit_diff_files(const unsigned char *old_sha1, - const unsigned char *new_sha1, - linediff_fn fn) + const unsigned char *new_sha1, unsigned long *old_size, + unsigned long *new_size, int *binary, int context, + int ignorews, linediff_fn fn) { mmfile_t file1, file2; xpparam_t diff_params; @@ -266,19 +275,40 @@ int cgit_diff_files(const unsigned char *old_sha1, if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) return 1; + *old_size = file1.size; + *new_size = file2.size; + + if ((file1.ptr && buffer_is_binary(file1.ptr, file1.size)) || + (file2.ptr && buffer_is_binary(file2.ptr, file2.size))) { + *binary = 1; + if (file1.size) + free(file1.ptr); + if (file2.size) + free(file2.ptr); + return 0; + } + + memset(&diff_params, 0, sizeof(diff_params)); + 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_params.find_func = NULL; emit_cb.outf = filediff_cb; emit_cb.priv = fn; xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); + if (file1.size) + free(file1.ptr); + if (file2.size) + free(file2.ptr); return 0; } 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; @@ -289,6 +319,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) { @@ -307,13 +339,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) @@ -342,3 +375,137 @@ int cgit_parse_snapshots_mask(const char *str) } return rv; } + +int cgit_open_filter(struct cgit_filter *filter) +{ + + filter->old_stdout = chk_positive(dup(STDOUT_FILENO), + "Unable to duplicate STDOUT"); + 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) { + 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); + die("Unable to exec subprocess %s: %s (%d)", filter->cmd, + strerror(errno), errno); + } + close(filter->pipe_fh[0]); + chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO), + "Unable to use pipe as STDOUT"); + close(filter->pipe_fh[1]); + return 0; +} + +int cgit_close_filter(struct cgit_filter *filter) +{ + chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), + "Unable to restore STDOUT"); + close(filter->old_stdout); + if (filter->pid < 0) + return 0; + waitpid(filter->pid, &filter->exitstatus, 0); + if (WIFEXITED(filter->exitstatus) && !WEXITSTATUS(filter->exitstatus)) + return 0; + die("Subprocess %s exited abnormally", filter->cmd); +} + +/* 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); +} + +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; +}