author | Lars Hjemli <hjemli@gmail.com> | 2009-07-31 14:55:27 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2009-07-31 15:41:21 (UTC) |
commit | 46b7abed99e957008c01c02cf612aa526ba92f04 (patch) (unidiff) | |
tree | 2cdbfe5281c2ffa645def488d53db0a8b82842f4 | |
parent | 18dfbdc099c1398016427b6fa7f1a1facb363998 (diff) | |
download | cgit-46b7abed99e957008c01c02cf612aa526ba92f04.zip cgit-46b7abed99e957008c01c02cf612aa526ba92f04.tar.gz cgit-46b7abed99e957008c01c02cf612aa526ba92f04.tar.bz2 |
ui-tree: add support for source-filter option
This new option is used to specify an external command which will be
executed when displaying blob content in the tree view. Blob content
will be written to STDIN of the filter and STDOUT from the filter
will be included verbatim in the html output from cgit. The file name
of the blob will be passed as the only argument to the filter command.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 2 | ||||
-rw-r--r-- | cgit.h | 1 | ||||
-rw-r--r-- | cgitrc.5.txt | 8 | ||||
-rw-r--r-- | ui-tree.c | 18 |
4 files changed, 25 insertions, 4 deletions
@@ -71,64 +71,66 @@ void config_cb(const char *name, const char *value) | |||
71 | else if (!strcmp(name, "snapshots")) | 71 | else if (!strcmp(name, "snapshots")) |
72 | ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); | 72 | ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); |
73 | else if (!strcmp(name, "enable-index-links")) | 73 | else if (!strcmp(name, "enable-index-links")) |
74 | ctx.cfg.enable_index_links = atoi(value); | 74 | ctx.cfg.enable_index_links = atoi(value); |
75 | else if (!strcmp(name, "enable-log-filecount")) | 75 | else if (!strcmp(name, "enable-log-filecount")) |
76 | ctx.cfg.enable_log_filecount = atoi(value); | 76 | ctx.cfg.enable_log_filecount = atoi(value); |
77 | else if (!strcmp(name, "enable-log-linecount")) | 77 | else if (!strcmp(name, "enable-log-linecount")) |
78 | ctx.cfg.enable_log_linecount = atoi(value); | 78 | ctx.cfg.enable_log_linecount = atoi(value); |
79 | else if (!strcmp(name, "max-stats")) | 79 | else if (!strcmp(name, "max-stats")) |
80 | ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); | 80 | ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); |
81 | else if (!strcmp(name, "cache-size")) | 81 | else if (!strcmp(name, "cache-size")) |
82 | ctx.cfg.cache_size = atoi(value); | 82 | ctx.cfg.cache_size = atoi(value); |
83 | else if (!strcmp(name, "cache-root")) | 83 | else if (!strcmp(name, "cache-root")) |
84 | ctx.cfg.cache_root = xstrdup(value); | 84 | ctx.cfg.cache_root = xstrdup(value); |
85 | else if (!strcmp(name, "cache-root-ttl")) | 85 | else if (!strcmp(name, "cache-root-ttl")) |
86 | ctx.cfg.cache_root_ttl = atoi(value); | 86 | ctx.cfg.cache_root_ttl = atoi(value); |
87 | else if (!strcmp(name, "cache-repo-ttl")) | 87 | else if (!strcmp(name, "cache-repo-ttl")) |
88 | ctx.cfg.cache_repo_ttl = atoi(value); | 88 | ctx.cfg.cache_repo_ttl = atoi(value); |
89 | else if (!strcmp(name, "cache-static-ttl")) | 89 | else if (!strcmp(name, "cache-static-ttl")) |
90 | ctx.cfg.cache_static_ttl = atoi(value); | 90 | ctx.cfg.cache_static_ttl = atoi(value); |
91 | else if (!strcmp(name, "cache-dynamic-ttl")) | 91 | else if (!strcmp(name, "cache-dynamic-ttl")) |
92 | ctx.cfg.cache_dynamic_ttl = atoi(value); | 92 | ctx.cfg.cache_dynamic_ttl = atoi(value); |
93 | else if (!strcmp(name, "embedded")) | 93 | else if (!strcmp(name, "embedded")) |
94 | ctx.cfg.embedded = atoi(value); | 94 | ctx.cfg.embedded = atoi(value); |
95 | else if (!strcmp(name, "max-message-length")) | 95 | else if (!strcmp(name, "max-message-length")) |
96 | ctx.cfg.max_msg_len = atoi(value); | 96 | ctx.cfg.max_msg_len = atoi(value); |
97 | else if (!strcmp(name, "max-repodesc-length")) | 97 | else if (!strcmp(name, "max-repodesc-length")) |
98 | ctx.cfg.max_repodesc_len = atoi(value); | 98 | ctx.cfg.max_repodesc_len = atoi(value); |
99 | else if (!strcmp(name, "max-repo-count")) | 99 | else if (!strcmp(name, "max-repo-count")) |
100 | ctx.cfg.max_repo_count = atoi(value); | 100 | ctx.cfg.max_repo_count = atoi(value); |
101 | else if (!strcmp(name, "max-commit-count")) | 101 | else if (!strcmp(name, "max-commit-count")) |
102 | ctx.cfg.max_commit_count = atoi(value); | 102 | ctx.cfg.max_commit_count = atoi(value); |
103 | else if (!strcmp(name, "source-filter")) | ||
104 | ctx.cfg.source_filter = new_filter(value, 1); | ||
103 | else if (!strcmp(name, "summary-log")) | 105 | else if (!strcmp(name, "summary-log")) |
104 | ctx.cfg.summary_log = atoi(value); | 106 | ctx.cfg.summary_log = atoi(value); |
105 | else if (!strcmp(name, "summary-branches")) | 107 | else if (!strcmp(name, "summary-branches")) |
106 | ctx.cfg.summary_branches = atoi(value); | 108 | ctx.cfg.summary_branches = atoi(value); |
107 | else if (!strcmp(name, "summary-tags")) | 109 | else if (!strcmp(name, "summary-tags")) |
108 | ctx.cfg.summary_tags = atoi(value); | 110 | ctx.cfg.summary_tags = atoi(value); |
109 | else if (!strcmp(name, "agefile")) | 111 | else if (!strcmp(name, "agefile")) |
110 | ctx.cfg.agefile = xstrdup(value); | 112 | ctx.cfg.agefile = xstrdup(value); |
111 | else if (!strcmp(name, "renamelimit")) | 113 | else if (!strcmp(name, "renamelimit")) |
112 | ctx.cfg.renamelimit = atoi(value); | 114 | ctx.cfg.renamelimit = atoi(value); |
113 | else if (!strcmp(name, "robots")) | 115 | else if (!strcmp(name, "robots")) |
114 | ctx.cfg.robots = xstrdup(value); | 116 | ctx.cfg.robots = xstrdup(value); |
115 | else if (!strcmp(name, "clone-prefix")) | 117 | else if (!strcmp(name, "clone-prefix")) |
116 | ctx.cfg.clone_prefix = xstrdup(value); | 118 | ctx.cfg.clone_prefix = xstrdup(value); |
117 | else if (!strcmp(name, "local-time")) | 119 | else if (!strcmp(name, "local-time")) |
118 | ctx.cfg.local_time = atoi(value); | 120 | ctx.cfg.local_time = atoi(value); |
119 | else if (!strcmp(name, "repo.group")) | 121 | else if (!strcmp(name, "repo.group")) |
120 | ctx.cfg.repo_group = xstrdup(value); | 122 | ctx.cfg.repo_group = xstrdup(value); |
121 | else if (!strcmp(name, "repo.url")) | 123 | else if (!strcmp(name, "repo.url")) |
122 | ctx.repo = cgit_add_repo(value); | 124 | ctx.repo = cgit_add_repo(value); |
123 | else if (!strcmp(name, "repo.name")) | 125 | else if (!strcmp(name, "repo.name")) |
124 | ctx.repo->name = xstrdup(value); | 126 | ctx.repo->name = xstrdup(value); |
125 | else if (ctx.repo && !strcmp(name, "repo.path")) | 127 | else if (ctx.repo && !strcmp(name, "repo.path")) |
126 | ctx.repo->path = trim_end(value, '/'); | 128 | ctx.repo->path = trim_end(value, '/'); |
127 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) | 129 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) |
128 | ctx.repo->clone_url = xstrdup(value); | 130 | ctx.repo->clone_url = xstrdup(value); |
129 | else if (ctx.repo && !strcmp(name, "repo.desc")) | 131 | else if (ctx.repo && !strcmp(name, "repo.desc")) |
130 | ctx.repo->desc = xstrdup(value); | 132 | ctx.repo->desc = xstrdup(value); |
131 | else if (ctx.repo && !strcmp(name, "repo.owner")) | 133 | else if (ctx.repo && !strcmp(name, "repo.owner")) |
132 | ctx.repo->owner = xstrdup(value); | 134 | ctx.repo->owner = xstrdup(value); |
133 | else if (ctx.repo && !strcmp(name, "repo.defbranch")) | 135 | else if (ctx.repo && !strcmp(name, "repo.defbranch")) |
134 | ctx.repo->defbranch = xstrdup(value); | 136 | ctx.repo->defbranch = xstrdup(value); |
@@ -154,64 +154,65 @@ struct cgit_config { | |||
154 | char *module_link; | 154 | char *module_link; |
155 | char *repo_group; | 155 | char *repo_group; |
156 | char *robots; | 156 | char *robots; |
157 | char *root_title; | 157 | char *root_title; |
158 | char *root_desc; | 158 | char *root_desc; |
159 | char *root_readme; | 159 | char *root_readme; |
160 | char *script_name; | 160 | char *script_name; |
161 | char *virtual_root; | 161 | char *virtual_root; |
162 | int cache_size; | 162 | int cache_size; |
163 | int cache_dynamic_ttl; | 163 | int cache_dynamic_ttl; |
164 | int cache_max_create_time; | 164 | int cache_max_create_time; |
165 | int cache_repo_ttl; | 165 | int cache_repo_ttl; |
166 | int cache_root_ttl; | 166 | int cache_root_ttl; |
167 | int cache_static_ttl; | 167 | int cache_static_ttl; |
168 | int embedded; | 168 | int embedded; |
169 | int enable_index_links; | 169 | int enable_index_links; |
170 | int enable_log_filecount; | 170 | int enable_log_filecount; |
171 | int enable_log_linecount; | 171 | int enable_log_linecount; |
172 | int local_time; | 172 | int local_time; |
173 | int max_repo_count; | 173 | int max_repo_count; |
174 | int max_commit_count; | 174 | int max_commit_count; |
175 | int max_lock_attempts; | 175 | int max_lock_attempts; |
176 | int max_msg_len; | 176 | int max_msg_len; |
177 | int max_repodesc_len; | 177 | int max_repodesc_len; |
178 | int max_stats; | 178 | int max_stats; |
179 | int nocache; | 179 | int nocache; |
180 | int noheader; | 180 | int noheader; |
181 | int renamelimit; | 181 | int renamelimit; |
182 | int snapshots; | 182 | int snapshots; |
183 | int summary_branches; | 183 | int summary_branches; |
184 | int summary_log; | 184 | int summary_log; |
185 | int summary_tags; | 185 | int summary_tags; |
186 | struct cgit_filter *source_filter; | ||
186 | }; | 187 | }; |
187 | 188 | ||
188 | struct cgit_page { | 189 | struct cgit_page { |
189 | time_t modified; | 190 | time_t modified; |
190 | time_t expires; | 191 | time_t expires; |
191 | size_t size; | 192 | size_t size; |
192 | char *mimetype; | 193 | char *mimetype; |
193 | char *charset; | 194 | char *charset; |
194 | char *filename; | 195 | char *filename; |
195 | char *etag; | 196 | char *etag; |
196 | char *title; | 197 | char *title; |
197 | int status; | 198 | int status; |
198 | char *statusmsg; | 199 | char *statusmsg; |
199 | }; | 200 | }; |
200 | 201 | ||
201 | struct cgit_context { | 202 | struct cgit_context { |
202 | struct cgit_query qry; | 203 | struct cgit_query qry; |
203 | struct cgit_config cfg; | 204 | struct cgit_config cfg; |
204 | struct cgit_repo *repo; | 205 | struct cgit_repo *repo; |
205 | struct cgit_page page; | 206 | struct cgit_page page; |
206 | }; | 207 | }; |
207 | 208 | ||
208 | struct cgit_snapshot_format { | 209 | struct cgit_snapshot_format { |
209 | const char *suffix; | 210 | const char *suffix; |
210 | const char *mimetype; | 211 | const char *mimetype; |
211 | write_archive_fn_t write_func; | 212 | write_archive_fn_t write_func; |
212 | int bit; | 213 | int bit; |
213 | }; | 214 | }; |
214 | 215 | ||
215 | extern const char *cgit_version; | 216 | extern const char *cgit_version; |
216 | 217 | ||
217 | extern struct cgit_repolist cgit_repolist; | 218 | extern struct cgit_repolist cgit_repolist; |
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index a207fe0..d420ad4 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt | |||
@@ -169,64 +169,72 @@ renamelimit:: | |||
169 | 169 | ||
170 | repo.group:: | 170 | repo.group:: |
171 | A value for the current repository group, which all repositories | 171 | A value for the current repository group, which all repositories |
172 | specified after this setting will inherit. Default value: none. | 172 | specified after this setting will inherit. Default value: none. |
173 | 173 | ||
174 | robots:: | 174 | robots:: |
175 | Text used as content for the "robots" meta-tag. Default value: | 175 | Text used as content for the "robots" meta-tag. Default value: |
176 | "index, nofollow". | 176 | "index, nofollow". |
177 | 177 | ||
178 | root-desc:: | 178 | root-desc:: |
179 | Text printed below the heading on the repository index page. Default | 179 | Text printed below the heading on the repository index page. Default |
180 | value: "a fast webinterface for the git dscm". | 180 | value: "a fast webinterface for the git dscm". |
181 | 181 | ||
182 | root-readme:: | 182 | root-readme:: |
183 | The content of the file specified with this option will be included | 183 | The content of the file specified with this option will be included |
184 | verbatim below the "about" link on the repository index page. Default | 184 | verbatim below the "about" link on the repository index page. Default |
185 | value: none. | 185 | value: none. |
186 | 186 | ||
187 | root-title:: | 187 | root-title:: |
188 | Text printed as heading on the repository index page. Default value: | 188 | Text printed as heading on the repository index page. Default value: |
189 | "Git Repository Browser". | 189 | "Git Repository Browser". |
190 | 190 | ||
191 | snapshots:: | 191 | snapshots:: |
192 | Text which specifies the default (and allowed) set of snapshot formats | 192 | Text which specifies the default (and allowed) set of snapshot formats |
193 | supported by cgit. The value is a space-separated list of zero or more | 193 | supported by cgit. The value is a space-separated list of zero or more |
194 | of the following values: | 194 | of the following values: |
195 | "tar" uncompressed tar-file | 195 | "tar" uncompressed tar-file |
196 | "tar.gz"gzip-compressed tar-file | 196 | "tar.gz"gzip-compressed tar-file |
197 | "tar.bz2"bzip-compressed tar-file | 197 | "tar.bz2"bzip-compressed tar-file |
198 | "zip" zip-file | 198 | "zip" zip-file |
199 | Default value: none. | 199 | Default value: none. |
200 | 200 | ||
201 | source-filter:: | ||
202 | Specifies a command which will be invoked to format plaintext blobs | ||
203 | in the tree view. The command will get the blob content on its STDIN | ||
204 | and the name of the blob as its only command line argument. The STDOUT | ||
205 | from the command will be included verbatim as the blob contents, i.e. | ||
206 | this can be used to implement e.g. syntax highlighting. Default value: | ||
207 | none. | ||
208 | |||
201 | summary-branches:: | 209 | summary-branches:: |
202 | Specifies the number of branches to display in the repository "summary" | 210 | Specifies the number of branches to display in the repository "summary" |
203 | view. Default value: "10". | 211 | view. Default value: "10". |
204 | 212 | ||
205 | summary-log:: | 213 | summary-log:: |
206 | Specifies the number of log entries to display in the repository | 214 | Specifies the number of log entries to display in the repository |
207 | "summary" view. Default value: "10". | 215 | "summary" view. Default value: "10". |
208 | 216 | ||
209 | summary-tags:: | 217 | summary-tags:: |
210 | Specifies the number of tags to display in the repository "summary" | 218 | Specifies the number of tags to display in the repository "summary" |
211 | view. Default value: "10". | 219 | view. Default value: "10". |
212 | 220 | ||
213 | virtual-root:: | 221 | virtual-root:: |
214 | Url which, if specified, will be used as root for all cgit links. It | 222 | Url which, if specified, will be used as root for all cgit links. It |
215 | will also cause cgit to generate 'virtual urls', i.e. urls like | 223 | will also cause cgit to generate 'virtual urls', i.e. urls like |
216 | '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default | 224 | '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default |
217 | value: none. | 225 | value: none. |
218 | NOTE: cgit has recently learned how to use PATH_INFO to achieve the | 226 | NOTE: cgit has recently learned how to use PATH_INFO to achieve the |
219 | same kind of virtual urls, so this option will probably be deprecated. | 227 | same kind of virtual urls, so this option will probably be deprecated. |
220 | 228 | ||
221 | REPOSITORY SETTINGS | 229 | REPOSITORY SETTINGS |
222 | ------------------- | 230 | ------------------- |
223 | repo.clone-url:: | 231 | repo.clone-url:: |
224 | A list of space-separated urls which can be used to clone this repo. | 232 | A list of space-separated urls which can be used to clone this repo. |
225 | Default value: none. | 233 | Default value: none. |
226 | 234 | ||
227 | repo.defbranch:: | 235 | repo.defbranch:: |
228 | The name of the default branch for this repository. If no such branch | 236 | The name of the default branch for this repository. If no such branch |
229 | exists in the repository, the first branch name (when sorted) is used | 237 | exists in the repository, the first branch name (when sorted) is used |
230 | as default instead. Default value: "master". | 238 | as default instead. Default value: "master". |
231 | 239 | ||
232 | repo.desc:: | 240 | repo.desc:: |
@@ -1,128 +1,138 @@ | |||
1 | /* ui-tree.c: functions for tree output | 1 | /* ui-tree.c: functions for tree output |
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 <ctype.h> | 9 | #include <ctype.h> |
10 | #include "cgit.h" | 10 | #include "cgit.h" |
11 | #include "html.h" | 11 | #include "html.h" |
12 | #include "ui-shared.h" | 12 | #include "ui-shared.h" |
13 | 13 | ||
14 | char *curr_rev; | 14 | char *curr_rev; |
15 | char *match_path; | 15 | char *match_path; |
16 | int header = 0; | 16 | int header = 0; |
17 | 17 | ||
18 | static void print_text_buffer(char *buf, unsigned long size) | 18 | static void print_text_buffer(const char *name, char *buf, unsigned long size) |
19 | { | 19 | { |
20 | unsigned long lineno, idx; | 20 | unsigned long lineno, idx; |
21 | const char *numberfmt = | 21 | const char *numberfmt = |
22 | "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n"; | 22 | "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n"; |
23 | 23 | ||
24 | html("<table summary='blob content' class='blob'>\n"); | 24 | html("<table summary='blob content' class='blob'>\n"); |
25 | if (ctx.cfg.source_filter) { | ||
26 | html("<tr><td class='lines'><pre><code>"); | ||
27 | ctx.cfg.source_filter->argv[1] = xstrdup(name); | ||
28 | cgit_open_filter(ctx.cfg.source_filter); | ||
29 | write(STDOUT_FILENO, buf, size); | ||
30 | cgit_close_filter(ctx.cfg.source_filter); | ||
31 | html("</code></pre></td></tr></table>\n"); | ||
32 | return; | ||
33 | } | ||
34 | |||
25 | html("<tr><td class='linenumbers'><pre>"); | 35 | html("<tr><td class='linenumbers'><pre>"); |
26 | idx = 0; | 36 | idx = 0; |
27 | lineno = 0; | 37 | lineno = 0; |
28 | 38 | ||
29 | if (size) { | 39 | if (size) { |
30 | htmlf(numberfmt, ++lineno); | 40 | htmlf(numberfmt, ++lineno); |
31 | while(idx < size - 1) { // skip absolute last newline | 41 | while(idx < size - 1) { // skip absolute last newline |
32 | if (buf[idx] == '\n') | 42 | if (buf[idx] == '\n') |
33 | htmlf(numberfmt, ++lineno); | 43 | htmlf(numberfmt, ++lineno); |
34 | idx++; | 44 | idx++; |
35 | } | 45 | } |
36 | } | 46 | } |
37 | html("</pre></td>\n"); | 47 | html("</pre></td>\n"); |
38 | html("<td class='lines'><pre><code>"); | 48 | html("<td class='lines'><pre><code>"); |
39 | html_txt(buf); | 49 | html_txt(buf); |
40 | html("</code></pre></td></tr></table>\n"); | 50 | html("</code></pre></td></tr></table>\n"); |
41 | } | 51 | } |
42 | 52 | ||
43 | #define ROWLEN 32 | 53 | #define ROWLEN 32 |
44 | 54 | ||
45 | static void print_binary_buffer(char *buf, unsigned long size) | 55 | static void print_binary_buffer(char *buf, unsigned long size) |
46 | { | 56 | { |
47 | unsigned long ofs, idx; | 57 | unsigned long ofs, idx; |
48 | static char ascii[ROWLEN + 1]; | 58 | static char ascii[ROWLEN + 1]; |
49 | 59 | ||
50 | html("<table summary='blob content' class='bin-blob'>\n"); | 60 | html("<table summary='blob content' class='bin-blob'>\n"); |
51 | html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); | 61 | html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>"); |
52 | for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { | 62 | for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { |
53 | htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); | 63 | htmlf("<tr><td class='right'>%04x</td><td class='hex'>", ofs); |
54 | for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) | 64 | for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) |
55 | htmlf("%*s%02x", | 65 | htmlf("%*s%02x", |
56 | idx == 16 ? 4 : 1, "", | 66 | idx == 16 ? 4 : 1, "", |
57 | buf[idx] & 0xff); | 67 | buf[idx] & 0xff); |
58 | html(" </td><td class='hex'>"); | 68 | html(" </td><td class='hex'>"); |
59 | for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) | 69 | for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) |
60 | ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; | 70 | ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; |
61 | ascii[idx] = '\0'; | 71 | ascii[idx] = '\0'; |
62 | html_txt(ascii); | 72 | html_txt(ascii); |
63 | html("</td></tr>\n"); | 73 | html("</td></tr>\n"); |
64 | } | 74 | } |
65 | html("</table>\n"); | 75 | html("</table>\n"); |
66 | } | 76 | } |
67 | 77 | ||
68 | static void print_object(const unsigned char *sha1, char *path) | 78 | static void print_object(const unsigned char *sha1, char *path, const char *basename) |
69 | { | 79 | { |
70 | enum object_type type; | 80 | enum object_type type; |
71 | char *buf; | 81 | char *buf; |
72 | unsigned long size; | 82 | unsigned long size; |
73 | 83 | ||
74 | type = sha1_object_info(sha1, &size); | 84 | type = sha1_object_info(sha1, &size); |
75 | if (type == OBJ_BAD) { | 85 | if (type == OBJ_BAD) { |
76 | cgit_print_error(fmt("Bad object name: %s", | 86 | cgit_print_error(fmt("Bad object name: %s", |
77 | sha1_to_hex(sha1))); | 87 | sha1_to_hex(sha1))); |
78 | return; | 88 | return; |
79 | } | 89 | } |
80 | 90 | ||
81 | buf = read_sha1_file(sha1, &type, &size); | 91 | buf = read_sha1_file(sha1, &type, &size); |
82 | if (!buf) { | 92 | if (!buf) { |
83 | cgit_print_error(fmt("Error reading object %s", | 93 | cgit_print_error(fmt("Error reading object %s", |
84 | sha1_to_hex(sha1))); | 94 | sha1_to_hex(sha1))); |
85 | return; | 95 | return; |
86 | } | 96 | } |
87 | 97 | ||
88 | html(" ("); | 98 | html(" ("); |
89 | cgit_plain_link("plain", NULL, NULL, ctx.qry.head, | 99 | cgit_plain_link("plain", NULL, NULL, ctx.qry.head, |
90 | curr_rev, path); | 100 | curr_rev, path); |
91 | htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); | 101 | htmlf(")<br/>blob: %s\n", sha1_to_hex(sha1)); |
92 | 102 | ||
93 | if (buffer_is_binary(buf, size)) | 103 | if (buffer_is_binary(buf, size)) |
94 | print_binary_buffer(buf, size); | 104 | print_binary_buffer(buf, size); |
95 | else | 105 | else |
96 | print_text_buffer(buf, size); | 106 | print_text_buffer(basename, buf, size); |
97 | } | 107 | } |
98 | 108 | ||
99 | 109 | ||
100 | static int ls_item(const unsigned char *sha1, const char *base, int baselen, | 110 | static int ls_item(const unsigned char *sha1, const char *base, int baselen, |
101 | const char *pathname, unsigned int mode, int stage, | 111 | const char *pathname, unsigned int mode, int stage, |
102 | void *cbdata) | 112 | void *cbdata) |
103 | { | 113 | { |
104 | char *name; | 114 | char *name; |
105 | char *fullpath; | 115 | char *fullpath; |
106 | enum object_type type; | 116 | enum object_type type; |
107 | unsigned long size = 0; | 117 | unsigned long size = 0; |
108 | 118 | ||
109 | name = xstrdup(pathname); | 119 | name = xstrdup(pathname); |
110 | fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", | 120 | fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", |
111 | ctx.qry.path ? "/" : "", name); | 121 | ctx.qry.path ? "/" : "", name); |
112 | 122 | ||
113 | if (!S_ISGITLINK(mode)) { | 123 | if (!S_ISGITLINK(mode)) { |
114 | type = sha1_object_info(sha1, &size); | 124 | type = sha1_object_info(sha1, &size); |
115 | if (type == OBJ_BAD) { | 125 | if (type == OBJ_BAD) { |
116 | htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", | 126 | htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", |
117 | name, | 127 | name, |
118 | sha1_to_hex(sha1)); | 128 | sha1_to_hex(sha1)); |
119 | return 0; | 129 | return 0; |
120 | } | 130 | } |
121 | } | 131 | } |
122 | 132 | ||
123 | html("<tr><td class='ls-mode'>"); | 133 | html("<tr><td class='ls-mode'>"); |
124 | cgit_print_filemode(mode); | 134 | cgit_print_filemode(mode); |
125 | html("</td><td>"); | 135 | html("</td><td>"); |
126 | if (S_ISGITLINK(mode)) { | 136 | if (S_ISGITLINK(mode)) { |
127 | htmlf("<a class='ls-mod' href='"); | 137 | htmlf("<a class='ls-mod' href='"); |
128 | html_attr(fmt(ctx.repo->module_link, | 138 | html_attr(fmt(ctx.repo->module_link, |
@@ -184,65 +194,65 @@ static void ls_tree(const unsigned char *sha1, char *path) | |||
184 | 194 | ||
185 | ls_head(); | 195 | ls_head(); |
186 | read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); | 196 | read_tree_recursive(tree, "", 0, 1, NULL, ls_item, NULL); |
187 | ls_tail(); | 197 | ls_tail(); |
188 | } | 198 | } |
189 | 199 | ||
190 | 200 | ||
191 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | 201 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, |
192 | const char *pathname, unsigned mode, int stage, | 202 | const char *pathname, unsigned mode, int stage, |
193 | void *cbdata) | 203 | void *cbdata) |
194 | { | 204 | { |
195 | static int state; | 205 | static int state; |
196 | static char buffer[PATH_MAX]; | 206 | static char buffer[PATH_MAX]; |
197 | char *url; | 207 | char *url; |
198 | 208 | ||
199 | if (state == 0) { | 209 | if (state == 0) { |
200 | memcpy(buffer, base, baselen); | 210 | memcpy(buffer, base, baselen); |
201 | strcpy(buffer+baselen, pathname); | 211 | strcpy(buffer+baselen, pathname); |
202 | url = cgit_pageurl(ctx.qry.repo, "tree", | 212 | url = cgit_pageurl(ctx.qry.repo, "tree", |
203 | fmt("h=%s&path=%s", curr_rev, buffer)); | 213 | fmt("h=%s&path=%s", curr_rev, buffer)); |
204 | html("/"); | 214 | html("/"); |
205 | cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, | 215 | cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head, |
206 | curr_rev, buffer); | 216 | curr_rev, buffer); |
207 | 217 | ||
208 | if (strcmp(match_path, buffer)) | 218 | if (strcmp(match_path, buffer)) |
209 | return READ_TREE_RECURSIVE; | 219 | return READ_TREE_RECURSIVE; |
210 | 220 | ||
211 | if (S_ISDIR(mode)) { | 221 | if (S_ISDIR(mode)) { |
212 | state = 1; | 222 | state = 1; |
213 | ls_head(); | 223 | ls_head(); |
214 | return READ_TREE_RECURSIVE; | 224 | return READ_TREE_RECURSIVE; |
215 | } else { | 225 | } else { |
216 | print_object(sha1, buffer); | 226 | print_object(sha1, buffer, pathname); |
217 | return 0; | 227 | return 0; |
218 | } | 228 | } |
219 | } | 229 | } |
220 | ls_item(sha1, base, baselen, pathname, mode, stage, NULL); | 230 | ls_item(sha1, base, baselen, pathname, mode, stage, NULL); |
221 | return 0; | 231 | return 0; |
222 | } | 232 | } |
223 | 233 | ||
224 | 234 | ||
225 | /* | 235 | /* |
226 | * Show a tree or a blob | 236 | * Show a tree or a blob |
227 | * rev: the commit pointing at the root tree object | 237 | * rev: the commit pointing at the root tree object |
228 | * path: path to tree or blob | 238 | * path: path to tree or blob |
229 | */ | 239 | */ |
230 | void cgit_print_tree(const char *rev, char *path) | 240 | void cgit_print_tree(const char *rev, char *path) |
231 | { | 241 | { |
232 | unsigned char sha1[20]; | 242 | unsigned char sha1[20]; |
233 | struct commit *commit; | 243 | struct commit *commit; |
234 | const char *paths[] = {path, NULL}; | 244 | const char *paths[] = {path, NULL}; |
235 | 245 | ||
236 | if (!rev) | 246 | if (!rev) |
237 | rev = ctx.qry.head; | 247 | rev = ctx.qry.head; |
238 | 248 | ||
239 | curr_rev = xstrdup(rev); | 249 | curr_rev = xstrdup(rev); |
240 | if (get_sha1(rev, sha1)) { | 250 | if (get_sha1(rev, sha1)) { |
241 | cgit_print_error(fmt("Invalid revision name: %s", rev)); | 251 | cgit_print_error(fmt("Invalid revision name: %s", rev)); |
242 | return; | 252 | return; |
243 | } | 253 | } |
244 | commit = lookup_commit_reference(sha1); | 254 | commit = lookup_commit_reference(sha1); |
245 | if (!commit || parse_commit(commit)) { | 255 | if (!commit || parse_commit(commit)) { |
246 | cgit_print_error(fmt("Invalid commit reference: %s", rev)); | 256 | cgit_print_error(fmt("Invalid commit reference: %s", rev)); |
247 | return; | 257 | return; |
248 | } | 258 | } |