author | Lars Hjemli <hjemli@gmail.com> | 2007-02-08 12:53:13 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2007-02-08 12:58:58 (UTC) |
commit | ab2ab95f09994560f62fd631f07d3b6e3577aa6e (patch) (unidiff) | |
tree | 846763c1bcb78bd27dc37c99e5f6d703ca5ab179 | |
parent | 14d360df60f059b9b5b045fc6df1eec6f0966d9a (diff) | |
download | cgit-ab2ab95f09994560f62fd631f07d3b6e3577aa6e.zip cgit-ab2ab95f09994560f62fd631f07d3b6e3577aa6e.tar.gz cgit-ab2ab95f09994560f62fd631f07d3b6e3577aa6e.tar.bz2 |
Add support for snapshots
Make a link from the commit viewer to a snapshot of the corresponding tree.
Currently only zip-format is supported.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | cgit.c | 39 | ||||
-rw-r--r-- | cgit.h | 10 | ||||
-rw-r--r-- | git.h | 27 | ||||
-rw-r--r-- | shared.c | 17 | ||||
-rw-r--r-- | ui-commit.c | 7 | ||||
-rw-r--r-- | ui-shared.c | 11 | ||||
-rw-r--r-- | ui-snapshot.c | 47 |
8 files changed, 153 insertions, 8 deletions
@@ -1,41 +1,42 @@ | |||
1 | CGIT_VERSION = 0.2 | 1 | CGIT_VERSION = 0.2 |
2 | 2 | ||
3 | prefix = /var/www/htdocs/cgit | 3 | prefix = /var/www/htdocs/cgit |
4 | gitsrc = ../git | 4 | gitsrc = ../git |
5 | 5 | ||
6 | CACHE_ROOT = /var/cache/cgit | 6 | CACHE_ROOT = /var/cache/cgit |
7 | EXTLIBS = $(gitsrc)/libgit.a $(gitsrc)/xdiff/lib.a -lz -lcrypto | 7 | EXTLIBS = $(gitsrc)/libgit.a $(gitsrc)/xdiff/lib.a -lz -lcrypto |
8 | OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ | 8 | OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ |
9 | ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c ui-diff.o | 9 | ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c ui-diff.o \ |
10 | ui-snapshot.o | ||
10 | 11 | ||
11 | CFLAGS += -Wall | 12 | CFLAGS += -Wall |
12 | 13 | ||
13 | ifdef DEBUG | 14 | ifdef DEBUG |
14 | CFLAGS += -g | 15 | CFLAGS += -g |
15 | endif | 16 | endif |
16 | 17 | ||
17 | all: cgit | 18 | all: cgit |
18 | 19 | ||
19 | install: all clean-cache | 20 | install: all clean-cache |
20 | mkdir -p $(prefix) | 21 | mkdir -p $(prefix) |
21 | install cgit $(prefix)/cgit.cgi | 22 | install cgit $(prefix)/cgit.cgi |
22 | install cgit.css $(prefix)/cgit.css | 23 | install cgit.css $(prefix)/cgit.css |
23 | 24 | ||
24 | cgit: cgit.c cgit.h git.h $(OBJECTS) $(gitsrc)/libgit.a | 25 | cgit: cgit.c cgit.h git.h $(OBJECTS) $(gitsrc)/libgit.a |
25 | $(CC) $(CFLAGS) -DCGIT_VERSION='"$(CGIT_VERSION)"' cgit.c -o cgit \ | 26 | $(CC) $(CFLAGS) -DCGIT_VERSION='"$(CGIT_VERSION)"' cgit.c -o cgit \ |
26 | $(OBJECTS) $(EXTLIBS) | 27 | $(OBJECTS) $(EXTLIBS) |
27 | 28 | ||
28 | $(OBJECTS): cgit.h git.h | 29 | $(OBJECTS): cgit.h git.h |
29 | 30 | ||
30 | ui-diff.o: xdiff.h | 31 | ui-diff.o: xdiff.h |
31 | 32 | ||
32 | $(gitsrc)/libgit.a: | 33 | $(gitsrc)/libgit.a: |
33 | $(MAKE) -C $(gitsrc) | 34 | $(MAKE) -C $(gitsrc) |
34 | 35 | ||
35 | 36 | ||
36 | .PHONY: clean | 37 | .PHONY: clean |
37 | clean: | 38 | clean: |
38 | rm -f cgit *.o | 39 | rm -f cgit *.o |
39 | 40 | ||
40 | clean-cache: | 41 | clean-cache: |
41 | rm -rf $(CACHE_ROOT)/* | 42 | rm -rf $(CACHE_ROOT)/* |
@@ -1,219 +1,244 @@ | |||
1 | /* cgit.c: cgi for the git scm | 1 | /* cgit.c: cgi for the git scm |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Lars Hjemli | 3 | * Copyright (C) 2006 Lars Hjemli |
4 | * | 4 | * |
5 | * Licensed under GNU General Public License v2 | 5 | * Licensed under GNU General Public License v2 |
6 | * (see COPYING for full license text) | 6 | * (see COPYING for full license text) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | 10 | ||
11 | const char cgit_version[] = CGIT_VERSION; | 11 | const char cgit_version[] = CGIT_VERSION; |
12 | 12 | ||
13 | 13 | ||
14 | static struct repoinfo *cgit_get_repoinfo(char *url) | 14 | static struct repoinfo *cgit_get_repoinfo(char *url) |
15 | { | 15 | { |
16 | int i; | 16 | int i; |
17 | struct repoinfo *repo; | 17 | struct repoinfo *repo; |
18 | 18 | ||
19 | for (i=0; i<cgit_repolist.count; i++) { | 19 | for (i=0; i<cgit_repolist.count; i++) { |
20 | repo = &cgit_repolist.repos[i]; | 20 | repo = &cgit_repolist.repos[i]; |
21 | if (!strcmp(repo->url, url)) | 21 | if (!strcmp(repo->url, url)) |
22 | return repo; | 22 | return repo; |
23 | } | 23 | } |
24 | return NULL; | 24 | return NULL; |
25 | } | 25 | } |
26 | 26 | ||
27 | 27 | ||
28 | static int cgit_prepare_cache(struct cacheitem *item) | 28 | static int cgit_prepare_cache(struct cacheitem *item) |
29 | { | 29 | { |
30 | if (!cgit_query_repo) { | 30 | if (!cgit_query_repo) { |
31 | item->name = xstrdup(fmt("%s/index.html", cgit_cache_root)); | 31 | item->name = xstrdup(fmt("%s/index.html", cgit_cache_root)); |
32 | item->ttl = cgit_cache_root_ttl; | 32 | item->ttl = cgit_cache_root_ttl; |
33 | return 1; | 33 | return 1; |
34 | } | 34 | } |
35 | cgit_repo = cgit_get_repoinfo(cgit_query_repo); | 35 | cgit_repo = cgit_get_repoinfo(cgit_query_repo); |
36 | if (!cgit_repo) { | 36 | if (!cgit_repo) { |
37 | char *title = fmt("%s - %s", cgit_root_title, "Bad request"); | 37 | char *title = fmt("%s - %s", cgit_root_title, "Bad request"); |
38 | cgit_print_docstart(title, item); | 38 | cgit_print_docstart(title, item); |
39 | cgit_print_pageheader(title, 0); | 39 | cgit_print_pageheader(title, 0); |
40 | cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo)); | 40 | cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo)); |
41 | cgit_print_docend(); | 41 | cgit_print_docend(); |
42 | return 0; | 42 | return 0; |
43 | } | 43 | } |
44 | 44 | ||
45 | if (!cgit_query_page) { | 45 | if (!cgit_query_page) { |
46 | item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root, | 46 | item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root, |
47 | cgit_repo->url)); | 47 | cgit_repo->url)); |
48 | item->ttl = cgit_cache_repo_ttl; | 48 | item->ttl = cgit_cache_repo_ttl; |
49 | } else { | 49 | } else { |
50 | item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, | 50 | item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, |
51 | cgit_repo->url, cgit_query_page, | 51 | cgit_repo->url, cgit_query_page, |
52 | cache_safe_filename(cgit_querystring))); | 52 | cache_safe_filename(cgit_querystring))); |
53 | if (cgit_query_has_symref) | 53 | if (cgit_query_has_symref) |
54 | item->ttl = cgit_cache_dynamic_ttl; | 54 | item->ttl = cgit_cache_dynamic_ttl; |
55 | else if (cgit_query_has_sha1) | 55 | else if (cgit_query_has_sha1) |
56 | item->ttl = cgit_cache_static_ttl; | 56 | item->ttl = cgit_cache_static_ttl; |
57 | else | 57 | else |
58 | item->ttl = cgit_cache_repo_ttl; | 58 | item->ttl = cgit_cache_repo_ttl; |
59 | } | 59 | } |
60 | return 1; | 60 | return 1; |
61 | } | 61 | } |
62 | 62 | ||
63 | static void cgit_print_repo_page(struct cacheitem *item) | 63 | static void cgit_print_repo_page(struct cacheitem *item) |
64 | { | 64 | { |
65 | char *title; | 65 | char *title; |
66 | int show_search; | 66 | int show_search; |
67 | 67 | ||
68 | if (chdir(cgit_repo->path)) { | 68 | if (chdir(cgit_repo->path)) { |
69 | title = fmt("%s - %s", cgit_root_title, "Bad request"); | 69 | title = fmt("%s - %s", cgit_root_title, "Bad request"); |
70 | cgit_print_docstart(title, item); | 70 | cgit_print_docstart(title, item); |
71 | cgit_print_pageheader(title, 0); | 71 | cgit_print_pageheader(title, 0); |
72 | cgit_print_error(fmt("Unable to scan repository: %s", | 72 | cgit_print_error(fmt("Unable to scan repository: %s", |
73 | strerror(errno))); | 73 | strerror(errno))); |
74 | cgit_print_docend(); | 74 | cgit_print_docend(); |
75 | return; | 75 | return; |
76 | } | 76 | } |
77 | 77 | ||
78 | title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); | 78 | title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); |
79 | show_search = 0; | 79 | show_search = 0; |
80 | setenv("GIT_DIR", cgit_repo->path, 1); | 80 | setenv("GIT_DIR", cgit_repo->path, 1); |
81 | |||
82 | if (cgit_query_page && !strcmp(cgit_query_page, "snapshot")) { | ||
83 | cgit_print_snapshot(item, cgit_query_sha1, "zip", | ||
84 | cgit_repo->url, cgit_query_name); | ||
85 | return; | ||
86 | } | ||
87 | |||
81 | if (cgit_query_page && !strcmp(cgit_query_page, "log")) | 88 | if (cgit_query_page && !strcmp(cgit_query_page, "log")) |
82 | show_search = 1; | 89 | show_search = 1; |
83 | cgit_print_docstart(title, item); | 90 | cgit_print_docstart(title, item); |
84 | cgit_print_pageheader(title, show_search); | 91 | cgit_print_pageheader(title, show_search); |
85 | if (!cgit_query_page) { | 92 | if (!cgit_query_page) { |
86 | cgit_print_summary(); | 93 | cgit_print_summary(); |
87 | } else if (!strcmp(cgit_query_page, "log")) { | 94 | } else if (!strcmp(cgit_query_page, "log")) { |
88 | cgit_print_log(cgit_query_head, cgit_query_ofs, 100, cgit_query_search); | 95 | cgit_print_log(cgit_query_head, cgit_query_ofs, 100, |
96 | cgit_query_search); | ||
89 | } else if (!strcmp(cgit_query_page, "tree")) { | 97 | } else if (!strcmp(cgit_query_page, "tree")) { |
90 | cgit_print_tree(cgit_query_sha1, cgit_query_path); | 98 | cgit_print_tree(cgit_query_sha1, cgit_query_path); |
91 | } else if (!strcmp(cgit_query_page, "commit")) { | 99 | } else if (!strcmp(cgit_query_page, "commit")) { |
92 | cgit_print_commit(cgit_query_sha1); | 100 | cgit_print_commit(cgit_query_sha1); |
93 | } else if (!strcmp(cgit_query_page, "view")) { | 101 | } else if (!strcmp(cgit_query_page, "view")) { |
94 | cgit_print_view(cgit_query_sha1); | 102 | cgit_print_view(cgit_query_sha1); |
95 | } else if (!strcmp(cgit_query_page, "diff")) { | 103 | } else if (!strcmp(cgit_query_page, "diff")) { |
96 | cgit_print_diff(cgit_query_sha1, cgit_query_sha2); | 104 | cgit_print_diff(cgit_query_sha1, cgit_query_sha2); |
105 | } else { | ||
106 | cgit_print_error("Invalid request"); | ||
97 | } | 107 | } |
98 | cgit_print_docend(); | 108 | cgit_print_docend(); |
99 | } | 109 | } |
100 | 110 | ||
101 | static void cgit_fill_cache(struct cacheitem *item) | 111 | static void cgit_fill_cache(struct cacheitem *item, int use_cache) |
102 | { | 112 | { |
103 | static char buf[PATH_MAX]; | 113 | static char buf[PATH_MAX]; |
114 | int stdout2; | ||
104 | 115 | ||
105 | getcwd(buf, sizeof(buf)); | 116 | getcwd(buf, sizeof(buf)); |
106 | htmlfd = item->fd; | ||
107 | item->st.st_mtime = time(NULL); | 117 | item->st.st_mtime = time(NULL); |
118 | |||
119 | if (use_cache) { | ||
120 | stdout2 = chk_positive(dup(STDOUT_FILENO), | ||
121 | "Preserving STDOUT"); | ||
122 | chk_zero(close(STDOUT_FILENO), "Closing STDOUT"); | ||
123 | chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)"); | ||
124 | } | ||
125 | |||
108 | if (cgit_query_repo) | 126 | if (cgit_query_repo) |
109 | cgit_print_repo_page(item); | 127 | cgit_print_repo_page(item); |
110 | else | 128 | else |
111 | cgit_print_repolist(item); | 129 | cgit_print_repolist(item); |
130 | |||
131 | if (use_cache) { | ||
132 | chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); | ||
133 | chk_positive(dup2(stdout2, STDOUT_FILENO), | ||
134 | "Restoring original STDOUT"); | ||
135 | chk_zero(close(stdout2), "Closing temporary STDOUT"); | ||
136 | } | ||
137 | |||
112 | chdir(buf); | 138 | chdir(buf); |
113 | } | 139 | } |
114 | 140 | ||
115 | static void cgit_check_cache(struct cacheitem *item) | 141 | static void cgit_check_cache(struct cacheitem *item) |
116 | { | 142 | { |
117 | int i = 0; | 143 | int i = 0; |
118 | 144 | ||
119 | top: | 145 | top: |
120 | if (++i > cgit_max_lock_attempts) { | 146 | if (++i > cgit_max_lock_attempts) { |
121 | die("cgit_refresh_cache: unable to lock %s: %s", | 147 | die("cgit_refresh_cache: unable to lock %s: %s", |
122 | item->name, strerror(errno)); | 148 | item->name, strerror(errno)); |
123 | } | 149 | } |
124 | if (!cache_exist(item)) { | 150 | if (!cache_exist(item)) { |
125 | if (!cache_lock(item)) { | 151 | if (!cache_lock(item)) { |
126 | sleep(1); | 152 | sleep(1); |
127 | goto top; | 153 | goto top; |
128 | } | 154 | } |
129 | if (!cache_exist(item)) { | 155 | if (!cache_exist(item)) { |
130 | cgit_fill_cache(item); | 156 | cgit_fill_cache(item, 1); |
131 | cache_unlock(item); | 157 | cache_unlock(item); |
132 | } else { | 158 | } else { |
133 | cache_cancel_lock(item); | 159 | cache_cancel_lock(item); |
134 | } | 160 | } |
135 | } else if (cache_expired(item) && cache_lock(item)) { | 161 | } else if (cache_expired(item) && cache_lock(item)) { |
136 | if (cache_expired(item)) { | 162 | if (cache_expired(item)) { |
137 | cgit_fill_cache(item); | 163 | cgit_fill_cache(item, 1); |
138 | cache_unlock(item); | 164 | cache_unlock(item); |
139 | } else { | 165 | } else { |
140 | cache_cancel_lock(item); | 166 | cache_cancel_lock(item); |
141 | } | 167 | } |
142 | } | 168 | } |
143 | } | 169 | } |
144 | 170 | ||
145 | static void cgit_print_cache(struct cacheitem *item) | 171 | static void cgit_print_cache(struct cacheitem *item) |
146 | { | 172 | { |
147 | static char buf[4096]; | 173 | static char buf[4096]; |
148 | ssize_t i; | 174 | ssize_t i; |
149 | 175 | ||
150 | int fd = open(item->name, O_RDONLY); | 176 | int fd = open(item->name, O_RDONLY); |
151 | if (fd<0) | 177 | if (fd<0) |
152 | die("Unable to open cached file %s", item->name); | 178 | die("Unable to open cached file %s", item->name); |
153 | 179 | ||
154 | while((i=read(fd, buf, sizeof(buf))) > 0) | 180 | while((i=read(fd, buf, sizeof(buf))) > 0) |
155 | write(STDOUT_FILENO, buf, i); | 181 | write(STDOUT_FILENO, buf, i); |
156 | 182 | ||
157 | close(fd); | 183 | close(fd); |
158 | } | 184 | } |
159 | 185 | ||
160 | static void cgit_parse_args(int argc, const char **argv) | 186 | static void cgit_parse_args(int argc, const char **argv) |
161 | { | 187 | { |
162 | int i; | 188 | int i; |
163 | 189 | ||
164 | for (i = 1; i < argc; i++) { | 190 | for (i = 1; i < argc; i++) { |
165 | if (!strncmp(argv[i], "--cache=", 8)) { | 191 | if (!strncmp(argv[i], "--cache=", 8)) { |
166 | cgit_cache_root = xstrdup(argv[i]+8); | 192 | cgit_cache_root = xstrdup(argv[i]+8); |
167 | } | 193 | } |
168 | if (!strcmp(argv[i], "--nocache")) { | 194 | if (!strcmp(argv[i], "--nocache")) { |
169 | cgit_nocache = 1; | 195 | cgit_nocache = 1; |
170 | } | 196 | } |
171 | if (!strncmp(argv[i], "--query=", 8)) { | 197 | if (!strncmp(argv[i], "--query=", 8)) { |
172 | cgit_querystring = xstrdup(argv[i]+8); | 198 | cgit_querystring = xstrdup(argv[i]+8); |
173 | } | 199 | } |
174 | if (!strncmp(argv[i], "--repo=", 7)) { | 200 | if (!strncmp(argv[i], "--repo=", 7)) { |
175 | cgit_query_repo = xstrdup(argv[i]+7); | 201 | cgit_query_repo = xstrdup(argv[i]+7); |
176 | } | 202 | } |
177 | if (!strncmp(argv[i], "--page=", 7)) { | 203 | if (!strncmp(argv[i], "--page=", 7)) { |
178 | cgit_query_page = xstrdup(argv[i]+7); | 204 | cgit_query_page = xstrdup(argv[i]+7); |
179 | } | 205 | } |
180 | if (!strncmp(argv[i], "--head=", 7)) { | 206 | if (!strncmp(argv[i], "--head=", 7)) { |
181 | cgit_query_head = xstrdup(argv[i]+7); | 207 | cgit_query_head = xstrdup(argv[i]+7); |
182 | cgit_query_has_symref = 1; | 208 | cgit_query_has_symref = 1; |
183 | } | 209 | } |
184 | if (!strncmp(argv[i], "--sha1=", 7)) { | 210 | if (!strncmp(argv[i], "--sha1=", 7)) { |
185 | cgit_query_sha1 = xstrdup(argv[i]+7); | 211 | cgit_query_sha1 = xstrdup(argv[i]+7); |
186 | cgit_query_has_sha1 = 1; | 212 | cgit_query_has_sha1 = 1; |
187 | } | 213 | } |
188 | if (!strncmp(argv[i], "--ofs=", 6)) { | 214 | if (!strncmp(argv[i], "--ofs=", 6)) { |
189 | cgit_query_ofs = atoi(argv[i]+6); | 215 | cgit_query_ofs = atoi(argv[i]+6); |
190 | } | 216 | } |
191 | } | 217 | } |
192 | } | 218 | } |
193 | 219 | ||
194 | int main(int argc, const char **argv) | 220 | int main(int argc, const char **argv) |
195 | { | 221 | { |
196 | struct cacheitem item; | 222 | struct cacheitem item; |
197 | 223 | ||
198 | htmlfd = STDOUT_FILENO; | 224 | htmlfd = STDOUT_FILENO; |
199 | item.st.st_mtime = time(NULL); | 225 | item.st.st_mtime = time(NULL); |
200 | cgit_repolist.length = 0; | 226 | cgit_repolist.length = 0; |
201 | cgit_repolist.count = 0; | 227 | cgit_repolist.count = 0; |
202 | cgit_repolist.repos = NULL; | 228 | cgit_repolist.repos = NULL; |
203 | 229 | ||
204 | cgit_read_config("/etc/cgitrc", cgit_global_config_cb); | 230 | cgit_read_config("/etc/cgitrc", cgit_global_config_cb); |
205 | if (getenv("QUERY_STRING")) | 231 | if (getenv("QUERY_STRING")) |
206 | cgit_querystring = xstrdup(getenv("QUERY_STRING")); | 232 | cgit_querystring = xstrdup(getenv("QUERY_STRING")); |
207 | cgit_parse_args(argc, argv); | 233 | cgit_parse_args(argc, argv); |
208 | cgit_parse_query(cgit_querystring, cgit_querystring_cb); | 234 | cgit_parse_query(cgit_querystring, cgit_querystring_cb); |
209 | if (!cgit_prepare_cache(&item)) | 235 | if (!cgit_prepare_cache(&item)) |
210 | return 0; | 236 | return 0; |
211 | if (cgit_nocache) { | 237 | if (cgit_nocache) { |
212 | item.fd = STDOUT_FILENO; | 238 | cgit_fill_cache(&item, 0); |
213 | cgit_fill_cache(&item); | ||
214 | } else { | 239 | } else { |
215 | cgit_check_cache(&item); | 240 | cgit_check_cache(&item); |
216 | cgit_print_cache(&item); | 241 | cgit_print_cache(&item); |
217 | } | 242 | } |
218 | return 0; | 243 | return 0; |
219 | } | 244 | } |
@@ -1,142 +1,152 @@ | |||
1 | #ifndef CGIT_H | 1 | #ifndef CGIT_H |
2 | #define CGIT_H | 2 | #define CGIT_H |
3 | 3 | ||
4 | #include "git.h" | 4 | #include "git.h" |
5 | #include <openssl/sha.h> | 5 | #include <openssl/sha.h> |
6 | #include <ctype.h> | 6 | #include <ctype.h> |
7 | #include <sched.h> | 7 | #include <sched.h> |
8 | 8 | ||
9 | typedef void (*configfn)(const char *name, const char *value); | 9 | typedef void (*configfn)(const char *name, const char *value); |
10 | 10 | ||
11 | struct cacheitem { | 11 | struct cacheitem { |
12 | char *name; | 12 | char *name; |
13 | struct stat st; | 13 | struct stat st; |
14 | int ttl; | 14 | int ttl; |
15 | int fd; | 15 | int fd; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | struct repoinfo { | 18 | struct repoinfo { |
19 | char *url; | 19 | char *url; |
20 | char *name; | 20 | char *name; |
21 | char *path; | 21 | char *path; |
22 | char *desc; | 22 | char *desc; |
23 | char *owner; | 23 | char *owner; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | struct repolist { | 26 | struct repolist { |
27 | int length; | 27 | int length; |
28 | int count; | 28 | int count; |
29 | struct repoinfo *repos; | 29 | struct repoinfo *repos; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | struct commitinfo { | 32 | struct commitinfo { |
33 | struct commit *commit; | 33 | struct commit *commit; |
34 | char *author; | 34 | char *author; |
35 | char *author_email; | 35 | char *author_email; |
36 | unsigned long author_date; | 36 | unsigned long author_date; |
37 | char *committer; | 37 | char *committer; |
38 | char *committer_email; | 38 | char *committer_email; |
39 | unsigned long committer_date; | 39 | unsigned long committer_date; |
40 | char *subject; | 40 | char *subject; |
41 | char *msg; | 41 | char *msg; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct taginfo { | 44 | struct taginfo { |
45 | char *tagger; | 45 | char *tagger; |
46 | char *tagger_email; | 46 | char *tagger_email; |
47 | int tagger_date; | 47 | int tagger_date; |
48 | char *msg; | 48 | char *msg; |
49 | }; | 49 | }; |
50 | 50 | ||
51 | extern const char cgit_version[]; | 51 | extern const char cgit_version[]; |
52 | 52 | ||
53 | extern struct repolist cgit_repolist; | 53 | extern struct repolist cgit_repolist; |
54 | extern struct repoinfo *cgit_repo; | 54 | extern struct repoinfo *cgit_repo; |
55 | 55 | ||
56 | extern char *cgit_root_title; | 56 | extern char *cgit_root_title; |
57 | extern char *cgit_css; | 57 | extern char *cgit_css; |
58 | extern char *cgit_logo; | 58 | extern char *cgit_logo; |
59 | extern char *cgit_logo_link; | 59 | extern char *cgit_logo_link; |
60 | extern char *cgit_virtual_root; | 60 | extern char *cgit_virtual_root; |
61 | extern char *cgit_cache_root; | 61 | extern char *cgit_cache_root; |
62 | 62 | ||
63 | extern int cgit_nocache; | 63 | extern int cgit_nocache; |
64 | extern int cgit_max_lock_attempts; | 64 | extern int cgit_max_lock_attempts; |
65 | extern int cgit_cache_root_ttl; | 65 | extern int cgit_cache_root_ttl; |
66 | extern int cgit_cache_repo_ttl; | 66 | extern int cgit_cache_repo_ttl; |
67 | extern int cgit_cache_dynamic_ttl; | 67 | extern int cgit_cache_dynamic_ttl; |
68 | extern int cgit_cache_static_ttl; | 68 | extern int cgit_cache_static_ttl; |
69 | extern int cgit_cache_max_create_time; | 69 | extern int cgit_cache_max_create_time; |
70 | 70 | ||
71 | extern int cgit_max_msg_len; | 71 | extern int cgit_max_msg_len; |
72 | 72 | ||
73 | extern char *cgit_repo_name; | 73 | extern char *cgit_repo_name; |
74 | extern char *cgit_repo_desc; | 74 | extern char *cgit_repo_desc; |
75 | extern char *cgit_repo_owner; | 75 | extern char *cgit_repo_owner; |
76 | 76 | ||
77 | extern int cgit_query_has_symref; | 77 | extern int cgit_query_has_symref; |
78 | extern int cgit_query_has_sha1; | 78 | extern int cgit_query_has_sha1; |
79 | 79 | ||
80 | extern char *cgit_querystring; | 80 | extern char *cgit_querystring; |
81 | extern char *cgit_query_repo; | 81 | extern char *cgit_query_repo; |
82 | extern char *cgit_query_page; | 82 | extern char *cgit_query_page; |
83 | extern char *cgit_query_search; | 83 | extern char *cgit_query_search; |
84 | extern char *cgit_query_head; | 84 | extern char *cgit_query_head; |
85 | extern char *cgit_query_sha1; | 85 | extern char *cgit_query_sha1; |
86 | extern char *cgit_query_sha2; | 86 | extern char *cgit_query_sha2; |
87 | extern char *cgit_query_path; | 87 | extern char *cgit_query_path; |
88 | extern char *cgit_query_name; | ||
88 | extern int cgit_query_ofs; | 89 | extern int cgit_query_ofs; |
89 | 90 | ||
90 | extern int htmlfd; | 91 | extern int htmlfd; |
91 | 92 | ||
92 | extern void cgit_global_config_cb(const char *name, const char *value); | 93 | extern void cgit_global_config_cb(const char *name, const char *value); |
93 | extern void cgit_repo_config_cb(const char *name, const char *value); | 94 | extern void cgit_repo_config_cb(const char *name, const char *value); |
94 | extern void cgit_querystring_cb(const char *name, const char *value); | 95 | extern void cgit_querystring_cb(const char *name, const char *value); |
95 | 96 | ||
97 | extern int chk_zero(int result, char *msg); | ||
98 | extern int chk_positive(int result, char *msg); | ||
99 | |||
96 | extern int hextoint(char c); | 100 | extern int hextoint(char c); |
97 | 101 | ||
98 | extern void *cgit_free_commitinfo(struct commitinfo *info); | 102 | extern void *cgit_free_commitinfo(struct commitinfo *info); |
99 | 103 | ||
100 | extern char *fmt(const char *format,...); | 104 | extern char *fmt(const char *format,...); |
101 | 105 | ||
102 | extern void html(const char *txt); | 106 | extern void html(const char *txt); |
103 | extern void htmlf(const char *format,...); | 107 | extern void htmlf(const char *format,...); |
104 | extern void html_txt(char *txt); | 108 | extern void html_txt(char *txt); |
105 | extern void html_ntxt(int len, char *txt); | 109 | extern void html_ntxt(int len, char *txt); |
106 | extern void html_attr(char *txt); | 110 | extern void html_attr(char *txt); |
107 | extern void html_hidden(char *name, char *value); | 111 | extern void html_hidden(char *name, char *value); |
108 | extern void html_link_open(char *url, char *title, char *class); | 112 | extern void html_link_open(char *url, char *title, char *class); |
109 | extern void html_link_close(void); | 113 | extern void html_link_close(void); |
110 | extern void html_filemode(unsigned short mode); | 114 | extern void html_filemode(unsigned short mode); |
111 | 115 | ||
112 | extern int cgit_read_config(const char *filename, configfn fn); | 116 | extern int cgit_read_config(const char *filename, configfn fn); |
113 | extern int cgit_parse_query(char *txt, configfn fn); | 117 | extern int cgit_parse_query(char *txt, configfn fn); |
114 | extern struct commitinfo *cgit_parse_commit(struct commit *commit); | 118 | extern struct commitinfo *cgit_parse_commit(struct commit *commit); |
115 | extern struct taginfo *cgit_parse_tag(struct tag *tag); | 119 | extern struct taginfo *cgit_parse_tag(struct tag *tag); |
116 | 120 | ||
117 | extern char *cache_safe_filename(const char *unsafe); | 121 | extern char *cache_safe_filename(const char *unsafe); |
118 | extern int cache_lock(struct cacheitem *item); | 122 | extern int cache_lock(struct cacheitem *item); |
119 | extern int cache_unlock(struct cacheitem *item); | 123 | extern int cache_unlock(struct cacheitem *item); |
120 | extern int cache_cancel_lock(struct cacheitem *item); | 124 | extern int cache_cancel_lock(struct cacheitem *item); |
121 | extern int cache_exist(struct cacheitem *item); | 125 | extern int cache_exist(struct cacheitem *item); |
122 | extern int cache_expired(struct cacheitem *item); | 126 | extern int cache_expired(struct cacheitem *item); |
123 | 127 | ||
124 | extern char *cgit_repourl(const char *reponame); | 128 | extern char *cgit_repourl(const char *reponame); |
125 | extern char *cgit_pageurl(const char *reponame, const char *pagename, | 129 | extern char *cgit_pageurl(const char *reponame, const char *pagename, |
126 | const char *query); | 130 | const char *query); |
127 | 131 | ||
128 | extern void cgit_print_error(char *msg); | 132 | extern void cgit_print_error(char *msg); |
129 | extern void cgit_print_date(unsigned long secs); | 133 | extern void cgit_print_date(unsigned long secs); |
130 | extern void cgit_print_docstart(char *title, struct cacheitem *item); | 134 | extern void cgit_print_docstart(char *title, struct cacheitem *item); |
131 | extern void cgit_print_docend(); | 135 | extern void cgit_print_docend(); |
132 | extern void cgit_print_pageheader(char *title, int show_search); | 136 | extern void cgit_print_pageheader(char *title, int show_search); |
137 | extern void cgit_print_snapshot_start(const char *mimetype, | ||
138 | const char *filename, | ||
139 | struct cacheitem *item); | ||
133 | 140 | ||
134 | extern void cgit_print_repolist(struct cacheitem *item); | 141 | extern void cgit_print_repolist(struct cacheitem *item); |
135 | extern void cgit_print_summary(); | 142 | extern void cgit_print_summary(); |
136 | extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep); | 143 | extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep); |
137 | extern void cgit_print_view(const char *hex); | 144 | extern void cgit_print_view(const char *hex); |
138 | extern void cgit_print_tree(const char *hex, char *path); | 145 | extern void cgit_print_tree(const char *hex, char *path); |
139 | extern void cgit_print_commit(const char *hex); | 146 | extern void cgit_print_commit(const char *hex); |
140 | extern void cgit_print_diff(const char *old_hex, const char *new_hex); | 147 | extern void cgit_print_diff(const char *old_hex, const char *new_hex); |
148 | extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, | ||
149 | const char *format, const char *prefix, | ||
150 | const char *filename); | ||
141 | 151 | ||
142 | #endif /* CGIT_H */ | 152 | #endif /* CGIT_H */ |
@@ -1,672 +1,699 @@ | |||
1 | #ifndef GIT_H | 1 | #ifndef GIT_H |
2 | #define GIT_H | 2 | #define GIT_H |
3 | 3 | ||
4 | 4 | ||
5 | /* | 5 | /* |
6 | * from git:git-compat-util.h | 6 | * from git:git-compat-util.h |
7 | */ | 7 | */ |
8 | 8 | ||
9 | 9 | ||
10 | #ifndef FLEX_ARRAY | 10 | #ifndef FLEX_ARRAY |
11 | #if defined(__GNUC__) && (__GNUC__ < 3) | 11 | #if defined(__GNUC__) && (__GNUC__ < 3) |
12 | #define FLEX_ARRAY 0 | 12 | #define FLEX_ARRAY 0 |
13 | #else | 13 | #else |
14 | #define FLEX_ARRAY /* empty */ | 14 | #define FLEX_ARRAY /* empty */ |
15 | #endif | 15 | #endif |
16 | #endif | 16 | #endif |
17 | 17 | ||
18 | 18 | ||
19 | #include <unistd.h> | 19 | #include <unistd.h> |
20 | #include <stdio.h> | 20 | #include <stdio.h> |
21 | #include <sys/stat.h> | 21 | #include <sys/stat.h> |
22 | #include <fcntl.h> | 22 | #include <fcntl.h> |
23 | #include <stddef.h> | 23 | #include <stddef.h> |
24 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <stdarg.h> | 25 | #include <stdarg.h> |
26 | #include <string.h> | 26 | #include <string.h> |
27 | #include <errno.h> | 27 | #include <errno.h> |
28 | #include <limits.h> | 28 | #include <limits.h> |
29 | #include <sys/param.h> | 29 | #include <sys/param.h> |
30 | #include <netinet/in.h> | 30 | #include <netinet/in.h> |
31 | #include <sys/types.h> | 31 | #include <sys/types.h> |
32 | #include <dirent.h> | 32 | #include <dirent.h> |
33 | #include <time.h> | 33 | #include <time.h> |
34 | #include <regex.h> | 34 | #include <regex.h> |
35 | 35 | ||
36 | /* On most systems <limits.h> would have given us this, but | 36 | /* On most systems <limits.h> would have given us this, but |
37 | * not on some systems (e.g. GNU/Hurd). | 37 | * not on some systems (e.g. GNU/Hurd). |
38 | */ | 38 | */ |
39 | #ifndef PATH_MAX | 39 | #ifndef PATH_MAX |
40 | #define PATH_MAX 4096 | 40 | #define PATH_MAX 4096 |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | #ifdef __GNUC__ | 43 | #ifdef __GNUC__ |
44 | #define NORETURN __attribute__((__noreturn__)) | 44 | #define NORETURN __attribute__((__noreturn__)) |
45 | #else | 45 | #else |
46 | #define NORETURN | 46 | #define NORETURN |
47 | #ifndef __attribute__ | 47 | #ifndef __attribute__ |
48 | #define __attribute__(x) | 48 | #define __attribute__(x) |
49 | #endif | 49 | #endif |
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | 52 | ||
53 | extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); | 53 | extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); |
54 | 54 | ||
55 | 55 | ||
56 | static inline char* xstrdup(const char *str) | 56 | static inline char* xstrdup(const char *str) |
57 | { | 57 | { |
58 | char *ret = strdup(str); | 58 | char *ret = strdup(str); |
59 | if (!ret) | 59 | if (!ret) |
60 | die("Out of memory, strdup failed"); | 60 | die("Out of memory, strdup failed"); |
61 | return ret; | 61 | return ret; |
62 | } | 62 | } |
63 | 63 | ||
64 | static inline void *xmalloc(size_t size) | 64 | static inline void *xmalloc(size_t size) |
65 | { | 65 | { |
66 | void *ret = malloc(size); | 66 | void *ret = malloc(size); |
67 | if (!ret && !size) | 67 | if (!ret && !size) |
68 | ret = malloc(1); | 68 | ret = malloc(1); |
69 | if (!ret) | 69 | if (!ret) |
70 | die("Out of memory, malloc failed"); | 70 | die("Out of memory, malloc failed"); |
71 | #ifdef XMALLOC_POISON | 71 | #ifdef XMALLOC_POISON |
72 | memset(ret, 0xA5, size); | 72 | memset(ret, 0xA5, size); |
73 | #endif | 73 | #endif |
74 | return ret; | 74 | return ret; |
75 | } | 75 | } |
76 | 76 | ||
77 | static inline void *xrealloc(void *ptr, size_t size) | 77 | static inline void *xrealloc(void *ptr, size_t size) |
78 | { | 78 | { |
79 | void *ret = realloc(ptr, size); | 79 | void *ret = realloc(ptr, size); |
80 | if (!ret && !size) | 80 | if (!ret && !size) |
81 | ret = realloc(ptr, 1); | 81 | ret = realloc(ptr, 1); |
82 | if (!ret) | 82 | if (!ret) |
83 | die("Out of memory, realloc failed"); | 83 | die("Out of memory, realloc failed"); |
84 | return ret; | 84 | return ret; |
85 | } | 85 | } |
86 | 86 | ||
87 | static inline void *xcalloc(size_t nmemb, size_t size) | 87 | static inline void *xcalloc(size_t nmemb, size_t size) |
88 | { | 88 | { |
89 | void *ret = calloc(nmemb, size); | 89 | void *ret = calloc(nmemb, size); |
90 | if (!ret && (!nmemb || !size)) | 90 | if (!ret && (!nmemb || !size)) |
91 | ret = calloc(1, 1); | 91 | ret = calloc(1, 1); |
92 | if (!ret) | 92 | if (!ret) |
93 | die("Out of memory, calloc failed"); | 93 | die("Out of memory, calloc failed"); |
94 | return ret; | 94 | return ret; |
95 | } | 95 | } |
96 | 96 | ||
97 | static inline ssize_t xread(int fd, void *buf, size_t len) | 97 | static inline ssize_t xread(int fd, void *buf, size_t len) |
98 | { | 98 | { |
99 | ssize_t nr; | 99 | ssize_t nr; |
100 | while (1) { | 100 | while (1) { |
101 | nr = read(fd, buf, len); | 101 | nr = read(fd, buf, len); |
102 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) | 102 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) |
103 | continue; | 103 | continue; |
104 | return nr; | 104 | return nr; |
105 | } | 105 | } |
106 | } | 106 | } |
107 | 107 | ||
108 | static inline ssize_t xwrite(int fd, const void *buf, size_t len) | 108 | static inline ssize_t xwrite(int fd, const void *buf, size_t len) |
109 | { | 109 | { |
110 | ssize_t nr; | 110 | ssize_t nr; |
111 | while (1) { | 111 | while (1) { |
112 | nr = write(fd, buf, len); | 112 | nr = write(fd, buf, len); |
113 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) | 113 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) |
114 | continue; | 114 | continue; |
115 | return nr; | 115 | return nr; |
116 | } | 116 | } |
117 | } | 117 | } |
118 | 118 | ||
119 | 119 | ||
120 | 120 | ||
121 | 121 | ||
122 | /* | 122 | /* |
123 | * from git:cache.h | 123 | * from git:cache.h |
124 | */ | 124 | */ |
125 | 125 | ||
126 | 126 | ||
127 | enum object_type { | 127 | enum object_type { |
128 | OBJ_NONE = 0, | 128 | OBJ_NONE = 0, |
129 | OBJ_COMMIT = 1, | 129 | OBJ_COMMIT = 1, |
130 | OBJ_TREE = 2, | 130 | OBJ_TREE = 2, |
131 | OBJ_BLOB = 3, | 131 | OBJ_BLOB = 3, |
132 | OBJ_TAG = 4, | 132 | OBJ_TAG = 4, |
133 | /* 5 for future expansion */ | 133 | /* 5 for future expansion */ |
134 | OBJ_OFS_DELTA = 6, | 134 | OBJ_OFS_DELTA = 6, |
135 | OBJ_REF_DELTA = 7, | 135 | OBJ_REF_DELTA = 7, |
136 | OBJ_BAD, | 136 | OBJ_BAD, |
137 | }; | 137 | }; |
138 | 138 | ||
139 | 139 | ||
140 | /* Convert to/from hex/sha1 representation */ | 140 | /* Convert to/from hex/sha1 representation */ |
141 | #define MINIMUM_ABBREV 4 | 141 | #define MINIMUM_ABBREV 4 |
142 | #define DEFAULT_ABBREV 7 | 142 | #define DEFAULT_ABBREV 7 |
143 | 143 | ||
144 | extern const unsigned char null_sha1[20]; | 144 | extern const unsigned char null_sha1[20]; |
145 | 145 | ||
146 | extern int sha1_object_info(const unsigned char *, char *, unsigned long *); | 146 | extern int sha1_object_info(const unsigned char *, char *, unsigned long *); |
147 | 147 | ||
148 | extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size); | 148 | extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size); |
149 | 149 | ||
150 | extern int get_sha1(const char *str, unsigned char *sha1); | 150 | extern int get_sha1(const char *str, unsigned char *sha1); |
151 | extern int get_sha1_hex(const char *hex, unsigned char *sha1); | 151 | extern int get_sha1_hex(const char *hex, unsigned char *sha1); |
152 | extern char *sha1_to_hex(const unsigned char *sha1);/* static buffer result! */ | 152 | extern char *sha1_to_hex(const unsigned char *sha1);/* static buffer result! */ |
153 | 153 | ||
154 | static inline int is_null_sha1(const unsigned char *sha1) | 154 | static inline int is_null_sha1(const unsigned char *sha1) |
155 | { | 155 | { |
156 | return !memcmp(sha1, null_sha1, 20); | 156 | return !memcmp(sha1, null_sha1, 20); |
157 | } | 157 | } |
158 | static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) | 158 | static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) |
159 | { | 159 | { |
160 | return memcmp(sha1, sha2, 20); | 160 | return memcmp(sha1, sha2, 20); |
161 | } | 161 | } |
162 | static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src) | 162 | static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src) |
163 | { | 163 | { |
164 | memcpy(sha_dst, sha_src, 20); | 164 | memcpy(sha_dst, sha_src, 20); |
165 | } | 165 | } |
166 | static inline void hashclr(unsigned char *hash) | 166 | static inline void hashclr(unsigned char *hash) |
167 | { | 167 | { |
168 | memset(hash, 0, 20); | 168 | memset(hash, 0, 20); |
169 | } | 169 | } |
170 | 170 | ||
171 | 171 | ||
172 | /* | 172 | /* |
173 | * from git:grep.h | 173 | * from git:grep.h |
174 | */ | 174 | */ |
175 | 175 | ||
176 | enum grep_pat_token { | 176 | enum grep_pat_token { |
177 | GREP_PATTERN, | 177 | GREP_PATTERN, |
178 | GREP_PATTERN_HEAD, | 178 | GREP_PATTERN_HEAD, |
179 | GREP_PATTERN_BODY, | 179 | GREP_PATTERN_BODY, |
180 | GREP_AND, | 180 | GREP_AND, |
181 | GREP_OPEN_PAREN, | 181 | GREP_OPEN_PAREN, |
182 | GREP_CLOSE_PAREN, | 182 | GREP_CLOSE_PAREN, |
183 | GREP_NOT, | 183 | GREP_NOT, |
184 | GREP_OR, | 184 | GREP_OR, |
185 | }; | 185 | }; |
186 | 186 | ||
187 | enum grep_context { | 187 | enum grep_context { |
188 | GREP_CONTEXT_HEAD, | 188 | GREP_CONTEXT_HEAD, |
189 | GREP_CONTEXT_BODY, | 189 | GREP_CONTEXT_BODY, |
190 | }; | 190 | }; |
191 | 191 | ||
192 | struct grep_pat { | 192 | struct grep_pat { |
193 | struct grep_pat *next; | 193 | struct grep_pat *next; |
194 | const char *origin; | 194 | const char *origin; |
195 | int no; | 195 | int no; |
196 | enum grep_pat_token token; | 196 | enum grep_pat_token token; |
197 | const char *pattern; | 197 | const char *pattern; |
198 | regex_t regexp; | 198 | regex_t regexp; |
199 | }; | 199 | }; |
200 | 200 | ||
201 | enum grep_expr_node { | 201 | enum grep_expr_node { |
202 | GREP_NODE_ATOM, | 202 | GREP_NODE_ATOM, |
203 | GREP_NODE_NOT, | 203 | GREP_NODE_NOT, |
204 | GREP_NODE_AND, | 204 | GREP_NODE_AND, |
205 | GREP_NODE_OR, | 205 | GREP_NODE_OR, |
206 | }; | 206 | }; |
207 | 207 | ||
208 | struct grep_opt { | 208 | struct grep_opt { |
209 | struct grep_pat *pattern_list; | 209 | struct grep_pat *pattern_list; |
210 | struct grep_pat **pattern_tail; | 210 | struct grep_pat **pattern_tail; |
211 | struct grep_expr *pattern_expression; | 211 | struct grep_expr *pattern_expression; |
212 | int prefix_length; | 212 | int prefix_length; |
213 | regex_t regexp; | 213 | regex_t regexp; |
214 | unsigned linenum:1; | 214 | unsigned linenum:1; |
215 | unsigned invert:1; | 215 | unsigned invert:1; |
216 | unsigned status_only:1; | 216 | unsigned status_only:1; |
217 | unsigned name_only:1; | 217 | unsigned name_only:1; |
218 | unsigned unmatch_name_only:1; | 218 | unsigned unmatch_name_only:1; |
219 | unsigned count:1; | 219 | unsigned count:1; |
220 | unsigned word_regexp:1; | 220 | unsigned word_regexp:1; |
221 | unsigned fixed:1; | 221 | unsigned fixed:1; |
222 | unsigned all_match:1; | 222 | unsigned all_match:1; |
223 | #define GREP_BINARY_DEFAULT 0 | 223 | #define GREP_BINARY_DEFAULT 0 |
224 | #define GREP_BINARY_NOMATCH 1 | 224 | #define GREP_BINARY_NOMATCH 1 |
225 | #define GREP_BINARY_TEXT 2 | 225 | #define GREP_BINARY_TEXT 2 |
226 | unsigned binary:2; | 226 | unsigned binary:2; |
227 | unsigned extended:1; | 227 | unsigned extended:1; |
228 | unsigned relative:1; | 228 | unsigned relative:1; |
229 | unsigned pathname:1; | 229 | unsigned pathname:1; |
230 | int regflags; | 230 | int regflags; |
231 | unsigned pre_context; | 231 | unsigned pre_context; |
232 | unsigned post_context; | 232 | unsigned post_context; |
233 | }; | 233 | }; |
234 | 234 | ||
235 | 235 | ||
236 | extern void compile_grep_patterns(struct grep_opt *opt); | 236 | extern void compile_grep_patterns(struct grep_opt *opt); |
237 | extern void free_grep_patterns(struct grep_opt *opt); | 237 | extern void free_grep_patterns(struct grep_opt *opt); |
238 | 238 | ||
239 | 239 | ||
240 | /* | 240 | /* |
241 | * from git:object.h | 241 | * from git:object.h |
242 | */ | 242 | */ |
243 | 243 | ||
244 | extern const char *type_names[9]; | 244 | extern const char *type_names[9]; |
245 | 245 | ||
246 | struct object_list { | 246 | struct object_list { |
247 | struct object *item; | 247 | struct object *item; |
248 | struct object_list *next; | 248 | struct object_list *next; |
249 | }; | 249 | }; |
250 | 250 | ||
251 | struct object_refs { | 251 | struct object_refs { |
252 | unsigned count; | 252 | unsigned count; |
253 | struct object *base; | 253 | struct object *base; |
254 | struct object *ref[FLEX_ARRAY]; /* more */ | 254 | struct object *ref[FLEX_ARRAY]; /* more */ |
255 | }; | 255 | }; |
256 | 256 | ||
257 | struct object_array { | 257 | struct object_array { |
258 | unsigned int nr; | 258 | unsigned int nr; |
259 | unsigned int alloc; | 259 | unsigned int alloc; |
260 | struct object_array_entry { | 260 | struct object_array_entry { |
261 | struct object *item; | 261 | struct object *item; |
262 | const char *name; | 262 | const char *name; |
263 | } *objects; | 263 | } *objects; |
264 | }; | 264 | }; |
265 | 265 | ||
266 | #define TYPE_BITS 3 | 266 | #define TYPE_BITS 3 |
267 | #define FLAG_BITS 27 | 267 | #define FLAG_BITS 27 |
268 | 268 | ||
269 | /* | 269 | /* |
270 | * The object type is stored in 3 bits. | 270 | * The object type is stored in 3 bits. |
271 | */ | 271 | */ |
272 | struct object { | 272 | struct object { |
273 | unsigned parsed : 1; | 273 | unsigned parsed : 1; |
274 | unsigned used : 1; | 274 | unsigned used : 1; |
275 | unsigned type : TYPE_BITS; | 275 | unsigned type : TYPE_BITS; |
276 | unsigned flags : FLAG_BITS; | 276 | unsigned flags : FLAG_BITS; |
277 | unsigned char sha1[20]; | 277 | unsigned char sha1[20]; |
278 | }; | 278 | }; |
279 | 279 | ||
280 | 280 | ||
281 | /** Returns the object, having parsed it to find out what it is. **/ | 281 | /** Returns the object, having parsed it to find out what it is. **/ |
282 | struct object *parse_object(const unsigned char *sha1); | 282 | struct object *parse_object(const unsigned char *sha1); |
283 | 283 | ||
284 | 284 | ||
285 | /* | 285 | /* |
286 | * from git:tree.h | 286 | * from git:tree.h |
287 | */ | 287 | */ |
288 | 288 | ||
289 | struct tree { | 289 | struct tree { |
290 | struct object object; | 290 | struct object object; |
291 | void *buffer; | 291 | void *buffer; |
292 | unsigned long size; | 292 | unsigned long size; |
293 | }; | 293 | }; |
294 | 294 | ||
295 | 295 | ||
296 | struct tree *lookup_tree(const unsigned char *sha1); | 296 | struct tree *lookup_tree(const unsigned char *sha1); |
297 | int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size); | 297 | int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size); |
298 | int parse_tree(struct tree *tree); | 298 | int parse_tree(struct tree *tree); |
299 | struct tree *parse_tree_indirect(const unsigned char *sha1); | 299 | struct tree *parse_tree_indirect(const unsigned char *sha1); |
300 | 300 | ||
301 | typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int); | 301 | typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int); |
302 | 302 | ||
303 | extern int read_tree_recursive(struct tree *tree, | 303 | extern int read_tree_recursive(struct tree *tree, |
304 | const char *base, int baselen, | 304 | const char *base, int baselen, |
305 | int stage, const char **match, | 305 | int stage, const char **match, |
306 | read_tree_fn_t fn); | 306 | read_tree_fn_t fn); |
307 | 307 | ||
308 | extern int read_tree(struct tree *tree, int stage, const char **paths); | 308 | extern int read_tree(struct tree *tree, int stage, const char **paths); |
309 | 309 | ||
310 | 310 | ||
311 | /* from git:commit.h */ | 311 | /* from git:commit.h */ |
312 | 312 | ||
313 | struct commit_list { | 313 | struct commit_list { |
314 | struct commit *item; | 314 | struct commit *item; |
315 | struct commit_list *next; | 315 | struct commit_list *next; |
316 | }; | 316 | }; |
317 | 317 | ||
318 | struct commit { | 318 | struct commit { |
319 | struct object object; | 319 | struct object object; |
320 | void *util; | 320 | void *util; |
321 | unsigned long date; | 321 | unsigned long date; |
322 | struct commit_list *parents; | 322 | struct commit_list *parents; |
323 | struct tree *tree; | 323 | struct tree *tree; |
324 | char *buffer; | 324 | char *buffer; |
325 | }; | 325 | }; |
326 | 326 | ||
327 | 327 | ||
328 | struct commit *lookup_commit(const unsigned char *sha1); | 328 | struct commit *lookup_commit(const unsigned char *sha1); |
329 | struct commit *lookup_commit_reference(const unsigned char *sha1); | 329 | struct commit *lookup_commit_reference(const unsigned char *sha1); |
330 | struct commit *lookup_commit_reference_gently(const unsigned char *sha1, | 330 | struct commit *lookup_commit_reference_gently(const unsigned char *sha1, |
331 | int quiet); | 331 | int quiet); |
332 | 332 | ||
333 | int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size); | 333 | int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size); |
334 | int parse_commit(struct commit *item); | 334 | int parse_commit(struct commit *item); |
335 | 335 | ||
336 | struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p); | 336 | struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p); |
337 | struct commit_list * insert_by_date(struct commit *item, struct commit_list **list); | 337 | struct commit_list * insert_by_date(struct commit *item, struct commit_list **list); |
338 | 338 | ||
339 | void free_commit_list(struct commit_list *list); | 339 | void free_commit_list(struct commit_list *list); |
340 | 340 | ||
341 | void sort_by_date(struct commit_list **list); | 341 | void sort_by_date(struct commit_list **list); |
342 | 342 | ||
343 | /* Commit formats */ | 343 | /* Commit formats */ |
344 | enum cmit_fmt { | 344 | enum cmit_fmt { |
345 | CMIT_FMT_RAW, | 345 | CMIT_FMT_RAW, |
346 | CMIT_FMT_MEDIUM, | 346 | CMIT_FMT_MEDIUM, |
347 | CMIT_FMT_DEFAULT = CMIT_FMT_MEDIUM, | 347 | CMIT_FMT_DEFAULT = CMIT_FMT_MEDIUM, |
348 | CMIT_FMT_SHORT, | 348 | CMIT_FMT_SHORT, |
349 | CMIT_FMT_FULL, | 349 | CMIT_FMT_FULL, |
350 | CMIT_FMT_FULLER, | 350 | CMIT_FMT_FULLER, |
351 | CMIT_FMT_ONELINE, | 351 | CMIT_FMT_ONELINE, |
352 | CMIT_FMT_EMAIL, | 352 | CMIT_FMT_EMAIL, |
353 | 353 | ||
354 | CMIT_FMT_UNSPECIFIED, | 354 | CMIT_FMT_UNSPECIFIED, |
355 | }; | 355 | }; |
356 | 356 | ||
357 | extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, int relative_date); | 357 | extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, int relative_date); |
358 | 358 | ||
359 | 359 | ||
360 | typedef void (*topo_sort_set_fn_t)(struct commit*, void *data); | 360 | typedef void (*topo_sort_set_fn_t)(struct commit*, void *data); |
361 | typedef void* (*topo_sort_get_fn_t)(struct commit*); | 361 | typedef void* (*topo_sort_get_fn_t)(struct commit*); |
362 | 362 | ||
363 | 363 | ||
364 | 364 | ||
365 | /* | 365 | /* |
366 | * from git:tag.h | 366 | * from git:tag.h |
367 | */ | 367 | */ |
368 | 368 | ||
369 | extern const char *tag_type; | 369 | extern const char *tag_type; |
370 | 370 | ||
371 | struct tag { | 371 | struct tag { |
372 | struct object object; | 372 | struct object object; |
373 | struct object *tagged; | 373 | struct object *tagged; |
374 | char *tag; | 374 | char *tag; |
375 | char *signature; /* not actually implemented */ | 375 | char *signature; /* not actually implemented */ |
376 | }; | 376 | }; |
377 | 377 | ||
378 | extern struct tag *lookup_tag(const unsigned char *sha1); | 378 | extern struct tag *lookup_tag(const unsigned char *sha1); |
379 | extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size); | 379 | extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size); |
380 | extern int parse_tag(struct tag *item); | 380 | extern int parse_tag(struct tag *item); |
381 | extern struct object *deref_tag(struct object *, const char *, int); | 381 | extern struct object *deref_tag(struct object *, const char *, int); |
382 | 382 | ||
383 | 383 | ||
384 | /* | 384 | /* |
385 | * from git:diffcore.h | 385 | * from git:diffcore.h |
386 | */ | 386 | */ |
387 | 387 | ||
388 | struct diff_filespec { | 388 | struct diff_filespec { |
389 | unsigned char sha1[20]; | 389 | unsigned char sha1[20]; |
390 | char *path; | 390 | char *path; |
391 | void *data; | 391 | void *data; |
392 | void *cnt_data; | 392 | void *cnt_data; |
393 | unsigned long size; | 393 | unsigned long size; |
394 | int xfrm_flags; /* for use by the xfrm */ | 394 | int xfrm_flags; /* for use by the xfrm */ |
395 | unsigned short mode; /* file mode */ | 395 | unsigned short mode; /* file mode */ |
396 | unsigned sha1_valid : 1; /* if true, use sha1 and trust mode; | 396 | unsigned sha1_valid : 1; /* if true, use sha1 and trust mode; |
397 | * if false, use the name and read from | 397 | * if false, use the name and read from |
398 | * the filesystem. | 398 | * the filesystem. |
399 | */ | 399 | */ |
400 | #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0) | 400 | #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0) |
401 | unsigned should_free : 1; /* data should be free()'ed */ | 401 | unsigned should_free : 1; /* data should be free()'ed */ |
402 | unsigned should_munmap : 1; /* data should be munmap()'ed */ | 402 | unsigned should_munmap : 1; /* data should be munmap()'ed */ |
403 | }; | 403 | }; |
404 | 404 | ||
405 | struct diff_filepair { | 405 | struct diff_filepair { |
406 | struct diff_filespec *one; | 406 | struct diff_filespec *one; |
407 | struct diff_filespec *two; | 407 | struct diff_filespec *two; |
408 | unsigned short int score; | 408 | unsigned short int score; |
409 | char status; /* M C R N D U (see Documentation/diff-format.txt) */ | 409 | char status; /* M C R N D U (see Documentation/diff-format.txt) */ |
410 | unsigned source_stays : 1; /* all of R/C are copies */ | 410 | unsigned source_stays : 1; /* all of R/C are copies */ |
411 | unsigned broken_pair : 1; | 411 | unsigned broken_pair : 1; |
412 | unsigned renamed_pair : 1; | 412 | unsigned renamed_pair : 1; |
413 | }; | 413 | }; |
414 | 414 | ||
415 | #define DIFF_PAIR_UNMERGED(p) \ | 415 | #define DIFF_PAIR_UNMERGED(p) \ |
416 | (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two)) | 416 | (!DIFF_FILE_VALID((p)->one) && !DIFF_FILE_VALID((p)->two)) |
417 | 417 | ||
418 | #define DIFF_PAIR_RENAME(p) ((p)->renamed_pair) | 418 | #define DIFF_PAIR_RENAME(p) ((p)->renamed_pair) |
419 | 419 | ||
420 | #define DIFF_PAIR_BROKEN(p) \ | 420 | #define DIFF_PAIR_BROKEN(p) \ |
421 | ( (!DIFF_FILE_VALID((p)->one) != !DIFF_FILE_VALID((p)->two)) && \ | 421 | ( (!DIFF_FILE_VALID((p)->one) != !DIFF_FILE_VALID((p)->two)) && \ |
422 | ((p)->broken_pair != 0) ) | 422 | ((p)->broken_pair != 0) ) |
423 | 423 | ||
424 | #define DIFF_PAIR_TYPE_CHANGED(p) \ | 424 | #define DIFF_PAIR_TYPE_CHANGED(p) \ |
425 | ((S_IFMT & (p)->one->mode) != (S_IFMT & (p)->two->mode)) | 425 | ((S_IFMT & (p)->one->mode) != (S_IFMT & (p)->two->mode)) |
426 | 426 | ||
427 | #define DIFF_PAIR_MODE_CHANGED(p) ((p)->one->mode != (p)->two->mode) | 427 | #define DIFF_PAIR_MODE_CHANGED(p) ((p)->one->mode != (p)->two->mode) |
428 | 428 | ||
429 | extern void diff_free_filepair(struct diff_filepair *); | 429 | extern void diff_free_filepair(struct diff_filepair *); |
430 | 430 | ||
431 | extern int diff_unmodified_pair(struct diff_filepair *); | 431 | extern int diff_unmodified_pair(struct diff_filepair *); |
432 | 432 | ||
433 | struct diff_queue_struct { | 433 | struct diff_queue_struct { |
434 | struct diff_filepair **queue; | 434 | struct diff_filepair **queue; |
435 | int alloc; | 435 | int alloc; |
436 | int nr; | 436 | int nr; |
437 | }; | 437 | }; |
438 | 438 | ||
439 | 439 | ||
440 | /* | 440 | /* |
441 | * from git:diff.h | 441 | * from git:diff.h |
442 | */ | 442 | */ |
443 | 443 | ||
444 | 444 | ||
445 | struct rev_info; | 445 | struct rev_info; |
446 | struct diff_options; | 446 | struct diff_options; |
447 | struct diff_queue_struct; | 447 | struct diff_queue_struct; |
448 | 448 | ||
449 | typedef void (*change_fn_t)(struct diff_options *options, | 449 | typedef void (*change_fn_t)(struct diff_options *options, |
450 | unsigned old_mode, unsigned new_mode, | 450 | unsigned old_mode, unsigned new_mode, |
451 | const unsigned char *old_sha1, | 451 | const unsigned char *old_sha1, |
452 | const unsigned char *new_sha1, | 452 | const unsigned char *new_sha1, |
453 | const char *base, const char *path); | 453 | const char *base, const char *path); |
454 | 454 | ||
455 | typedef void (*add_remove_fn_t)(struct diff_options *options, | 455 | typedef void (*add_remove_fn_t)(struct diff_options *options, |
456 | int addremove, unsigned mode, | 456 | int addremove, unsigned mode, |
457 | const unsigned char *sha1, | 457 | const unsigned char *sha1, |
458 | const char *base, const char *path); | 458 | const char *base, const char *path); |
459 | 459 | ||
460 | typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, | 460 | typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, |
461 | struct diff_options *options, void *data); | 461 | struct diff_options *options, void *data); |
462 | 462 | ||
463 | #define DIFF_FORMAT_RAW 0x0001 | 463 | #define DIFF_FORMAT_RAW 0x0001 |
464 | #define DIFF_FORMAT_DIFFSTAT0x0002 | 464 | #define DIFF_FORMAT_DIFFSTAT0x0002 |
465 | #define DIFF_FORMAT_NUMSTAT0x0004 | 465 | #define DIFF_FORMAT_NUMSTAT0x0004 |
466 | #define DIFF_FORMAT_SUMMARY0x0008 | 466 | #define DIFF_FORMAT_SUMMARY0x0008 |
467 | #define DIFF_FORMAT_PATCH0x0010 | 467 | #define DIFF_FORMAT_PATCH0x0010 |
468 | 468 | ||
469 | /* These override all above */ | 469 | /* These override all above */ |
470 | #define DIFF_FORMAT_NAME0x0100 | 470 | #define DIFF_FORMAT_NAME0x0100 |
471 | #define DIFF_FORMAT_NAME_STATUS0x0200 | 471 | #define DIFF_FORMAT_NAME_STATUS0x0200 |
472 | #define DIFF_FORMAT_CHECKDIFF0x0400 | 472 | #define DIFF_FORMAT_CHECKDIFF0x0400 |
473 | 473 | ||
474 | /* Same as output_format = 0 but we know that -s flag was given | 474 | /* Same as output_format = 0 but we know that -s flag was given |
475 | * and we should not give default value to output_format. | 475 | * and we should not give default value to output_format. |
476 | */ | 476 | */ |
477 | #define DIFF_FORMAT_NO_OUTPUT0x0800 | 477 | #define DIFF_FORMAT_NO_OUTPUT0x0800 |
478 | 478 | ||
479 | #define DIFF_FORMAT_CALLBACK0x1000 | 479 | #define DIFF_FORMAT_CALLBACK0x1000 |
480 | 480 | ||
481 | struct diff_options { | 481 | struct diff_options { |
482 | const char *filter; | 482 | const char *filter; |
483 | const char *orderfile; | 483 | const char *orderfile; |
484 | const char *pickaxe; | 484 | const char *pickaxe; |
485 | const char *single_follow; | 485 | const char *single_follow; |
486 | unsigned recursive:1, | 486 | unsigned recursive:1, |
487 | tree_in_recursive:1, | 487 | tree_in_recursive:1, |
488 | binary:1, | 488 | binary:1, |
489 | text:1, | 489 | text:1, |
490 | full_index:1, | 490 | full_index:1, |
491 | silent_on_remove:1, | 491 | silent_on_remove:1, |
492 | find_copies_harder:1, | 492 | find_copies_harder:1, |
493 | color_diff:1, | 493 | color_diff:1, |
494 | color_diff_words:1; | 494 | color_diff_words:1; |
495 | int context; | 495 | int context; |
496 | int break_opt; | 496 | int break_opt; |
497 | int detect_rename; | 497 | int detect_rename; |
498 | int line_termination; | 498 | int line_termination; |
499 | int output_format; | 499 | int output_format; |
500 | int pickaxe_opts; | 500 | int pickaxe_opts; |
501 | int rename_score; | 501 | int rename_score; |
502 | int reverse_diff; | 502 | int reverse_diff; |
503 | int rename_limit; | 503 | int rename_limit; |
504 | int setup; | 504 | int setup; |
505 | int abbrev; | 505 | int abbrev; |
506 | const char *msg_sep; | 506 | const char *msg_sep; |
507 | const char *stat_sep; | 507 | const char *stat_sep; |
508 | long xdl_opts; | 508 | long xdl_opts; |
509 | 509 | ||
510 | int stat_width; | 510 | int stat_width; |
511 | int stat_name_width; | 511 | int stat_name_width; |
512 | 512 | ||
513 | int nr_paths; | 513 | int nr_paths; |
514 | const char **paths; | 514 | const char **paths; |
515 | int *pathlens; | 515 | int *pathlens; |
516 | change_fn_t change; | 516 | change_fn_t change; |
517 | add_remove_fn_t add_remove; | 517 | add_remove_fn_t add_remove; |
518 | diff_format_fn_t format_callback; | 518 | diff_format_fn_t format_callback; |
519 | void *format_callback_data; | 519 | void *format_callback_data; |
520 | }; | 520 | }; |
521 | 521 | ||
522 | enum color_diff { | 522 | enum color_diff { |
523 | DIFF_RESET = 0, | 523 | DIFF_RESET = 0, |
524 | DIFF_PLAIN = 1, | 524 | DIFF_PLAIN = 1, |
525 | DIFF_METAINFO = 2, | 525 | DIFF_METAINFO = 2, |
526 | DIFF_FRAGINFO = 3, | 526 | DIFF_FRAGINFO = 3, |
527 | DIFF_FILE_OLD = 4, | 527 | DIFF_FILE_OLD = 4, |
528 | DIFF_FILE_NEW = 5, | 528 | DIFF_FILE_NEW = 5, |
529 | DIFF_COMMIT = 6, | 529 | DIFF_COMMIT = 6, |
530 | DIFF_WHITESPACE = 7, | 530 | DIFF_WHITESPACE = 7, |
531 | }; | 531 | }; |
532 | 532 | ||
533 | 533 | ||
534 | extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new, | 534 | extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new, |
535 | const char *base, struct diff_options *opt); | 535 | const char *base, struct diff_options *opt); |
536 | 536 | ||
537 | extern int diff_root_tree_sha1(const unsigned char *new, const char *base, | 537 | extern int diff_root_tree_sha1(const unsigned char *new, const char *base, |
538 | struct diff_options *opt); | 538 | struct diff_options *opt); |
539 | 539 | ||
540 | extern int git_diff_ui_config(const char *var, const char *value); | 540 | extern int git_diff_ui_config(const char *var, const char *value); |
541 | extern void diff_setup(struct diff_options *); | 541 | extern void diff_setup(struct diff_options *); |
542 | extern int diff_opt_parse(struct diff_options *, const char **, int); | 542 | extern int diff_opt_parse(struct diff_options *, const char **, int); |
543 | extern int diff_setup_done(struct diff_options *); | 543 | extern int diff_setup_done(struct diff_options *); |
544 | 544 | ||
545 | 545 | ||
546 | extern void diffcore_std(struct diff_options *); | 546 | extern void diffcore_std(struct diff_options *); |
547 | extern void diff_flush(struct diff_options*); | 547 | extern void diff_flush(struct diff_options*); |
548 | 548 | ||
549 | 549 | ||
550 | /* diff-raw status letters */ | 550 | /* diff-raw status letters */ |
551 | #define DIFF_STATUS_ADDED 'A' | 551 | #define DIFF_STATUS_ADDED 'A' |
552 | #define DIFF_STATUS_COPIED 'C' | 552 | #define DIFF_STATUS_COPIED 'C' |
553 | #define DIFF_STATUS_DELETED 'D' | 553 | #define DIFF_STATUS_DELETED 'D' |
554 | #define DIFF_STATUS_MODIFIED 'M' | 554 | #define DIFF_STATUS_MODIFIED 'M' |
555 | #define DIFF_STATUS_RENAMED 'R' | 555 | #define DIFF_STATUS_RENAMED 'R' |
556 | #define DIFF_STATUS_TYPE_CHANGED'T' | 556 | #define DIFF_STATUS_TYPE_CHANGED'T' |
557 | #define DIFF_STATUS_UNKNOWN 'X' | 557 | #define DIFF_STATUS_UNKNOWN 'X' |
558 | #define DIFF_STATUS_UNMERGED 'U' | 558 | #define DIFF_STATUS_UNMERGED 'U' |
559 | 559 | ||
560 | 560 | ||
561 | 561 | ||
562 | /* | 562 | /* |
563 | * from git:refs.g | 563 | * from git:refs.g |
564 | */ | 564 | */ |
565 | 565 | ||
566 | typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data); | 566 | typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data); |
567 | extern int head_ref(each_ref_fn, void *); | 567 | extern int head_ref(each_ref_fn, void *); |
568 | extern int for_each_ref(each_ref_fn, void *); | 568 | extern int for_each_ref(each_ref_fn, void *); |
569 | extern int for_each_tag_ref(each_ref_fn, void *); | 569 | extern int for_each_tag_ref(each_ref_fn, void *); |
570 | extern int for_each_branch_ref(each_ref_fn, void *); | 570 | extern int for_each_branch_ref(each_ref_fn, void *); |
571 | extern int for_each_remote_ref(each_ref_fn, void *); | 571 | extern int for_each_remote_ref(each_ref_fn, void *); |
572 | 572 | ||
573 | 573 | ||
574 | 574 | ||
575 | /* | 575 | /* |
576 | * from git:revision.h | 576 | * from git:revision.h |
577 | */ | 577 | */ |
578 | 578 | ||
579 | struct rev_info; | 579 | struct rev_info; |
580 | struct log_info; | 580 | struct log_info; |
581 | 581 | ||
582 | typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit); | 582 | typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit); |
583 | 583 | ||
584 | struct rev_info { | 584 | struct rev_info { |
585 | /* Starting list */ | 585 | /* Starting list */ |
586 | struct commit_list *commits; | 586 | struct commit_list *commits; |
587 | struct object_array pending; | 587 | struct object_array pending; |
588 | 588 | ||
589 | /* Basic information */ | 589 | /* Basic information */ |
590 | const char *prefix; | 590 | const char *prefix; |
591 | void *prune_data; | 591 | void *prune_data; |
592 | prune_fn_t *prune_fn; | 592 | prune_fn_t *prune_fn; |
593 | 593 | ||
594 | /* Traversal flags */ | 594 | /* Traversal flags */ |
595 | unsigned intdense:1, | 595 | unsigned intdense:1, |
596 | no_merges:1, | 596 | no_merges:1, |
597 | no_walk:1, | 597 | no_walk:1, |
598 | remove_empty_trees:1, | 598 | remove_empty_trees:1, |
599 | simplify_history:1, | 599 | simplify_history:1, |
600 | lifo:1, | 600 | lifo:1, |
601 | topo_order:1, | 601 | topo_order:1, |
602 | tag_objects:1, | 602 | tag_objects:1, |
603 | tree_objects:1, | 603 | tree_objects:1, |
604 | blob_objects:1, | 604 | blob_objects:1, |
605 | edge_hint:1, | 605 | edge_hint:1, |
606 | limited:1, | 606 | limited:1, |
607 | unpacked:1, /* see also ignore_packed below */ | 607 | unpacked:1, /* see also ignore_packed below */ |
608 | boundary:1, | 608 | boundary:1, |
609 | parents:1; | 609 | parents:1; |
610 | 610 | ||
611 | /* Diff flags */ | 611 | /* Diff flags */ |
612 | unsigned intdiff:1, | 612 | unsigned intdiff:1, |
613 | full_diff:1, | 613 | full_diff:1, |
614 | show_root_diff:1, | 614 | show_root_diff:1, |
615 | no_commit_id:1, | 615 | no_commit_id:1, |
616 | verbose_header:1, | 616 | verbose_header:1, |
617 | ignore_merges:1, | 617 | ignore_merges:1, |
618 | combine_merges:1, | 618 | combine_merges:1, |
619 | dense_combined_merges:1, | 619 | dense_combined_merges:1, |
620 | always_show_header:1; | 620 | always_show_header:1; |
621 | 621 | ||
622 | /* Format info */ | 622 | /* Format info */ |
623 | unsigned intshown_one:1, | 623 | unsigned intshown_one:1, |
624 | abbrev_commit:1, | 624 | abbrev_commit:1, |
625 | relative_date:1; | 625 | relative_date:1; |
626 | 626 | ||
627 | const char **ignore_packed; /* pretend objects in these are unpacked */ | 627 | const char **ignore_packed; /* pretend objects in these are unpacked */ |
628 | int num_ignore_packed; | 628 | int num_ignore_packed; |
629 | 629 | ||
630 | unsigned intabbrev; | 630 | unsigned intabbrev; |
631 | enum cmit_fmtcommit_format; | 631 | enum cmit_fmtcommit_format; |
632 | struct log_info *loginfo; | 632 | struct log_info *loginfo; |
633 | int nr, total; | 633 | int nr, total; |
634 | const char*mime_boundary; | 634 | const char*mime_boundary; |
635 | const char*message_id; | 635 | const char*message_id; |
636 | const char*ref_message_id; | 636 | const char*ref_message_id; |
637 | const char*add_signoff; | 637 | const char*add_signoff; |
638 | const char*extra_headers; | 638 | const char*extra_headers; |
639 | 639 | ||
640 | /* Filter by commit log message */ | 640 | /* Filter by commit log message */ |
641 | struct grep_opt*grep_filter; | 641 | struct grep_opt*grep_filter; |
642 | 642 | ||
643 | /* special limits */ | 643 | /* special limits */ |
644 | int max_count; | 644 | int max_count; |
645 | unsigned long max_age; | 645 | unsigned long max_age; |
646 | unsigned long min_age; | 646 | unsigned long min_age; |
647 | 647 | ||
648 | /* diff info for patches and for paths limiting */ | 648 | /* diff info for patches and for paths limiting */ |
649 | struct diff_options diffopt; | 649 | struct diff_options diffopt; |
650 | struct diff_options pruning; | 650 | struct diff_options pruning; |
651 | 651 | ||
652 | topo_sort_set_fn_t topo_setter; | 652 | topo_sort_set_fn_t topo_setter; |
653 | topo_sort_get_fn_t topo_getter; | 653 | topo_sort_get_fn_t topo_getter; |
654 | }; | 654 | }; |
655 | 655 | ||
656 | 656 | ||
657 | extern void init_revisions(struct rev_info *revs, const char *prefix); | 657 | extern void init_revisions(struct rev_info *revs, const char *prefix); |
658 | extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def); | 658 | extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def); |
659 | extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename); | 659 | extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename); |
660 | 660 | ||
661 | extern void prepare_revision_walk(struct rev_info *revs); | 661 | extern void prepare_revision_walk(struct rev_info *revs); |
662 | extern struct commit *get_revision(struct rev_info *revs); | 662 | extern struct commit *get_revision(struct rev_info *revs); |
663 | 663 | ||
664 | 664 | ||
665 | 665 | ||
666 | /* from git:log-tree.h */ | 666 | /* from git:log-tree.h */ |
667 | 667 | ||
668 | int log_tree_commit(struct rev_info *, struct commit *); | 668 | int log_tree_commit(struct rev_info *, struct commit *); |
669 | 669 | ||
670 | 670 | ||
671 | 671 | ||
672 | /* from git:archive.h */ | ||
673 | |||
674 | struct archiver_args { | ||
675 | const char *base; | ||
676 | struct tree *tree; | ||
677 | const unsigned char *commit_sha1; | ||
678 | time_t time; | ||
679 | const char **pathspec; | ||
680 | unsigned int verbose : 1; | ||
681 | void *extra; | ||
682 | }; | ||
683 | |||
684 | typedef int (*write_archive_fn_t)(struct archiver_args *); | ||
685 | |||
686 | typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv); | ||
687 | |||
688 | struct archiver { | ||
689 | const char *name; | ||
690 | struct archiver_args args; | ||
691 | write_archive_fn_t write_archive; | ||
692 | parse_extra_args_fn_t parse_extra; | ||
693 | }; | ||
694 | |||
695 | extern int write_tar_archive(struct archiver_args *); | ||
696 | extern int write_zip_archive(struct archiver_args *); | ||
697 | extern void *parse_extra_zip_args(int argc, const char **argv); | ||
698 | |||
672 | #endif /* GIT_H */ | 699 | #endif /* GIT_H */ |
@@ -1,168 +1,185 @@ | |||
1 | /* shared.c: global vars + some callback functions | 1 | /* shared.c: global vars + some callback functions |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Lars Hjemli | 3 | * Copyright (C) 2006 Lars Hjemli |
4 | * | 4 | * |
5 | * Licensed under GNU General Public License v2 | 5 | * Licensed under GNU General Public License v2 |
6 | * (see COPYING for full license text) | 6 | * (see COPYING for full license text) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | 10 | ||
11 | struct repolist cgit_repolist; | 11 | struct repolist cgit_repolist; |
12 | struct repoinfo *cgit_repo; | 12 | struct repoinfo *cgit_repo; |
13 | 13 | ||
14 | char *cgit_root_title = "Git repository browser"; | 14 | char *cgit_root_title = "Git repository browser"; |
15 | char *cgit_css = "/cgit.css"; | 15 | char *cgit_css = "/cgit.css"; |
16 | char *cgit_logo = "/git-logo.png"; | 16 | char *cgit_logo = "/git-logo.png"; |
17 | char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; | 17 | char *cgit_logo_link = "http://www.kernel.org/pub/software/scm/git/docs/"; |
18 | char *cgit_virtual_root = NULL; | 18 | char *cgit_virtual_root = NULL; |
19 | 19 | ||
20 | char *cgit_cache_root = "/var/cache/cgit"; | 20 | char *cgit_cache_root = "/var/cache/cgit"; |
21 | 21 | ||
22 | int cgit_nocache = 0; | 22 | int cgit_nocache = 0; |
23 | int cgit_max_lock_attempts = 5; | 23 | int cgit_max_lock_attempts = 5; |
24 | int cgit_cache_root_ttl = 5; | 24 | int cgit_cache_root_ttl = 5; |
25 | int cgit_cache_repo_ttl = 5; | 25 | int cgit_cache_repo_ttl = 5; |
26 | int cgit_cache_dynamic_ttl = 5; | 26 | int cgit_cache_dynamic_ttl = 5; |
27 | int cgit_cache_static_ttl = -1; | 27 | int cgit_cache_static_ttl = -1; |
28 | int cgit_cache_max_create_time = 5; | 28 | int cgit_cache_max_create_time = 5; |
29 | 29 | ||
30 | int cgit_max_msg_len = 60; | 30 | int cgit_max_msg_len = 60; |
31 | 31 | ||
32 | char *cgit_repo_name = NULL; | 32 | char *cgit_repo_name = NULL; |
33 | char *cgit_repo_desc = NULL; | 33 | char *cgit_repo_desc = NULL; |
34 | char *cgit_repo_owner = NULL; | 34 | char *cgit_repo_owner = NULL; |
35 | 35 | ||
36 | int cgit_query_has_symref = 0; | 36 | int cgit_query_has_symref = 0; |
37 | int cgit_query_has_sha1 = 0; | 37 | int cgit_query_has_sha1 = 0; |
38 | 38 | ||
39 | char *cgit_querystring = NULL; | 39 | char *cgit_querystring = NULL; |
40 | char *cgit_query_repo = NULL; | 40 | char *cgit_query_repo = NULL; |
41 | char *cgit_query_page = NULL; | 41 | char *cgit_query_page = NULL; |
42 | char *cgit_query_head = NULL; | 42 | char *cgit_query_head = NULL; |
43 | char *cgit_query_search = NULL; | 43 | char *cgit_query_search = NULL; |
44 | char *cgit_query_sha1 = NULL; | 44 | char *cgit_query_sha1 = NULL; |
45 | char *cgit_query_sha2 = NULL; | 45 | char *cgit_query_sha2 = NULL; |
46 | char *cgit_query_path = NULL; | 46 | char *cgit_query_path = NULL; |
47 | char *cgit_query_name = NULL; | ||
47 | int cgit_query_ofs = 0; | 48 | int cgit_query_ofs = 0; |
48 | 49 | ||
49 | int htmlfd = 0; | 50 | int htmlfd = 0; |
50 | 51 | ||
52 | int chk_zero(int result, char *msg) | ||
53 | { | ||
54 | if (result != 0) | ||
55 | die("%s: %s", msg, strerror(errno)); | ||
56 | return result; | ||
57 | } | ||
58 | |||
59 | int chk_positive(int result, char *msg) | ||
60 | { | ||
61 | if (result <= 0) | ||
62 | die("%s: %s", msg, strerror(errno)); | ||
63 | return result; | ||
64 | } | ||
65 | |||
51 | struct repoinfo *add_repo(const char *url) | 66 | struct repoinfo *add_repo(const char *url) |
52 | { | 67 | { |
53 | struct repoinfo *ret; | 68 | struct repoinfo *ret; |
54 | 69 | ||
55 | if (++cgit_repolist.count > cgit_repolist.length) { | 70 | if (++cgit_repolist.count > cgit_repolist.length) { |
56 | if (cgit_repolist.length == 0) | 71 | if (cgit_repolist.length == 0) |
57 | cgit_repolist.length = 8; | 72 | cgit_repolist.length = 8; |
58 | else | 73 | else |
59 | cgit_repolist.length *= 2; | 74 | cgit_repolist.length *= 2; |
60 | cgit_repolist.repos = xrealloc(cgit_repolist.repos, | 75 | cgit_repolist.repos = xrealloc(cgit_repolist.repos, |
61 | cgit_repolist.length * | 76 | cgit_repolist.length * |
62 | sizeof(struct repoinfo)); | 77 | sizeof(struct repoinfo)); |
63 | } | 78 | } |
64 | 79 | ||
65 | ret = &cgit_repolist.repos[cgit_repolist.count-1]; | 80 | ret = &cgit_repolist.repos[cgit_repolist.count-1]; |
66 | ret->url = xstrdup(url); | 81 | ret->url = xstrdup(url); |
67 | ret->name = ret->url; | 82 | ret->name = ret->url; |
68 | ret->path = NULL; | 83 | ret->path = NULL; |
69 | ret->desc = NULL; | 84 | ret->desc = NULL; |
70 | ret->owner = NULL; | 85 | ret->owner = NULL; |
71 | return ret; | 86 | return ret; |
72 | } | 87 | } |
73 | 88 | ||
74 | void cgit_global_config_cb(const char *name, const char *value) | 89 | void cgit_global_config_cb(const char *name, const char *value) |
75 | { | 90 | { |
76 | if (!strcmp(name, "root-title")) | 91 | if (!strcmp(name, "root-title")) |
77 | cgit_root_title = xstrdup(value); | 92 | cgit_root_title = xstrdup(value); |
78 | else if (!strcmp(name, "css")) | 93 | else if (!strcmp(name, "css")) |
79 | cgit_css = xstrdup(value); | 94 | cgit_css = xstrdup(value); |
80 | else if (!strcmp(name, "logo")) | 95 | else if (!strcmp(name, "logo")) |
81 | cgit_logo = xstrdup(value); | 96 | cgit_logo = xstrdup(value); |
82 | else if (!strcmp(name, "logo-link")) | 97 | else if (!strcmp(name, "logo-link")) |
83 | cgit_logo_link = xstrdup(value); | 98 | cgit_logo_link = xstrdup(value); |
84 | else if (!strcmp(name, "virtual-root")) | 99 | else if (!strcmp(name, "virtual-root")) |
85 | cgit_virtual_root = xstrdup(value); | 100 | cgit_virtual_root = xstrdup(value); |
86 | else if (!strcmp(name, "nocache")) | 101 | else if (!strcmp(name, "nocache")) |
87 | cgit_nocache = atoi(value); | 102 | cgit_nocache = atoi(value); |
88 | else if (!strcmp(name, "cache-root")) | 103 | else if (!strcmp(name, "cache-root")) |
89 | cgit_cache_root = xstrdup(value); | 104 | cgit_cache_root = xstrdup(value); |
90 | else if (!strcmp(name, "cache-root-ttl")) | 105 | else if (!strcmp(name, "cache-root-ttl")) |
91 | cgit_cache_root_ttl = atoi(value); | 106 | cgit_cache_root_ttl = atoi(value); |
92 | else if (!strcmp(name, "cache-repo-ttl")) | 107 | else if (!strcmp(name, "cache-repo-ttl")) |
93 | cgit_cache_repo_ttl = atoi(value); | 108 | cgit_cache_repo_ttl = atoi(value); |
94 | else if (!strcmp(name, "cache-static-ttl")) | 109 | else if (!strcmp(name, "cache-static-ttl")) |
95 | cgit_cache_static_ttl = atoi(value); | 110 | cgit_cache_static_ttl = atoi(value); |
96 | else if (!strcmp(name, "cache-dynamic-ttl")) | 111 | else if (!strcmp(name, "cache-dynamic-ttl")) |
97 | cgit_cache_dynamic_ttl = atoi(value); | 112 | cgit_cache_dynamic_ttl = atoi(value); |
98 | else if (!strcmp(name, "max-message-length")) | 113 | else if (!strcmp(name, "max-message-length")) |
99 | cgit_max_msg_len = atoi(value); | 114 | cgit_max_msg_len = atoi(value); |
100 | else if (!strcmp(name, "repo.url")) | 115 | else if (!strcmp(name, "repo.url")) |
101 | cgit_repo = add_repo(value); | 116 | cgit_repo = add_repo(value); |
102 | else if (!strcmp(name, "repo.name")) | 117 | else if (!strcmp(name, "repo.name")) |
103 | cgit_repo->name = xstrdup(value); | 118 | cgit_repo->name = xstrdup(value); |
104 | else if (cgit_repo && !strcmp(name, "repo.path")) | 119 | else if (cgit_repo && !strcmp(name, "repo.path")) |
105 | cgit_repo->path = xstrdup(value); | 120 | cgit_repo->path = xstrdup(value); |
106 | else if (cgit_repo && !strcmp(name, "repo.desc")) | 121 | else if (cgit_repo && !strcmp(name, "repo.desc")) |
107 | cgit_repo->desc = xstrdup(value); | 122 | cgit_repo->desc = xstrdup(value); |
108 | else if (cgit_repo && !strcmp(name, "repo.owner")) | 123 | else if (cgit_repo && !strcmp(name, "repo.owner")) |
109 | cgit_repo->owner = xstrdup(value); | 124 | cgit_repo->owner = xstrdup(value); |
110 | } | 125 | } |
111 | 126 | ||
112 | void cgit_repo_config_cb(const char *name, const char *value) | 127 | void cgit_repo_config_cb(const char *name, const char *value) |
113 | { | 128 | { |
114 | if (!strcmp(name, "name")) | 129 | if (!strcmp(name, "name")) |
115 | cgit_repo_name = xstrdup(value); | 130 | cgit_repo_name = xstrdup(value); |
116 | else if (!strcmp(name, "desc")) | 131 | else if (!strcmp(name, "desc")) |
117 | cgit_repo_desc = xstrdup(value); | 132 | cgit_repo_desc = xstrdup(value); |
118 | else if (!strcmp(name, "owner")) | 133 | else if (!strcmp(name, "owner")) |
119 | cgit_repo_owner = xstrdup(value); | 134 | cgit_repo_owner = xstrdup(value); |
120 | } | 135 | } |
121 | 136 | ||
122 | void cgit_querystring_cb(const char *name, const char *value) | 137 | void cgit_querystring_cb(const char *name, const char *value) |
123 | { | 138 | { |
124 | if (!strcmp(name,"r")) { | 139 | if (!strcmp(name,"r")) { |
125 | cgit_query_repo = xstrdup(value); | 140 | cgit_query_repo = xstrdup(value); |
126 | } else if (!strcmp(name, "p")) { | 141 | } else if (!strcmp(name, "p")) { |
127 | cgit_query_page = xstrdup(value); | 142 | cgit_query_page = xstrdup(value); |
128 | } else if (!strcmp(name, "q")) { | 143 | } else if (!strcmp(name, "q")) { |
129 | cgit_query_search = xstrdup(value); | 144 | cgit_query_search = xstrdup(value); |
130 | } else if (!strcmp(name, "h")) { | 145 | } else if (!strcmp(name, "h")) { |
131 | cgit_query_head = xstrdup(value); | 146 | cgit_query_head = xstrdup(value); |
132 | cgit_query_has_symref = 1; | 147 | cgit_query_has_symref = 1; |
133 | } else if (!strcmp(name, "id")) { | 148 | } else if (!strcmp(name, "id")) { |
134 | cgit_query_sha1 = xstrdup(value); | 149 | cgit_query_sha1 = xstrdup(value); |
135 | cgit_query_has_sha1 = 1; | 150 | cgit_query_has_sha1 = 1; |
136 | } else if (!strcmp(name, "id2")) { | 151 | } else if (!strcmp(name, "id2")) { |
137 | cgit_query_sha2 = xstrdup(value); | 152 | cgit_query_sha2 = xstrdup(value); |
138 | cgit_query_has_sha1 = 1; | 153 | cgit_query_has_sha1 = 1; |
139 | } else if (!strcmp(name, "ofs")) { | 154 | } else if (!strcmp(name, "ofs")) { |
140 | cgit_query_ofs = atoi(value); | 155 | cgit_query_ofs = atoi(value); |
141 | } else if (!strcmp(name, "path")) { | 156 | } else if (!strcmp(name, "path")) { |
142 | cgit_query_path = xstrdup(value); | 157 | cgit_query_path = xstrdup(value); |
158 | } else if (!strcmp(name, "name")) { | ||
159 | cgit_query_name = xstrdup(value); | ||
143 | } | 160 | } |
144 | } | 161 | } |
145 | 162 | ||
146 | void *cgit_free_commitinfo(struct commitinfo *info) | 163 | void *cgit_free_commitinfo(struct commitinfo *info) |
147 | { | 164 | { |
148 | free(info->author); | 165 | free(info->author); |
149 | free(info->author_email); | 166 | free(info->author_email); |
150 | free(info->committer); | 167 | free(info->committer); |
151 | free(info->committer_email); | 168 | free(info->committer_email); |
152 | free(info->subject); | 169 | free(info->subject); |
153 | free(info); | 170 | free(info); |
154 | return NULL; | 171 | return NULL; |
155 | } | 172 | } |
156 | 173 | ||
157 | int hextoint(char c) | 174 | int hextoint(char c) |
158 | { | 175 | { |
159 | if (c >= 'a' && c <= 'f') | 176 | if (c >= 'a' && c <= 'f') |
160 | return 10 + c - 'a'; | 177 | return 10 + c - 'a'; |
161 | else if (c >= 'A' && c <= 'F') | 178 | else if (c >= 'A' && c <= 'F') |
162 | return 10 + c - 'A'; | 179 | return 10 + c - 'A'; |
163 | else if (c >= '0' && c <= '9') | 180 | else if (c >= '0' && c <= '9') |
164 | return c - '0'; | 181 | return c - '0'; |
165 | else | 182 | else |
166 | return -1; | 183 | return -1; |
167 | } | 184 | } |
168 | 185 | ||
diff --git a/ui-commit.c b/ui-commit.c index 73fa104..de3f2cf 100644 --- a/ui-commit.c +++ b/ui-commit.c | |||
@@ -1,185 +1,192 @@ | |||
1 | /* ui-commit.c: generate commit view | 1 | /* ui-commit.c: generate commit view |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Lars Hjemli | 3 | * Copyright (C) 2006 Lars Hjemli |
4 | * | 4 | * |
5 | * Licensed under GNU General Public License v2 | 5 | * Licensed under GNU General Public License v2 |
6 | * (see COPYING for full license text) | 6 | * (see COPYING for full license text) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | 10 | ||
11 | int files = 0; | 11 | int files = 0; |
12 | 12 | ||
13 | void print_filepair(struct diff_filepair *pair) | 13 | void print_filepair(struct diff_filepair *pair) |
14 | { | 14 | { |
15 | char *query; | 15 | char *query; |
16 | char *class; | 16 | char *class; |
17 | 17 | ||
18 | switch (pair->status) { | 18 | switch (pair->status) { |
19 | case DIFF_STATUS_ADDED: | 19 | case DIFF_STATUS_ADDED: |
20 | class = "add"; | 20 | class = "add"; |
21 | break; | 21 | break; |
22 | case DIFF_STATUS_COPIED: | 22 | case DIFF_STATUS_COPIED: |
23 | class = "cpy"; | 23 | class = "cpy"; |
24 | break; | 24 | break; |
25 | case DIFF_STATUS_DELETED: | 25 | case DIFF_STATUS_DELETED: |
26 | class = "del"; | 26 | class = "del"; |
27 | break; | 27 | break; |
28 | case DIFF_STATUS_MODIFIED: | 28 | case DIFF_STATUS_MODIFIED: |
29 | class = "upd"; | 29 | class = "upd"; |
30 | break; | 30 | break; |
31 | case DIFF_STATUS_RENAMED: | 31 | case DIFF_STATUS_RENAMED: |
32 | class = "mov"; | 32 | class = "mov"; |
33 | break; | 33 | break; |
34 | case DIFF_STATUS_TYPE_CHANGED: | 34 | case DIFF_STATUS_TYPE_CHANGED: |
35 | class = "typ"; | 35 | class = "typ"; |
36 | break; | 36 | break; |
37 | case DIFF_STATUS_UNKNOWN: | 37 | case DIFF_STATUS_UNKNOWN: |
38 | class = "unk"; | 38 | class = "unk"; |
39 | break; | 39 | break; |
40 | case DIFF_STATUS_UNMERGED: | 40 | case DIFF_STATUS_UNMERGED: |
41 | class = "stg"; | 41 | class = "stg"; |
42 | break; | 42 | break; |
43 | default: | 43 | default: |
44 | die("bug: unhandled diff status %c", pair->status); | 44 | die("bug: unhandled diff status %c", pair->status); |
45 | } | 45 | } |
46 | 46 | ||
47 | html("<tr>"); | 47 | html("<tr>"); |
48 | htmlf("<td class='mode'>"); | 48 | htmlf("<td class='mode'>"); |
49 | if (is_null_sha1(pair->two->sha1)) { | 49 | if (is_null_sha1(pair->two->sha1)) { |
50 | html_filemode(pair->one->mode); | 50 | html_filemode(pair->one->mode); |
51 | } else { | 51 | } else { |
52 | html_filemode(pair->two->mode); | 52 | html_filemode(pair->two->mode); |
53 | } | 53 | } |
54 | 54 | ||
55 | if (pair->one->mode != pair->two->mode && | 55 | if (pair->one->mode != pair->two->mode && |
56 | !is_null_sha1(pair->one->sha1) && | 56 | !is_null_sha1(pair->one->sha1) && |
57 | !is_null_sha1(pair->two->sha1)) { | 57 | !is_null_sha1(pair->two->sha1)) { |
58 | html("<span class='modechange'>["); | 58 | html("<span class='modechange'>["); |
59 | html_filemode(pair->one->mode); | 59 | html_filemode(pair->one->mode); |
60 | html("]</span>"); | 60 | html("]</span>"); |
61 | } | 61 | } |
62 | htmlf("</td><td class='%s'>", class); | 62 | htmlf("</td><td class='%s'>", class); |
63 | query = fmt("id=%s&id2=%s", sha1_to_hex(pair->one->sha1), | 63 | query = fmt("id=%s&id2=%s", sha1_to_hex(pair->one->sha1), |
64 | sha1_to_hex(pair->two->sha1)); | 64 | sha1_to_hex(pair->two->sha1)); |
65 | html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), | 65 | html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), |
66 | NULL, NULL); | 66 | NULL, NULL); |
67 | if (pair->status == DIFF_STATUS_COPIED || | 67 | if (pair->status == DIFF_STATUS_COPIED || |
68 | pair->status == DIFF_STATUS_RENAMED) { | 68 | pair->status == DIFF_STATUS_RENAMED) { |
69 | html_txt(pair->two->path); | 69 | html_txt(pair->two->path); |
70 | htmlf("</a> (%s from ", pair->status == DIFF_STATUS_COPIED ? | 70 | htmlf("</a> (%s from ", pair->status == DIFF_STATUS_COPIED ? |
71 | "copied" : "renamed"); | 71 | "copied" : "renamed"); |
72 | query = fmt("id=%s", sha1_to_hex(pair->one->sha1)); | 72 | query = fmt("id=%s", sha1_to_hex(pair->one->sha1)); |
73 | html_link_open(cgit_pageurl(cgit_query_repo, "view", query), | 73 | html_link_open(cgit_pageurl(cgit_query_repo, "view", query), |
74 | NULL, NULL); | 74 | NULL, NULL); |
75 | html_txt(pair->one->path); | 75 | html_txt(pair->one->path); |
76 | html("</a>)"); | 76 | html("</a>)"); |
77 | } else { | 77 | } else { |
78 | html_txt(pair->two->path); | 78 | html_txt(pair->two->path); |
79 | html("</a>"); | 79 | html("</a>"); |
80 | } | 80 | } |
81 | html("<td>"); | 81 | html("<td>"); |
82 | 82 | ||
83 | //TODO: diffstat graph | 83 | //TODO: diffstat graph |
84 | 84 | ||
85 | html("</td></tr>\n"); | 85 | html("</td></tr>\n"); |
86 | files++; | 86 | files++; |
87 | } | 87 | } |
88 | 88 | ||
89 | void diff_format_cb(struct diff_queue_struct *q, | 89 | void diff_format_cb(struct diff_queue_struct *q, |
90 | struct diff_options *options, void *data) | 90 | struct diff_options *options, void *data) |
91 | { | 91 | { |
92 | int i; | 92 | int i; |
93 | 93 | ||
94 | for (i = 0; i < q->nr; i++) { | 94 | for (i = 0; i < q->nr; i++) { |
95 | if (q->queue[i]->status == 'U') | 95 | if (q->queue[i]->status == 'U') |
96 | continue; | 96 | continue; |
97 | print_filepair(q->queue[i]); | 97 | print_filepair(q->queue[i]); |
98 | } | 98 | } |
99 | } | 99 | } |
100 | 100 | ||
101 | void cgit_diffstat(struct commit *commit) | 101 | void cgit_diffstat(struct commit *commit) |
102 | { | 102 | { |
103 | struct diff_options opt; | 103 | struct diff_options opt; |
104 | int ret; | 104 | int ret; |
105 | 105 | ||
106 | diff_setup(&opt); | 106 | diff_setup(&opt); |
107 | opt.output_format = DIFF_FORMAT_CALLBACK; | 107 | opt.output_format = DIFF_FORMAT_CALLBACK; |
108 | opt.detect_rename = 1; | 108 | opt.detect_rename = 1; |
109 | opt.recursive = 1; | 109 | opt.recursive = 1; |
110 | opt.format_callback = diff_format_cb; | 110 | opt.format_callback = diff_format_cb; |
111 | diff_setup_done(&opt); | 111 | diff_setup_done(&opt); |
112 | 112 | ||
113 | if (commit->parents) | 113 | if (commit->parents) |
114 | ret = diff_tree_sha1(commit->parents->item->object.sha1, | 114 | ret = diff_tree_sha1(commit->parents->item->object.sha1, |
115 | commit->object.sha1, | 115 | commit->object.sha1, |
116 | "", &opt); | 116 | "", &opt); |
117 | else | 117 | else |
118 | ret = diff_root_tree_sha1(commit->object.sha1, "", &opt); | 118 | ret = diff_root_tree_sha1(commit->object.sha1, "", &opt); |
119 | 119 | ||
120 | diffcore_std(&opt); | 120 | diffcore_std(&opt); |
121 | diff_flush(&opt); | 121 | diff_flush(&opt); |
122 | } | 122 | } |
123 | 123 | ||
124 | void cgit_print_commit(const char *hex) | 124 | void cgit_print_commit(const char *hex) |
125 | { | 125 | { |
126 | struct commit *commit; | 126 | struct commit *commit; |
127 | struct commitinfo *info; | 127 | struct commitinfo *info; |
128 | struct commit_list *p; | 128 | struct commit_list *p; |
129 | unsigned char sha1[20]; | 129 | unsigned char sha1[20]; |
130 | char *query; | 130 | char *query; |
131 | char *filename; | ||
131 | 132 | ||
132 | if (get_sha1(hex, sha1)) { | 133 | if (get_sha1(hex, sha1)) { |
133 | cgit_print_error(fmt("Bad object id: %s", hex)); | 134 | cgit_print_error(fmt("Bad object id: %s", hex)); |
134 | return; | 135 | return; |
135 | } | 136 | } |
136 | commit = lookup_commit_reference(sha1); | 137 | commit = lookup_commit_reference(sha1); |
137 | if (!commit) { | 138 | if (!commit) { |
138 | cgit_print_error(fmt("Bad commit reference: %s", hex)); | 139 | cgit_print_error(fmt("Bad commit reference: %s", hex)); |
139 | return; | 140 | return; |
140 | } | 141 | } |
141 | info = cgit_parse_commit(commit); | 142 | info = cgit_parse_commit(commit); |
142 | 143 | ||
143 | html("<table class='commit-info'>\n"); | 144 | html("<table class='commit-info'>\n"); |
144 | html("<tr><th>author</th><td>"); | 145 | html("<tr><th>author</th><td>"); |
145 | html_txt(info->author); | 146 | html_txt(info->author); |
146 | html(" "); | 147 | html(" "); |
147 | html_txt(info->author_email); | 148 | html_txt(info->author_email); |
148 | html("</td><td class='right'>"); | 149 | html("</td><td class='right'>"); |
149 | cgit_print_date(info->author_date); | 150 | cgit_print_date(info->author_date); |
150 | html("</td></tr>\n"); | 151 | html("</td></tr>\n"); |
151 | html("<tr><th>committer</th><td>"); | 152 | html("<tr><th>committer</th><td>"); |
152 | html_txt(info->committer); | 153 | html_txt(info->committer); |
153 | html(" "); | 154 | html(" "); |
154 | html_txt(info->committer_email); | 155 | html_txt(info->committer_email); |
155 | html("</td><td class='right'>"); | 156 | html("</td><td class='right'>"); |
156 | cgit_print_date(info->committer_date); | 157 | cgit_print_date(info->committer_date); |
157 | html("</td></tr>\n"); | 158 | html("</td></tr>\n"); |
158 | html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='"); | 159 | html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='"); |
159 | query = fmt("id=%s", sha1_to_hex(commit->tree->object.sha1)); | 160 | query = fmt("id=%s", sha1_to_hex(commit->tree->object.sha1)); |
160 | html_attr(cgit_pageurl(cgit_query_repo, "tree", query)); | 161 | html_attr(cgit_pageurl(cgit_query_repo, "tree", query)); |
161 | htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1)); | 162 | htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1)); |
162 | for (p = commit->parents; p ; p = p->next) { | 163 | for (p = commit->parents; p ; p = p->next) { |
163 | html("<tr><th>parent</th>" | 164 | html("<tr><th>parent</th>" |
164 | "<td colspan='2' class='sha1'>" | 165 | "<td colspan='2' class='sha1'>" |
165 | "<a href='"); | 166 | "<a href='"); |
166 | query = fmt("id=%s", sha1_to_hex(p->item->object.sha1)); | 167 | query = fmt("id=%s", sha1_to_hex(p->item->object.sha1)); |
167 | html_attr(cgit_pageurl(cgit_query_repo, "commit", query)); | 168 | html_attr(cgit_pageurl(cgit_query_repo, "commit", query)); |
168 | htmlf("'>%s</a></td></tr>\n", | 169 | htmlf("'>%s</a></td></tr>\n", |
169 | sha1_to_hex(p->item->object.sha1)); | 170 | sha1_to_hex(p->item->object.sha1)); |
170 | } | 171 | } |
172 | htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); | ||
173 | filename = fmt("%s-%s.zip", cgit_query_repo, hex); | ||
174 | html_attr(cgit_pageurl(cgit_query_repo, "snapshot", | ||
175 | fmt("id=%s&name=%s", hex, filename))); | ||
176 | htmlf("'>%s</a></td></tr>", filename); | ||
177 | |||
171 | html("</table>\n"); | 178 | html("</table>\n"); |
172 | html("<div class='commit-subject'>"); | 179 | html("<div class='commit-subject'>"); |
173 | html_txt(info->subject); | 180 | html_txt(info->subject); |
174 | html("</div>"); | 181 | html("</div>"); |
175 | html("<div class='commit-msg'>"); | 182 | html("<div class='commit-msg'>"); |
176 | html_txt(info->msg); | 183 | html_txt(info->msg); |
177 | html("</div>"); | 184 | html("</div>"); |
178 | html("<table class='diffstat'>"); | 185 | html("<table class='diffstat'>"); |
179 | html("<tr><th colspan='3'>Affected files</tr>\n"); | 186 | html("<tr><th colspan='3'>Affected files</tr>\n"); |
180 | cgit_diffstat(commit); | 187 | cgit_diffstat(commit); |
181 | htmlf("<tr><td colspan='3' class='summary'>" | 188 | htmlf("<tr><td colspan='3' class='summary'>" |
182 | "%d file%s changed</td></tr>\n", files, files > 1 ? "s" : ""); | 189 | "%d file%s changed</td></tr>\n", files, files > 1 ? "s" : ""); |
183 | html("</table>"); | 190 | html("</table>"); |
184 | cgit_free_commitinfo(info); | 191 | cgit_free_commitinfo(info); |
185 | } | 192 | } |
diff --git a/ui-shared.c b/ui-shared.c index 3322561..172499c 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -1,146 +1,157 @@ | |||
1 | /* ui-shared.c: common web output functions | 1 | /* ui-shared.c: common web output functions |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Lars Hjemli | 3 | * Copyright (C) 2006 Lars Hjemli |
4 | * | 4 | * |
5 | * Licensed under GNU General Public License v2 | 5 | * Licensed under GNU General Public License v2 |
6 | * (see COPYING for full license text) | 6 | * (see COPYING for full license text) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | 10 | ||
11 | const char cgit_doctype[] = | 11 | const char cgit_doctype[] = |
12 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" | 12 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" |
13 | " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; | 13 | " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"; |
14 | 14 | ||
15 | static char *http_date(time_t t) | 15 | static char *http_date(time_t t) |
16 | { | 16 | { |
17 | static char day[][4] = | 17 | static char day[][4] = |
18 | {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; | 18 | {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; |
19 | static char month[][4] = | 19 | static char month[][4] = |
20 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", | 20 | {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
21 | "Jul", "Aug", "Sep", "Oct", "Now", "Dec"}; | 21 | "Jul", "Aug", "Sep", "Oct", "Now", "Dec"}; |
22 | struct tm *tm = gmtime(&t); | 22 | struct tm *tm = gmtime(&t); |
23 | return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], | 23 | return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm->tm_wday], |
24 | tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year, | 24 | tm->tm_mday, month[tm->tm_mon], 1900+tm->tm_year, |
25 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 25 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
26 | } | 26 | } |
27 | 27 | ||
28 | static long ttl_seconds(long ttl) | 28 | static long ttl_seconds(long ttl) |
29 | { | 29 | { |
30 | if (ttl<0) | 30 | if (ttl<0) |
31 | return 60 * 60 * 24 * 365; | 31 | return 60 * 60 * 24 * 365; |
32 | else | 32 | else |
33 | return ttl * 60; | 33 | return ttl * 60; |
34 | } | 34 | } |
35 | 35 | ||
36 | void cgit_print_error(char *msg) | 36 | void cgit_print_error(char *msg) |
37 | { | 37 | { |
38 | html("<div class='error'>"); | 38 | html("<div class='error'>"); |
39 | html_txt(msg); | 39 | html_txt(msg); |
40 | html("</div>\n"); | 40 | html("</div>\n"); |
41 | } | 41 | } |
42 | 42 | ||
43 | char *cgit_repourl(const char *reponame) | 43 | char *cgit_repourl(const char *reponame) |
44 | { | 44 | { |
45 | if (cgit_virtual_root) { | 45 | if (cgit_virtual_root) { |
46 | return fmt("%s/%s/", cgit_virtual_root, reponame); | 46 | return fmt("%s/%s/", cgit_virtual_root, reponame); |
47 | } else { | 47 | } else { |
48 | return fmt("?r=%s", reponame); | 48 | return fmt("?r=%s", reponame); |
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | char *cgit_pageurl(const char *reponame, const char *pagename, | 52 | char *cgit_pageurl(const char *reponame, const char *pagename, |
53 | const char *query) | 53 | const char *query) |
54 | { | 54 | { |
55 | if (cgit_virtual_root) { | 55 | if (cgit_virtual_root) { |
56 | return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, | 56 | return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, |
57 | pagename, query); | 57 | pagename, query); |
58 | } else { | 58 | } else { |
59 | return fmt("?r=%s&p=%s&%s", reponame, pagename, query); | 59 | return fmt("?r=%s&p=%s&%s", reponame, pagename, query); |
60 | } | 60 | } |
61 | } | 61 | } |
62 | 62 | ||
63 | char *cgit_currurl() | 63 | char *cgit_currurl() |
64 | { | 64 | { |
65 | if (!cgit_virtual_root) | 65 | if (!cgit_virtual_root) |
66 | return "./cgit.cgi"; | 66 | return "./cgit.cgi"; |
67 | else if (cgit_query_page) | 67 | else if (cgit_query_page) |
68 | return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); | 68 | return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); |
69 | else if (cgit_query_repo) | 69 | else if (cgit_query_repo) |
70 | return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); | 70 | return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); |
71 | else | 71 | else |
72 | return fmt("%s/", cgit_virtual_root); | 72 | return fmt("%s/", cgit_virtual_root); |
73 | } | 73 | } |
74 | 74 | ||
75 | 75 | ||
76 | void cgit_print_date(unsigned long secs) | 76 | void cgit_print_date(unsigned long secs) |
77 | { | 77 | { |
78 | char buf[32]; | 78 | char buf[32]; |
79 | struct tm *time; | 79 | struct tm *time; |
80 | 80 | ||
81 | time = gmtime(&secs); | 81 | time = gmtime(&secs); |
82 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time); | 82 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", time); |
83 | html_txt(buf); | 83 | html_txt(buf); |
84 | 84 | ||
85 | } | 85 | } |
86 | 86 | ||
87 | void cgit_print_docstart(char *title, struct cacheitem *item) | 87 | void cgit_print_docstart(char *title, struct cacheitem *item) |
88 | { | 88 | { |
89 | html("Content-Type: text/html; charset=utf-8\n"); | 89 | html("Content-Type: text/html; charset=utf-8\n"); |
90 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); | 90 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); |
91 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + | 91 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + |
92 | ttl_seconds(item->ttl))); | 92 | ttl_seconds(item->ttl))); |
93 | html("\n"); | 93 | html("\n"); |
94 | html(cgit_doctype); | 94 | html(cgit_doctype); |
95 | html("<html>\n"); | 95 | html("<html>\n"); |
96 | html("<head>\n"); | 96 | html("<head>\n"); |
97 | html("<title>"); | 97 | html("<title>"); |
98 | html_txt(title); | 98 | html_txt(title); |
99 | html("</title>\n"); | 99 | html("</title>\n"); |
100 | htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version); | 100 | htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version); |
101 | html("<link rel='stylesheet' type='text/css' href='"); | 101 | html("<link rel='stylesheet' type='text/css' href='"); |
102 | html_attr(cgit_css); | 102 | html_attr(cgit_css); |
103 | html("'/>\n"); | 103 | html("'/>\n"); |
104 | html("</head>\n"); | 104 | html("</head>\n"); |
105 | html("<body>\n"); | 105 | html("<body>\n"); |
106 | } | 106 | } |
107 | 107 | ||
108 | void cgit_print_docend() | 108 | void cgit_print_docend() |
109 | { | 109 | { |
110 | html("</td></tr></table>"); | 110 | html("</td></tr></table>"); |
111 | html("</body>\n</html>\n"); | 111 | html("</body>\n</html>\n"); |
112 | } | 112 | } |
113 | 113 | ||
114 | void cgit_print_pageheader(char *title, int show_search) | 114 | void cgit_print_pageheader(char *title, int show_search) |
115 | { | 115 | { |
116 | html("<table id='layout'><tr><td id='header'>"); | 116 | html("<table id='layout'><tr><td id='header'>"); |
117 | htmlf("<a href='%s'>", cgit_logo_link); | 117 | htmlf("<a href='%s'>", cgit_logo_link); |
118 | htmlf("<img id='logo' src='%s'/>\n", cgit_logo); | 118 | htmlf("<img id='logo' src='%s'/>\n", cgit_logo); |
119 | htmlf("</a>"); | 119 | htmlf("</a>"); |
120 | if (show_search) { | 120 | if (show_search) { |
121 | html("<form method='get' href='"); | 121 | html("<form method='get' href='"); |
122 | html_attr(cgit_currurl()); | 122 | html_attr(cgit_currurl()); |
123 | html("'>"); | 123 | html("'>"); |
124 | if (!cgit_virtual_root) { | 124 | if (!cgit_virtual_root) { |
125 | if (cgit_query_repo) | 125 | if (cgit_query_repo) |
126 | html_hidden("r", cgit_query_repo); | 126 | html_hidden("r", cgit_query_repo); |
127 | if (cgit_query_page) | 127 | if (cgit_query_page) |
128 | html_hidden("p", cgit_query_page); | 128 | html_hidden("p", cgit_query_page); |
129 | } | 129 | } |
130 | if (cgit_query_head) | 130 | if (cgit_query_head) |
131 | html_hidden("h", cgit_query_head); | 131 | html_hidden("h", cgit_query_head); |
132 | if (cgit_query_sha1) | 132 | if (cgit_query_sha1) |
133 | html_hidden("id", cgit_query_sha1); | 133 | html_hidden("id", cgit_query_sha1); |
134 | if (cgit_query_sha2) | 134 | if (cgit_query_sha2) |
135 | html_hidden("id2", cgit_query_sha2); | 135 | html_hidden("id2", cgit_query_sha2); |
136 | html("<input type='text' name='q' value='"); | 136 | html("<input type='text' name='q' value='"); |
137 | html_attr(cgit_query_search); | 137 | html_attr(cgit_query_search); |
138 | html("'/></form>"); | 138 | html("'/></form>"); |
139 | } | 139 | } |
140 | if (cgit_query_repo) | 140 | if (cgit_query_repo) |
141 | htmlf("<a href='%s'>", cgit_repourl(cgit_query_repo)); | 141 | htmlf("<a href='%s'>", cgit_repourl(cgit_query_repo)); |
142 | html_txt(title); | 142 | html_txt(title); |
143 | if (cgit_query_repo) | 143 | if (cgit_query_repo) |
144 | html("</a>"); | 144 | html("</a>"); |
145 | html("</td></tr><tr><td id='content'>"); | 145 | html("</td></tr><tr><td id='content'>"); |
146 | } | 146 | } |
147 | |||
148 | void cgit_print_snapshot_start(const char *mimetype, const char *filename, | ||
149 | struct cacheitem *item) | ||
150 | { | ||
151 | htmlf("Content-Type: %s\n", mimetype); | ||
152 | htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); | ||
153 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); | ||
154 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + | ||
155 | ttl_seconds(item->ttl))); | ||
156 | html("\n"); | ||
157 | } | ||
diff --git a/ui-snapshot.c b/ui-snapshot.c new file mode 100644 index 0000000..2257d6b --- a/dev/null +++ b/ui-snapshot.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* ui-snapshot.c: generate snapshot of a commit | ||
2 | * | ||
3 | * Copyright (C) 2006 Lars Hjemli | ||
4 | * | ||
5 | * Licensed under GNU General Public License v2 | ||
6 | * (see COPYING for full license text) | ||
7 | */ | ||
8 | |||
9 | #include "cgit.h" | ||
10 | |||
11 | static void cgit_print_zip(struct cacheitem *item, const char *hex, | ||
12 | const char *prefix, const char *filename) | ||
13 | { | ||
14 | struct archiver_args args; | ||
15 | struct commit *commit; | ||
16 | unsigned char sha1[20]; | ||
17 | |||
18 | if (get_sha1(hex, sha1)) { | ||
19 | cgit_print_error(fmt("Bad object id: %s", hex)); | ||
20 | return; | ||
21 | } | ||
22 | commit = lookup_commit_reference(sha1); | ||
23 | |||
24 | if (!commit) { | ||
25 | cgit_print_error(fmt("Not a commit reference: %s", hex)); | ||
26 | return; | ||
27 | } | ||
28 | |||
29 | memset(&args, 0, sizeof(args)); | ||
30 | args.base = fmt("%s/", prefix); | ||
31 | args.tree = commit->tree; | ||
32 | |||
33 | cgit_print_snapshot_start("application/x-zip", filename, item); | ||
34 | write_zip_archive(&args); | ||
35 | } | ||
36 | |||
37 | |||
38 | void cgit_print_snapshot(struct cacheitem *item, const char *hex, | ||
39 | const char *format, const char *prefix, | ||
40 | const char *filename) | ||
41 | { | ||
42 | if (!strcmp(format, "zip")) | ||
43 | cgit_print_zip(item, hex, prefix, filename); | ||
44 | else | ||
45 | cgit_print_error(fmt("Unsupported snapshot format: %s", | ||
46 | format)); | ||
47 | } | ||