]> git.cameronkatri.com Git - cgit.git/blobdiff - shared.c
mime: rewrite detection function
[cgit.git] / shared.c
index 765cd276dd9b0eb947bed9820793d98a18a45a16..3d91a76ec09c8a88aefa2d1148f3542aa6850565 100644 (file)
--- a/shared.c
+++ b/shared.c
@@ -1,6 +1,6 @@
 /* shared.c: global vars + some callback functions
  *
- * Copyright (C) 2006 Lars Hjemli
+ * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
  *
  * Licensed under GNU General Public License v2
  *   (see COPYING for full license text)
@@ -14,24 +14,25 @@ struct cgit_context ctx;
 int chk_zero(int result, char *msg)
 {
        if (result != 0)
-               die("%s: %s", msg, strerror(errno));
+               die_errno("%s", msg);
        return result;
 }
 
 int chk_positive(int result, char *msg)
 {
        if (result <= 0)
-               die("%s: %s", msg, strerror(errno));
+               die_errno("%s", msg);
        return result;
 }
 
 int chk_non_negative(int result, char *msg)
 {
-       if (result < 0)
-               die("%s: %s",msg, strerror(errno));
+       if (result < 0)
+               die_errno("%s", msg);
        return result;
 }
 
+char *cgit_default_repo_desc = "[no description]";
 struct cgit_repo *cgit_add_repo(const char *url)
 {
        struct cgit_repo *ret;
@@ -51,22 +52,29 @@ struct cgit_repo *cgit_add_repo(const char *url)
        ret->url = trim_end(url, '/');
        ret->name = ret->url;
        ret->path = NULL;
-       ret->desc = "[no description]";
+       ret->desc = cgit_default_repo_desc;
        ret->owner = NULL;
        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->branch_sort = ctx.cfg.branch_sort;
+       ret->commit_sort = ctx.cfg.commit_sort;
        ret->module_link = ctx.cfg.module_link;
        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;
+       ret->email_filter = ctx.cfg.email_filter;
+       ret->owner_filter = ctx.cfg.owner_filter;
+       ret->clone_url = ctx.cfg.clone_url;
+       ret->submodules.strdup_strings = 1;
+       ret->hide = ret->ignore = 0;
        return ret;
 }
 
@@ -75,8 +83,10 @@ struct cgit_repo *cgit_get_repoinfo(const char *url)
        int i;
        struct cgit_repo *repo;
 
-       for (i=0; i<cgit_repolist.count; i++) {
+       for (i = 0; i < cgit_repolist.count; i++) {
                repo = &cgit_repolist.repos[i];
+               if (repo->ignore)
+                       continue;
                if (!strcmp(repo->url, url))
                        return repo;
        }
@@ -99,23 +109,36 @@ void *cgit_free_commitinfo(struct commitinfo *info)
 char *trim_end(const char *str, char c)
 {
        int len;
-       char *s, *t;
 
        if (str == NULL)
                return NULL;
-       t = (char *)str;
-       len = strlen(t);
-       while(len > 0 && t[len - 1] == c)
+       len = strlen(str);
+       while (len > 0 && str[len - 1] == c)
                len--;
-
        if (len == 0)
                return NULL;
+       return xstrndup(str, len);
+}
+
+char *ensure_end(const char *str, char c)
+{
+       size_t len = strlen(str);
+       char *result;
+
+       if (len && str[len - 1] == c)
+               return xstrndup(str, len);
 
-       c = t[len];
-       t[len] = '\0';
-       s = xstrdup(t);
-       t[len] = c;
-       return s;
+       result = xmalloc(len + 2);
+       memcpy(result, str, len);
+       result[len] = '/';
+       result[len + 1] = '\0';
+       return result;
+}
+
+void strbuf_ensure_end(struct strbuf *sb, char c)
+{
+       if (!sb->len || sb->buf[sb->len - 1] != c)
+               strbuf_addch(sb, c);
 }
 
 char *strlpart(char *txt, int maxlen)
@@ -161,13 +184,13 @@ void cgit_add_ref(struct reflist *list, struct refinfo *ref)
        list->refs[list->count++] = ref;
 }
 
-struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1)
+static struct refinfo *cgit_mk_refinfo(const char *refname, const struct object_id *oid)
 {
        struct refinfo *ref;
 
        ref = xmalloc(sizeof (struct refinfo));
        ref->refname = xstrdup(refname);
-       ref->object = parse_object(sha1);
+       ref->object = parse_object(oid->hash);
        switch (ref->object->type) {
        case OBJ_TAG:
                ref->tag = cgit_parse_tag((struct tag *)ref->object);
@@ -179,11 +202,47 @@ struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1)
        return ref;
 }
 
-int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags,
+static void cgit_free_taginfo(struct taginfo *tag)
+{
+       if (tag->tagger)
+               free(tag->tagger);
+       if (tag->tagger_email)
+               free(tag->tagger_email);
+       if (tag->msg)
+               free(tag->msg);
+       free(tag);
+}
+
+static void cgit_free_refinfo(struct refinfo *ref)
+{
+       if (ref->refname)
+               free((char *)ref->refname);
+       switch (ref->object->type) {
+       case OBJ_TAG:
+               cgit_free_taginfo(ref->tag);
+               break;
+       case OBJ_COMMIT:
+               cgit_free_commitinfo(ref->commit);
+               break;
+       }
+       free(ref);
+}
+
+void cgit_free_reflist_inner(struct reflist *list)
+{
+       int i;
+
+       for (i = 0; i < list->count; i++) {
+               cgit_free_refinfo(list->refs[i]);
+       }
+       free(list->refs);
+}
+
+int cgit_refs_cb(const char *refname, const struct object_id *oid, int flags,
                  void *cb_data)
 {
        struct reflist *list = (struct reflist *)cb_data;
-       struct refinfo *info = cgit_mk_refinfo(refname, sha1);
+       struct refinfo *info = cgit_mk_refinfo(refname, oid);
 
        if (info)
                cgit_add_ref(list, info);
@@ -210,7 +269,7 @@ static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
                file->ptr = (char *)"";
                file->size = 0;
        } else {
-               file->ptr = read_sha1_file(sha1, &type, 
+               file->ptr = read_sha1_file(sha1, &type,
                                           (unsigned long *)&file->size);
        }
        return 1;
@@ -224,10 +283,10 @@ static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
  * ripped from git and modified to use globals instead of
  * a special callback-struct.
  */
-char *diffbuf = NULL;
-int buflen = 0;
+static char *diffbuf = NULL;
+static int buflen = 0;
 
-int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
+static int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
 {
        int i;
 
@@ -310,9 +369,9 @@ void cgit_diff_tree(const unsigned char *old_sha1,
                    filepair_fn fn, const char *prefix, int ignorews)
 {
        struct diff_options opt;
-       int ret;
-       int prefixlen;
+       struct pathspec_item item;
 
+       memset(&item, 0, sizeof(item));
        diff_setup(&opt);
        opt.output_format = DIFF_FORMAT_CALLBACK;
        opt.detect_rename = 1;
@@ -323,17 +382,17 @@ void cgit_diff_tree(const unsigned char *old_sha1,
        opt.format_callback = cgit_diff_tree_cb;
        opt.format_callback_data = fn;
        if (prefix) {
-               opt.nr_paths = 1;
-               opt.paths = &prefix;
-               prefixlen = strlen(prefix);
-               opt.pathlens = &prefixlen;
+               item.match = prefix;
+               item.len = strlen(prefix);
+               opt.pathspec.nr = 1;
+               opt.pathspec.items = &item;
        }
        diff_setup_done(&opt);
 
        if (old_sha1 && !is_null_sha1(old_sha1))
-               ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
+               diff_tree_sha1(old_sha1, new_sha1, "", &opt);
        else
-               ret = diff_root_tree_sha1(new_sha1, "", &opt);
+               diff_root_tree_sha1(new_sha1, "", &opt);
        diffcore_std(&opt);
        diff_flush(&opt);
 }
@@ -350,64 +409,57 @@ void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix)
 
 int cgit_parse_snapshots_mask(const char *str)
 {
+       struct string_list tokens = STRING_LIST_INIT_DUP;
+       struct string_list_item *item;
        const struct cgit_snapshot_format *f;
-       static const char *delim = " \t,:/|;";
-       int tl, sl, rv = 0;
+       int rv = 0;
 
        /* favor legacy setting */
-       if(atoi(str))
+       if (atoi(str))
                return 1;
-       for(;;) {
-               str += strspn(str,delim);
-               tl = strcspn(str,delim);
-               if (!tl)
-                       break;
+
+       string_list_split(&tokens, str, ' ', -1);
+       string_list_remove_empty_items(&tokens, 0);
+
+       for_each_string_list_item(item, &tokens) {
                for (f = cgit_snapshot_formats; f->suffix; f++) {
-                       sl = strlen(f->suffix);
-                       if((tl == sl && !strncmp(f->suffix, str, tl)) ||
-                          (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) {
+                       if (!strcmp(item->string, f->suffix) ||
+                           !strcmp(item->string, f->suffix + 1)) {
                                rv |= f->bit;
                                break;
                        }
                }
-               str += tl;
        }
+
+       string_list_clear(&tokens, 0);
        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;
-}
+typedef struct {
+       char * name;
+       char * value;
+} cgit_env_var;
 
-int cgit_close_filter(struct cgit_filter *filter)
+void cgit_prepare_repo_env(struct cgit_repo * repo)
 {
-       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);
+       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,
@@ -438,14 +490,14 @@ int readfile(const char *path, char **buf, size_t *size)
        return (*size == st.st_size ? 0 : e);
 }
 
-int is_token_char(char c)
+static 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)
+static char *expand_macro(char *name, int maxlength)
 {
        char *value;
        int len;
@@ -508,3 +560,42 @@ char *expand_macros(const char *txt)
        }
        return result;
 }
+
+char *get_mimetype_for_filename(const char *filename)
+{
+       char *ext, *mimetype, *token, line[1024];
+       FILE *file;
+       struct string_list_item *mime;
+
+       if (!filename)
+               return NULL;
+
+       ext = strrchr(filename, '.');
+       if (!ext)
+               return NULL;
+       ++ext;
+       if (!ext[0])
+               return NULL;
+       mime = string_list_lookup(&ctx.cfg.mimetypes, ext);
+       if (mime)
+               return xstrdup(mime->util);
+
+       if (!ctx.cfg.mimetype_file)
+               return NULL;
+       file = fopen(ctx.cfg.mimetype_file, "r");
+       if (!file)
+               return NULL;
+       while (fgets(line, sizeof(line), file)) {
+               if (!line[0] || line[0] == '#')
+                       continue;
+               mimetype = strtok(line, " \t\r\n");
+               while ((token = strtok(NULL, " \t\r\n"))) {
+                       if (!strcasecmp(ext, token)) {
+                               fclose(file);
+                               return xstrdup(mimetype);
+                       }
+               }
+       }
+       fclose(file);
+       return NULL;
+}