author | Lars Hjemli <hjemli@gmail.com> | 2007-11-03 09:42:37 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2007-11-03 09:42:37 (UTC) |
commit | 51140311bb3b0d4d0e859d5045ffe4c74478f5fe (patch) (unidiff) | |
tree | 6575f174e32abd5f5d1f481e5f7f5978525ae416 | |
parent | df203a293e3ac19245f8761cf7c5808f8735f917 (diff) | |
download | cgit-51140311bb3b0d4d0e859d5045ffe4c74478f5fe.zip cgit-51140311bb3b0d4d0e859d5045ffe4c74478f5fe.tar.gz cgit-51140311bb3b0d4d0e859d5045ffe4c74478f5fe.tar.bz2 |
Add search parameters to cgit_log_link
This makes the [prev] and [next] links work correctly on search results.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.h | 3 | ||||
-rw-r--r-- | ui-log.c | 6 | ||||
-rw-r--r-- | ui-repolist.c | 3 | ||||
-rw-r--r-- | ui-shared.c | 13 | ||||
-rw-r--r-- | ui-summary.c | 2 | ||||
-rw-r--r-- | ui-tree.c | 2 |
6 files changed, 21 insertions, 8 deletions
@@ -1,282 +1,283 @@ | |||
1 | #ifndef CGIT_H | 1 | #ifndef CGIT_H |
2 | #define CGIT_H | 2 | #define CGIT_H |
3 | 3 | ||
4 | 4 | ||
5 | #include <git-compat-util.h> | 5 | #include <git-compat-util.h> |
6 | #include <cache.h> | 6 | #include <cache.h> |
7 | #include <grep.h> | 7 | #include <grep.h> |
8 | #include <object.h> | 8 | #include <object.h> |
9 | #include <tree.h> | 9 | #include <tree.h> |
10 | #include <commit.h> | 10 | #include <commit.h> |
11 | #include <tag.h> | 11 | #include <tag.h> |
12 | #include <diff.h> | 12 | #include <diff.h> |
13 | #include <diffcore.h> | 13 | #include <diffcore.h> |
14 | #include <refs.h> | 14 | #include <refs.h> |
15 | #include <revision.h> | 15 | #include <revision.h> |
16 | #include <log-tree.h> | 16 | #include <log-tree.h> |
17 | #include <archive.h> | 17 | #include <archive.h> |
18 | #include <xdiff/xdiff.h> | 18 | #include <xdiff/xdiff.h> |
19 | 19 | ||
20 | 20 | ||
21 | /* | 21 | /* |
22 | * The valid cgit repo-commands | 22 | * The valid cgit repo-commands |
23 | */ | 23 | */ |
24 | #define CMD_LOG 1 | 24 | #define CMD_LOG 1 |
25 | #define CMD_COMMIT 2 | 25 | #define CMD_COMMIT 2 |
26 | #define CMD_DIFF 3 | 26 | #define CMD_DIFF 3 |
27 | #define CMD_TREE 4 | 27 | #define CMD_TREE 4 |
28 | #define CMD_BLOB 5 | 28 | #define CMD_BLOB 5 |
29 | #define CMD_SNAPSHOT 6 | 29 | #define CMD_SNAPSHOT 6 |
30 | #define CMD_TAG 7 | 30 | #define CMD_TAG 7 |
31 | #define CMD_REFS 8 | 31 | #define CMD_REFS 8 |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Dateformats used on misc. pages | 34 | * Dateformats used on misc. pages |
35 | */ | 35 | */ |
36 | #define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" | 36 | #define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" |
37 | #define FMT_SHORTDATE "%Y-%m-%d" | 37 | #define FMT_SHORTDATE "%Y-%m-%d" |
38 | 38 | ||
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Limits used for relative dates | 41 | * Limits used for relative dates |
42 | */ | 42 | */ |
43 | #define TM_MIN 60 | 43 | #define TM_MIN 60 |
44 | #define TM_HOUR (TM_MIN * 60) | 44 | #define TM_HOUR (TM_MIN * 60) |
45 | #define TM_DAY (TM_HOUR * 24) | 45 | #define TM_DAY (TM_HOUR * 24) |
46 | #define TM_WEEK (TM_DAY * 7) | 46 | #define TM_WEEK (TM_DAY * 7) |
47 | #define TM_YEAR (TM_DAY * 365) | 47 | #define TM_YEAR (TM_DAY * 365) |
48 | #define TM_MONTH (TM_YEAR / 12.0) | 48 | #define TM_MONTH (TM_YEAR / 12.0) |
49 | 49 | ||
50 | 50 | ||
51 | typedef void (*configfn)(const char *name, const char *value); | 51 | typedef void (*configfn)(const char *name, const char *value); |
52 | typedef void (*filepair_fn)(struct diff_filepair *pair); | 52 | typedef void (*filepair_fn)(struct diff_filepair *pair); |
53 | typedef void (*linediff_fn)(char *line, int len); | 53 | typedef void (*linediff_fn)(char *line, int len); |
54 | 54 | ||
55 | struct cacheitem { | 55 | struct cacheitem { |
56 | char *name; | 56 | char *name; |
57 | struct stat st; | 57 | struct stat st; |
58 | int ttl; | 58 | int ttl; |
59 | int fd; | 59 | int fd; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | struct repoinfo { | 62 | struct repoinfo { |
63 | char *url; | 63 | char *url; |
64 | char *name; | 64 | char *name; |
65 | char *path; | 65 | char *path; |
66 | char *desc; | 66 | char *desc; |
67 | char *owner; | 67 | char *owner; |
68 | char *defbranch; | 68 | char *defbranch; |
69 | char *group; | 69 | char *group; |
70 | char *module_link; | 70 | char *module_link; |
71 | char *readme; | 71 | char *readme; |
72 | int snapshots; | 72 | int snapshots; |
73 | int enable_log_filecount; | 73 | int enable_log_filecount; |
74 | int enable_log_linecount; | 74 | int enable_log_linecount; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct repolist { | 77 | struct repolist { |
78 | int length; | 78 | int length; |
79 | int count; | 79 | int count; |
80 | struct repoinfo *repos; | 80 | struct repoinfo *repos; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | struct commitinfo { | 83 | struct commitinfo { |
84 | struct commit *commit; | 84 | struct commit *commit; |
85 | char *author; | 85 | char *author; |
86 | char *author_email; | 86 | char *author_email; |
87 | unsigned long author_date; | 87 | unsigned long author_date; |
88 | char *committer; | 88 | char *committer; |
89 | char *committer_email; | 89 | char *committer_email; |
90 | unsigned long committer_date; | 90 | unsigned long committer_date; |
91 | char *subject; | 91 | char *subject; |
92 | char *msg; | 92 | char *msg; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | struct taginfo { | 95 | struct taginfo { |
96 | char *tagger; | 96 | char *tagger; |
97 | char *tagger_email; | 97 | char *tagger_email; |
98 | int tagger_date; | 98 | int tagger_date; |
99 | char *msg; | 99 | char *msg; |
100 | }; | 100 | }; |
101 | 101 | ||
102 | struct refinfo { | 102 | struct refinfo { |
103 | const char *refname; | 103 | const char *refname; |
104 | struct object *object; | 104 | struct object *object; |
105 | union { | 105 | union { |
106 | struct taginfo *tag; | 106 | struct taginfo *tag; |
107 | struct commitinfo *commit; | 107 | struct commitinfo *commit; |
108 | }; | 108 | }; |
109 | }; | 109 | }; |
110 | 110 | ||
111 | struct reflist { | 111 | struct reflist { |
112 | struct refinfo **refs; | 112 | struct refinfo **refs; |
113 | int alloc; | 113 | int alloc; |
114 | int count; | 114 | int count; |
115 | }; | 115 | }; |
116 | 116 | ||
117 | extern const char *cgit_version; | 117 | extern const char *cgit_version; |
118 | 118 | ||
119 | extern struct repolist cgit_repolist; | 119 | extern struct repolist cgit_repolist; |
120 | extern struct repoinfo *cgit_repo; | 120 | extern struct repoinfo *cgit_repo; |
121 | extern int cgit_cmd; | 121 | extern int cgit_cmd; |
122 | 122 | ||
123 | extern char *cgit_root_title; | 123 | extern char *cgit_root_title; |
124 | extern char *cgit_css; | 124 | extern char *cgit_css; |
125 | extern char *cgit_logo; | 125 | extern char *cgit_logo; |
126 | extern char *cgit_index_header; | 126 | extern char *cgit_index_header; |
127 | extern char *cgit_index_info; | 127 | extern char *cgit_index_info; |
128 | extern char *cgit_logo_link; | 128 | extern char *cgit_logo_link; |
129 | extern char *cgit_module_link; | 129 | extern char *cgit_module_link; |
130 | extern char *cgit_agefile; | 130 | extern char *cgit_agefile; |
131 | extern char *cgit_virtual_root; | 131 | extern char *cgit_virtual_root; |
132 | extern char *cgit_script_name; | 132 | extern char *cgit_script_name; |
133 | extern char *cgit_cache_root; | 133 | extern char *cgit_cache_root; |
134 | extern char *cgit_repo_group; | 134 | extern char *cgit_repo_group; |
135 | 135 | ||
136 | extern int cgit_nocache; | 136 | extern int cgit_nocache; |
137 | extern int cgit_snapshots; | 137 | extern int cgit_snapshots; |
138 | extern int cgit_enable_index_links; | 138 | extern int cgit_enable_index_links; |
139 | extern int cgit_enable_log_filecount; | 139 | extern int cgit_enable_log_filecount; |
140 | extern int cgit_enable_log_linecount; | 140 | extern int cgit_enable_log_linecount; |
141 | extern int cgit_max_lock_attempts; | 141 | extern int cgit_max_lock_attempts; |
142 | extern int cgit_cache_root_ttl; | 142 | extern int cgit_cache_root_ttl; |
143 | extern int cgit_cache_repo_ttl; | 143 | extern int cgit_cache_repo_ttl; |
144 | extern int cgit_cache_dynamic_ttl; | 144 | extern int cgit_cache_dynamic_ttl; |
145 | extern int cgit_cache_static_ttl; | 145 | extern int cgit_cache_static_ttl; |
146 | extern int cgit_cache_max_create_time; | 146 | extern int cgit_cache_max_create_time; |
147 | extern int cgit_summary_log; | 147 | extern int cgit_summary_log; |
148 | extern int cgit_summary_tags; | 148 | extern int cgit_summary_tags; |
149 | extern int cgit_summary_branches; | 149 | extern int cgit_summary_branches; |
150 | 150 | ||
151 | extern int cgit_max_msg_len; | 151 | extern int cgit_max_msg_len; |
152 | extern int cgit_max_repodesc_len; | 152 | extern int cgit_max_repodesc_len; |
153 | extern int cgit_max_commit_count; | 153 | extern int cgit_max_commit_count; |
154 | 154 | ||
155 | extern int cgit_query_has_symref; | 155 | extern int cgit_query_has_symref; |
156 | extern int cgit_query_has_sha1; | 156 | extern int cgit_query_has_sha1; |
157 | 157 | ||
158 | extern char *cgit_querystring; | 158 | extern char *cgit_querystring; |
159 | extern char *cgit_query_repo; | 159 | extern char *cgit_query_repo; |
160 | extern char *cgit_query_page; | 160 | extern char *cgit_query_page; |
161 | extern char *cgit_query_search; | 161 | extern char *cgit_query_search; |
162 | extern char *cgit_query_grep; | 162 | extern char *cgit_query_grep; |
163 | extern char *cgit_query_head; | 163 | extern char *cgit_query_head; |
164 | extern char *cgit_query_sha1; | 164 | extern char *cgit_query_sha1; |
165 | extern char *cgit_query_sha2; | 165 | extern char *cgit_query_sha2; |
166 | extern char *cgit_query_path; | 166 | extern char *cgit_query_path; |
167 | extern char *cgit_query_name; | 167 | extern char *cgit_query_name; |
168 | extern int cgit_query_ofs; | 168 | extern int cgit_query_ofs; |
169 | 169 | ||
170 | extern int htmlfd; | 170 | extern int htmlfd; |
171 | 171 | ||
172 | extern int cgit_get_cmd_index(const char *cmd); | 172 | extern int cgit_get_cmd_index(const char *cmd); |
173 | extern struct repoinfo *cgit_get_repoinfo(const char *url); | 173 | extern struct repoinfo *cgit_get_repoinfo(const char *url); |
174 | extern void cgit_global_config_cb(const char *name, const char *value); | 174 | extern void cgit_global_config_cb(const char *name, const char *value); |
175 | extern void cgit_repo_config_cb(const char *name, const char *value); | 175 | extern void cgit_repo_config_cb(const char *name, const char *value); |
176 | extern void cgit_querystring_cb(const char *name, const char *value); | 176 | extern void cgit_querystring_cb(const char *name, const char *value); |
177 | 177 | ||
178 | extern int chk_zero(int result, char *msg); | 178 | extern int chk_zero(int result, char *msg); |
179 | extern int chk_positive(int result, char *msg); | 179 | extern int chk_positive(int result, char *msg); |
180 | extern int chk_non_negative(int result, char *msg); | 180 | extern int chk_non_negative(int result, char *msg); |
181 | 181 | ||
182 | extern int hextoint(char c); | 182 | extern int hextoint(char c); |
183 | extern char *trim_end(const char *str, char c); | 183 | extern char *trim_end(const char *str, char c); |
184 | extern char *strlpart(char *txt, int maxlen); | 184 | extern char *strlpart(char *txt, int maxlen); |
185 | extern char *strrpart(char *txt, int maxlen); | 185 | extern char *strrpart(char *txt, int maxlen); |
186 | 186 | ||
187 | extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); | 187 | extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); |
188 | extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, | 188 | extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, |
189 | int flags, void *cb_data); | 189 | int flags, void *cb_data); |
190 | 190 | ||
191 | extern void *cgit_free_commitinfo(struct commitinfo *info); | 191 | extern void *cgit_free_commitinfo(struct commitinfo *info); |
192 | 192 | ||
193 | extern int cgit_diff_files(const unsigned char *old_sha1, | 193 | extern int cgit_diff_files(const unsigned char *old_sha1, |
194 | const unsigned char *new_sha1, | 194 | const unsigned char *new_sha1, |
195 | linediff_fn fn); | 195 | linediff_fn fn); |
196 | 196 | ||
197 | extern void cgit_diff_tree(const unsigned char *old_sha1, | 197 | extern void cgit_diff_tree(const unsigned char *old_sha1, |
198 | const unsigned char *new_sha1, | 198 | const unsigned char *new_sha1, |
199 | filepair_fn fn, const char *prefix); | 199 | filepair_fn fn, const char *prefix); |
200 | 200 | ||
201 | extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); | 201 | extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); |
202 | 202 | ||
203 | extern char *fmt(const char *format,...); | 203 | extern char *fmt(const char *format,...); |
204 | 204 | ||
205 | extern void html(const char *txt); | 205 | extern void html(const char *txt); |
206 | extern void htmlf(const char *format,...); | 206 | extern void htmlf(const char *format,...); |
207 | extern void html_txt(char *txt); | 207 | extern void html_txt(char *txt); |
208 | extern void html_ntxt(int len, char *txt); | 208 | extern void html_ntxt(int len, char *txt); |
209 | extern void html_attr(char *txt); | 209 | extern void html_attr(char *txt); |
210 | extern void html_hidden(char *name, char *value); | 210 | extern void html_hidden(char *name, char *value); |
211 | extern void html_option(char *value, char *text, char *selected_value); | 211 | extern void html_option(char *value, char *text, char *selected_value); |
212 | extern void html_link_open(char *url, char *title, char *class); | 212 | extern void html_link_open(char *url, char *title, char *class); |
213 | extern void html_link_close(void); | 213 | extern void html_link_close(void); |
214 | extern void html_filemode(unsigned short mode); | 214 | extern void html_filemode(unsigned short mode); |
215 | extern int html_include(const char *filename); | 215 | extern int html_include(const char *filename); |
216 | 216 | ||
217 | extern int cgit_read_config(const char *filename, configfn fn); | 217 | extern int cgit_read_config(const char *filename, configfn fn); |
218 | extern int cgit_parse_query(char *txt, configfn fn); | 218 | extern int cgit_parse_query(char *txt, configfn fn); |
219 | extern struct commitinfo *cgit_parse_commit(struct commit *commit); | 219 | extern struct commitinfo *cgit_parse_commit(struct commit *commit); |
220 | extern struct taginfo *cgit_parse_tag(struct tag *tag); | 220 | extern struct taginfo *cgit_parse_tag(struct tag *tag); |
221 | extern void cgit_parse_url(const char *url); | 221 | extern void cgit_parse_url(const char *url); |
222 | 222 | ||
223 | extern char *cache_safe_filename(const char *unsafe); | 223 | extern char *cache_safe_filename(const char *unsafe); |
224 | extern int cache_lock(struct cacheitem *item); | 224 | extern int cache_lock(struct cacheitem *item); |
225 | extern int cache_unlock(struct cacheitem *item); | 225 | extern int cache_unlock(struct cacheitem *item); |
226 | extern int cache_cancel_lock(struct cacheitem *item); | 226 | extern int cache_cancel_lock(struct cacheitem *item); |
227 | extern int cache_exist(struct cacheitem *item); | 227 | extern int cache_exist(struct cacheitem *item); |
228 | extern int cache_expired(struct cacheitem *item); | 228 | extern int cache_expired(struct cacheitem *item); |
229 | 229 | ||
230 | extern char *cgit_repourl(const char *reponame); | 230 | extern char *cgit_repourl(const char *reponame); |
231 | extern char *cgit_fileurl(const char *reponame, const char *pagename, | 231 | extern char *cgit_fileurl(const char *reponame, const char *pagename, |
232 | const char *filename, const char *query); | 232 | const char *filename, const char *query); |
233 | extern char *cgit_pageurl(const char *reponame, const char *pagename, | 233 | extern char *cgit_pageurl(const char *reponame, const char *pagename, |
234 | const char *query); | 234 | const char *query); |
235 | 235 | ||
236 | extern const char *cgit_repobasename(const char *reponame); | 236 | extern const char *cgit_repobasename(const char *reponame); |
237 | 237 | ||
238 | extern void cgit_tree_link(char *name, char *title, char *class, char *head, | 238 | extern void cgit_tree_link(char *name, char *title, char *class, char *head, |
239 | char *rev, char *path); | 239 | char *rev, char *path); |
240 | extern void cgit_log_link(char *name, char *title, char *class, char *head, | 240 | extern void cgit_log_link(char *name, char *title, char *class, char *head, |
241 | char *rev, char *path, int ofs); | 241 | char *rev, char *path, int ofs, char *grep, |
242 | char *pattern); | ||
242 | extern void cgit_commit_link(char *name, char *title, char *class, char *head, | 243 | extern void cgit_commit_link(char *name, char *title, char *class, char *head, |
243 | char *rev); | 244 | char *rev); |
244 | extern void cgit_refs_link(char *name, char *title, char *class, char *head, | 245 | extern void cgit_refs_link(char *name, char *title, char *class, char *head, |
245 | char *rev, char *path); | 246 | char *rev, char *path); |
246 | extern void cgit_snapshot_link(char *name, char *title, char *class, | 247 | extern void cgit_snapshot_link(char *name, char *title, char *class, |
247 | char *head, char *rev, char *archivename); | 248 | char *head, char *rev, char *archivename); |
248 | extern void cgit_diff_link(char *name, char *title, char *class, char *head, | 249 | extern void cgit_diff_link(char *name, char *title, char *class, char *head, |
249 | char *new_rev, char *old_rev, char *path); | 250 | char *new_rev, char *old_rev, char *path); |
250 | 251 | ||
251 | extern void cgit_object_link(struct object *obj); | 252 | extern void cgit_object_link(struct object *obj); |
252 | 253 | ||
253 | extern void cgit_print_error(char *msg); | 254 | extern void cgit_print_error(char *msg); |
254 | extern void cgit_print_date(time_t secs, char *format); | 255 | extern void cgit_print_date(time_t secs, char *format); |
255 | extern void cgit_print_age(time_t t, time_t max_relative, char *format); | 256 | extern void cgit_print_age(time_t t, time_t max_relative, char *format); |
256 | extern void cgit_print_docstart(char *title, struct cacheitem *item); | 257 | extern void cgit_print_docstart(char *title, struct cacheitem *item); |
257 | extern void cgit_print_docend(); | 258 | extern void cgit_print_docend(); |
258 | extern void cgit_print_pageheader(char *title, int show_search); | 259 | extern void cgit_print_pageheader(char *title, int show_search); |
259 | extern void cgit_print_snapshot_start(const char *mimetype, | 260 | extern void cgit_print_snapshot_start(const char *mimetype, |
260 | const char *filename, | 261 | const char *filename, |
261 | struct cacheitem *item); | 262 | struct cacheitem *item); |
262 | extern void cgit_print_branches(int maxcount); | 263 | extern void cgit_print_branches(int maxcount); |
263 | extern void cgit_print_tags(int maxcount); | 264 | extern void cgit_print_tags(int maxcount); |
264 | 265 | ||
265 | extern void cgit_print_repolist(struct cacheitem *item); | 266 | extern void cgit_print_repolist(struct cacheitem *item); |
266 | extern void cgit_print_summary(); | 267 | extern void cgit_print_summary(); |
267 | extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, | 268 | extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, |
268 | char *pattern, char *path, int pager); | 269 | char *pattern, char *path, int pager); |
269 | extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); | 270 | extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); |
270 | extern void cgit_print_tree(const char *rev, char *path); | 271 | extern void cgit_print_tree(const char *rev, char *path); |
271 | extern void cgit_print_commit(char *hex); | 272 | extern void cgit_print_commit(char *hex); |
272 | extern void cgit_print_refs(); | 273 | extern void cgit_print_refs(); |
273 | extern void cgit_print_tag(char *revname); | 274 | extern void cgit_print_tag(char *revname); |
274 | extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix); | 275 | extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix); |
275 | extern void cgit_print_snapshot(struct cacheitem *item, const char *head, | 276 | extern void cgit_print_snapshot(struct cacheitem *item, const char *head, |
276 | const char *hex, const char *prefix, | 277 | const char *hex, const char *prefix, |
277 | const char *filename, int snapshot); | 278 | const char *filename, int snapshot); |
278 | extern void cgit_print_snapshot_links(const char *repo, const char *head, | 279 | extern void cgit_print_snapshot_links(const char *repo, const char *head, |
279 | const char *hex, int snapshots); | 280 | const char *hex, int snapshots); |
280 | extern int cgit_parse_snapshots_mask(const char *str); | 281 | extern int cgit_parse_snapshots_mask(const char *str); |
281 | 282 | ||
282 | #endif /* CGIT_H */ | 283 | #endif /* CGIT_H */ |
@@ -1,131 +1,133 @@ | |||
1 | /* ui-log.c: functions for log output | 1 | /* ui-log.c: functions for log 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 "cgit.h" | 9 | #include "cgit.h" |
10 | 10 | ||
11 | int files, lines; | 11 | int files, lines; |
12 | 12 | ||
13 | void count_lines(char *line, int size) | 13 | void count_lines(char *line, int size) |
14 | { | 14 | { |
15 | if (size>0 && (line[0] == '+' || line[0] == '-')) | 15 | if (size>0 && (line[0] == '+' || line[0] == '-')) |
16 | lines++; | 16 | lines++; |
17 | } | 17 | } |
18 | 18 | ||
19 | void inspect_files(struct diff_filepair *pair) | 19 | void inspect_files(struct diff_filepair *pair) |
20 | { | 20 | { |
21 | files++; | 21 | files++; |
22 | if (cgit_repo->enable_log_linecount) | 22 | if (cgit_repo->enable_log_linecount) |
23 | cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines); | 23 | cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines); |
24 | } | 24 | } |
25 | 25 | ||
26 | void print_commit(struct commit *commit) | 26 | void print_commit(struct commit *commit) |
27 | { | 27 | { |
28 | struct commitinfo *info; | 28 | struct commitinfo *info; |
29 | 29 | ||
30 | info = cgit_parse_commit(commit); | 30 | info = cgit_parse_commit(commit); |
31 | html("<tr><td>"); | 31 | html("<tr><td>"); |
32 | cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); | 32 | cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); |
33 | html("</td><td>"); | 33 | html("</td><td>"); |
34 | cgit_commit_link(info->subject, NULL, NULL, cgit_query_head, | 34 | cgit_commit_link(info->subject, NULL, NULL, cgit_query_head, |
35 | sha1_to_hex(commit->object.sha1)); | 35 | sha1_to_hex(commit->object.sha1)); |
36 | if (cgit_repo->enable_log_filecount) { | 36 | if (cgit_repo->enable_log_filecount) { |
37 | files = 0; | 37 | files = 0; |
38 | lines = 0; | 38 | lines = 0; |
39 | cgit_diff_commit(commit, inspect_files); | 39 | cgit_diff_commit(commit, inspect_files); |
40 | html("</td><td class='right'>"); | 40 | html("</td><td class='right'>"); |
41 | htmlf("%d", files); | 41 | htmlf("%d", files); |
42 | if (cgit_repo->enable_log_linecount) { | 42 | if (cgit_repo->enable_log_linecount) { |
43 | html("</td><td class='right'>"); | 43 | html("</td><td class='right'>"); |
44 | htmlf("%d", lines); | 44 | htmlf("%d", lines); |
45 | } | 45 | } |
46 | } | 46 | } |
47 | html("</td><td>"); | 47 | html("</td><td>"); |
48 | html_txt(info->author); | 48 | html_txt(info->author); |
49 | html("</td></tr>\n"); | 49 | html("</td></tr>\n"); |
50 | cgit_free_commitinfo(info); | 50 | cgit_free_commitinfo(info); |
51 | } | 51 | } |
52 | 52 | ||
53 | 53 | ||
54 | void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, char *path, int pager) | 54 | void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, char *path, int pager) |
55 | { | 55 | { |
56 | struct rev_info rev; | 56 | struct rev_info rev; |
57 | struct commit *commit; | 57 | struct commit *commit; |
58 | const char *argv[] = {NULL, tip, NULL, NULL, NULL}; | 58 | const char *argv[] = {NULL, tip, NULL, NULL, NULL}; |
59 | int argc = 2; | 59 | int argc = 2; |
60 | int i; | 60 | int i; |
61 | 61 | ||
62 | if (!tip) | 62 | if (!tip) |
63 | argv[1] = cgit_query_head; | 63 | argv[1] = cgit_query_head; |
64 | 64 | ||
65 | if (grep && pattern && (!strcmp(grep, "grep") || | 65 | if (grep && pattern && (!strcmp(grep, "grep") || |
66 | !strcmp(grep, "author") || | 66 | !strcmp(grep, "author") || |
67 | !strcmp(grep, "committer"))) | 67 | !strcmp(grep, "committer"))) |
68 | argv[argc++] = fmt("--%s=%s", grep, pattern); | 68 | argv[argc++] = fmt("--%s=%s", grep, pattern); |
69 | 69 | ||
70 | if (path) { | 70 | if (path) { |
71 | argv[argc++] = "--"; | 71 | argv[argc++] = "--"; |
72 | argv[argc++] = path; | 72 | argv[argc++] = path; |
73 | } | 73 | } |
74 | init_revisions(&rev, NULL); | 74 | init_revisions(&rev, NULL); |
75 | rev.abbrev = DEFAULT_ABBREV; | 75 | rev.abbrev = DEFAULT_ABBREV; |
76 | rev.commit_format = CMIT_FMT_DEFAULT; | 76 | rev.commit_format = CMIT_FMT_DEFAULT; |
77 | rev.verbose_header = 1; | 77 | rev.verbose_header = 1; |
78 | rev.show_root_diff = 0; | 78 | rev.show_root_diff = 0; |
79 | setup_revisions(argc, argv, &rev, NULL); | 79 | setup_revisions(argc, argv, &rev, NULL); |
80 | if (rev.grep_filter) { | 80 | if (rev.grep_filter) { |
81 | rev.grep_filter->regflags |= REG_ICASE; | 81 | rev.grep_filter->regflags |= REG_ICASE; |
82 | compile_grep_patterns(rev.grep_filter); | 82 | compile_grep_patterns(rev.grep_filter); |
83 | } | 83 | } |
84 | prepare_revision_walk(&rev); | 84 | prepare_revision_walk(&rev); |
85 | 85 | ||
86 | html("<table class='list nowrap'>"); | 86 | html("<table class='list nowrap'>"); |
87 | html("<tr class='nohover'><th class='left'>Age</th>" | 87 | html("<tr class='nohover'><th class='left'>Age</th>" |
88 | "<th class='left'>Message</th>"); | 88 | "<th class='left'>Message</th>"); |
89 | 89 | ||
90 | if (cgit_repo->enable_log_filecount) { | 90 | if (cgit_repo->enable_log_filecount) { |
91 | html("<th class='left'>Files</th>"); | 91 | html("<th class='left'>Files</th>"); |
92 | if (cgit_repo->enable_log_linecount) | 92 | if (cgit_repo->enable_log_linecount) |
93 | html("<th class='left'>Lines</th>"); | 93 | html("<th class='left'>Lines</th>"); |
94 | } | 94 | } |
95 | html("<th class='left'>Author</th></tr>\n"); | 95 | html("<th class='left'>Author</th></tr>\n"); |
96 | 96 | ||
97 | if (ofs<0) | 97 | if (ofs<0) |
98 | ofs = 0; | 98 | ofs = 0; |
99 | 99 | ||
100 | for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { | 100 | for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; i++) { |
101 | free(commit->buffer); | 101 | free(commit->buffer); |
102 | commit->buffer = NULL; | 102 | commit->buffer = NULL; |
103 | free_commit_list(commit->parents); | 103 | free_commit_list(commit->parents); |
104 | commit->parents = NULL; | 104 | commit->parents = NULL; |
105 | } | 105 | } |
106 | 106 | ||
107 | for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { | 107 | for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; i++) { |
108 | print_commit(commit); | 108 | print_commit(commit); |
109 | free(commit->buffer); | 109 | free(commit->buffer); |
110 | commit->buffer = NULL; | 110 | commit->buffer = NULL; |
111 | free_commit_list(commit->parents); | 111 | free_commit_list(commit->parents); |
112 | commit->parents = NULL; | 112 | commit->parents = NULL; |
113 | } | 113 | } |
114 | html("</table>\n"); | 114 | html("</table>\n"); |
115 | 115 | ||
116 | if (pager) { | 116 | if (pager) { |
117 | html("<div class='pager'>"); | 117 | html("<div class='pager'>"); |
118 | if (ofs > 0) { | 118 | if (ofs > 0) { |
119 | cgit_log_link("[prev]", NULL, NULL, cgit_query_head, | 119 | cgit_log_link("[prev]", NULL, NULL, cgit_query_head, |
120 | cgit_query_sha1, cgit_query_path, | 120 | cgit_query_sha1, cgit_query_path, |
121 | ofs - cnt); | 121 | ofs - cnt, cgit_query_grep, |
122 | cgit_query_search); | ||
122 | html(" "); | 123 | html(" "); |
123 | } | 124 | } |
124 | if ((commit = get_revision(&rev)) != NULL) { | 125 | if ((commit = get_revision(&rev)) != NULL) { |
125 | cgit_log_link("[next]", NULL, NULL, cgit_query_head, | 126 | cgit_log_link("[next]", NULL, NULL, cgit_query_head, |
126 | cgit_query_sha1, cgit_query_path, | 127 | cgit_query_sha1, cgit_query_path, |
127 | ofs + cnt); | 128 | ofs + cnt, cgit_query_grep, |
129 | cgit_query_search); | ||
128 | } | 130 | } |
129 | html("</div>"); | 131 | html("</div>"); |
130 | } | 132 | } |
131 | } | 133 | } |
diff --git a/ui-repolist.c b/ui-repolist.c index 4c86543..9aa5c1e 100644 --- a/ui-repolist.c +++ b/ui-repolist.c | |||
@@ -1,109 +1,110 @@ | |||
1 | /* ui-repolist.c: functions for generating the repolist page | 1 | /* ui-repolist.c: functions for generating the repolist page |
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 | #include <time.h> | 10 | #include <time.h> |
11 | 11 | ||
12 | 12 | ||
13 | time_t read_agefile(char *path) | 13 | time_t read_agefile(char *path) |
14 | { | 14 | { |
15 | FILE *f; | 15 | FILE *f; |
16 | static char buf[64], buf2[64]; | 16 | static char buf[64], buf2[64]; |
17 | 17 | ||
18 | if (!(f = fopen(path, "r"))) | 18 | if (!(f = fopen(path, "r"))) |
19 | return -1; | 19 | return -1; |
20 | fgets(buf, sizeof(buf), f); | 20 | fgets(buf, sizeof(buf), f); |
21 | fclose(f); | 21 | fclose(f); |
22 | if (parse_date(buf, buf2, sizeof(buf2))) | 22 | if (parse_date(buf, buf2, sizeof(buf2))) |
23 | return strtoul(buf2, NULL, 10); | 23 | return strtoul(buf2, NULL, 10); |
24 | else | 24 | else |
25 | return 0; | 25 | return 0; |
26 | } | 26 | } |
27 | 27 | ||
28 | static void print_modtime(struct repoinfo *repo) | 28 | static void print_modtime(struct repoinfo *repo) |
29 | { | 29 | { |
30 | char *path; | 30 | char *path; |
31 | struct stat s; | 31 | struct stat s; |
32 | 32 | ||
33 | path = fmt("%s/%s", repo->path, cgit_agefile); | 33 | path = fmt("%s/%s", repo->path, cgit_agefile); |
34 | if (stat(path, &s) == 0) { | 34 | if (stat(path, &s) == 0) { |
35 | cgit_print_age(read_agefile(path), -1, NULL); | 35 | cgit_print_age(read_agefile(path), -1, NULL); |
36 | return; | 36 | return; |
37 | } | 37 | } |
38 | 38 | ||
39 | path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); | 39 | path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); |
40 | if (stat(path, &s) != 0) | 40 | if (stat(path, &s) != 0) |
41 | return; | 41 | return; |
42 | cgit_print_age(s.st_mtime, -1, NULL); | 42 | cgit_print_age(s.st_mtime, -1, NULL); |
43 | } | 43 | } |
44 | 44 | ||
45 | void cgit_print_repolist(struct cacheitem *item) | 45 | void cgit_print_repolist(struct cacheitem *item) |
46 | { | 46 | { |
47 | int i, columns = 4; | 47 | int i, columns = 4; |
48 | char *last_group = NULL; | 48 | char *last_group = NULL; |
49 | 49 | ||
50 | if (cgit_enable_index_links) | 50 | if (cgit_enable_index_links) |
51 | columns++; | 51 | columns++; |
52 | 52 | ||
53 | cgit_print_docstart(cgit_root_title, item); | 53 | cgit_print_docstart(cgit_root_title, item); |
54 | cgit_print_pageheader(cgit_root_title, 0); | 54 | cgit_print_pageheader(cgit_root_title, 0); |
55 | 55 | ||
56 | html("<table class='list nowrap'>"); | 56 | html("<table class='list nowrap'>"); |
57 | if (cgit_index_header) { | 57 | if (cgit_index_header) { |
58 | htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>", | 58 | htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>", |
59 | columns); | 59 | columns); |
60 | html_include(cgit_index_header); | 60 | html_include(cgit_index_header); |
61 | html("</td></tr>"); | 61 | html("</td></tr>"); |
62 | } | 62 | } |
63 | html("<tr class='nohover'>" | 63 | html("<tr class='nohover'>" |
64 | "<th class='left'>Name</th>" | 64 | "<th class='left'>Name</th>" |
65 | "<th class='left'>Description</th>" | 65 | "<th class='left'>Description</th>" |
66 | "<th class='left'>Owner</th>" | 66 | "<th class='left'>Owner</th>" |
67 | "<th class='left'>Idle</th>"); | 67 | "<th class='left'>Idle</th>"); |
68 | if (cgit_enable_index_links) | 68 | if (cgit_enable_index_links) |
69 | html("<th>Links</th>"); | 69 | html("<th>Links</th>"); |
70 | html("</tr>\n"); | 70 | html("</tr>\n"); |
71 | 71 | ||
72 | for (i=0; i<cgit_repolist.count; i++) { | 72 | for (i=0; i<cgit_repolist.count; i++) { |
73 | cgit_repo = &cgit_repolist.repos[i]; | 73 | cgit_repo = &cgit_repolist.repos[i]; |
74 | if ((last_group == NULL && cgit_repo->group != NULL) || | 74 | if ((last_group == NULL && cgit_repo->group != NULL) || |
75 | (last_group != NULL && cgit_repo->group == NULL) || | 75 | (last_group != NULL && cgit_repo->group == NULL) || |
76 | (last_group != NULL && cgit_repo->group != NULL && | 76 | (last_group != NULL && cgit_repo->group != NULL && |
77 | strcmp(cgit_repo->group, last_group))) { | 77 | strcmp(cgit_repo->group, last_group))) { |
78 | htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", | 78 | htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", |
79 | columns); | 79 | columns); |
80 | html_txt(cgit_repo->group); | 80 | html_txt(cgit_repo->group); |
81 | html("</td></tr>"); | 81 | html("</td></tr>"); |
82 | last_group = cgit_repo->group; | 82 | last_group = cgit_repo->group; |
83 | } | 83 | } |
84 | htmlf("<tr><td class='%s'>", | 84 | htmlf("<tr><td class='%s'>", |
85 | cgit_repo->group ? "sublevel-repo" : "toplevel-repo"); | 85 | cgit_repo->group ? "sublevel-repo" : "toplevel-repo"); |
86 | html_link_open(cgit_repourl(cgit_repo->url), NULL, NULL); | 86 | html_link_open(cgit_repourl(cgit_repo->url), NULL, NULL); |
87 | html_txt(cgit_repo->name); | 87 | html_txt(cgit_repo->name); |
88 | html_link_close(); | 88 | html_link_close(); |
89 | html("</td><td>"); | 89 | html("</td><td>"); |
90 | html_ntxt(cgit_max_repodesc_len, cgit_repo->desc); | 90 | html_ntxt(cgit_max_repodesc_len, cgit_repo->desc); |
91 | html("</td><td>"); | 91 | html("</td><td>"); |
92 | html_txt(cgit_repo->owner); | 92 | html_txt(cgit_repo->owner); |
93 | html("</td><td>"); | 93 | html("</td><td>"); |
94 | print_modtime(cgit_repo); | 94 | print_modtime(cgit_repo); |
95 | html("</td>"); | 95 | html("</td>"); |
96 | if (cgit_enable_index_links) { | 96 | if (cgit_enable_index_links) { |
97 | html("<td>"); | 97 | html("<td>"); |
98 | html_link_open(cgit_repourl(cgit_repo->url), | 98 | html_link_open(cgit_repourl(cgit_repo->url), |
99 | NULL, "button"); | 99 | NULL, "button"); |
100 | html("summary</a>"); | 100 | html("summary</a>"); |
101 | cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 0); | 101 | cgit_log_link("log", NULL, "button", NULL, NULL, NULL, |
102 | 0, NULL, NULL); | ||
102 | cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); | 103 | cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); |
103 | html("</td>"); | 104 | html("</td>"); |
104 | } | 105 | } |
105 | html("</tr>\n"); | 106 | html("</tr>\n"); |
106 | } | 107 | } |
107 | html("</table>"); | 108 | html("</table>"); |
108 | cgit_print_docend(); | 109 | cgit_print_docend(); |
109 | } | 110 | } |
diff --git a/ui-shared.c b/ui-shared.c index 1d66940..a03661a 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -1,519 +1,528 @@ | |||
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_rooturl() | 43 | char *cgit_rooturl() |
44 | { | 44 | { |
45 | if (cgit_virtual_root) | 45 | if (cgit_virtual_root) |
46 | return fmt("%s/", cgit_virtual_root); | 46 | return fmt("%s/", cgit_virtual_root); |
47 | else | 47 | else |
48 | return cgit_script_name; | 48 | return cgit_script_name; |
49 | } | 49 | } |
50 | 50 | ||
51 | char *cgit_repourl(const char *reponame) | 51 | char *cgit_repourl(const char *reponame) |
52 | { | 52 | { |
53 | if (cgit_virtual_root) { | 53 | if (cgit_virtual_root) { |
54 | return fmt("%s/%s/", cgit_virtual_root, reponame); | 54 | return fmt("%s/%s/", cgit_virtual_root, reponame); |
55 | } else { | 55 | } else { |
56 | return fmt("?r=%s", reponame); | 56 | return fmt("?r=%s", reponame); |
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | char *cgit_fileurl(const char *reponame, const char *pagename, | 60 | char *cgit_fileurl(const char *reponame, const char *pagename, |
61 | const char *filename, const char *query) | 61 | const char *filename, const char *query) |
62 | { | 62 | { |
63 | if (cgit_virtual_root) { | 63 | if (cgit_virtual_root) { |
64 | if (query) | 64 | if (query) |
65 | return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame, | 65 | return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame, |
66 | pagename, filename?filename:"", query); | 66 | pagename, filename?filename:"", query); |
67 | else | 67 | else |
68 | return fmt("%s/%s/%s/", cgit_virtual_root, reponame, | 68 | return fmt("%s/%s/%s/", cgit_virtual_root, reponame, |
69 | pagename); | 69 | pagename); |
70 | } else { | 70 | } else { |
71 | if (query) | 71 | if (query) |
72 | return fmt("?r=%s&p=%s&%s", reponame, pagename, query); | 72 | return fmt("?r=%s&p=%s&%s", reponame, pagename, query); |
73 | else | 73 | else |
74 | return fmt("?r=%s&p=%s", reponame, pagename); | 74 | return fmt("?r=%s&p=%s", reponame, pagename); |
75 | } | 75 | } |
76 | } | 76 | } |
77 | 77 | ||
78 | char *cgit_pageurl(const char *reponame, const char *pagename, | 78 | char *cgit_pageurl(const char *reponame, const char *pagename, |
79 | const char *query) | 79 | const char *query) |
80 | { | 80 | { |
81 | return cgit_fileurl(reponame,pagename,0,query); | 81 | return cgit_fileurl(reponame,pagename,0,query); |
82 | } | 82 | } |
83 | 83 | ||
84 | const char *cgit_repobasename(const char *reponame) | 84 | const char *cgit_repobasename(const char *reponame) |
85 | { | 85 | { |
86 | /* I assume we don't need to store more than one repo basename */ | 86 | /* I assume we don't need to store more than one repo basename */ |
87 | static char rvbuf[1024]; | 87 | static char rvbuf[1024]; |
88 | int p; | 88 | int p; |
89 | const char *rv; | 89 | const char *rv; |
90 | strncpy(rvbuf,reponame,sizeof(rvbuf)); | 90 | strncpy(rvbuf,reponame,sizeof(rvbuf)); |
91 | if(rvbuf[sizeof(rvbuf)-1]) | 91 | if(rvbuf[sizeof(rvbuf)-1]) |
92 | die("cgit_repobasename: truncated repository name '%s'", reponame); | 92 | die("cgit_repobasename: truncated repository name '%s'", reponame); |
93 | p = strlen(rvbuf)-1; | 93 | p = strlen(rvbuf)-1; |
94 | /* strip trailing slashes */ | 94 | /* strip trailing slashes */ |
95 | while(p && rvbuf[p]=='/') rvbuf[p--]=0; | 95 | while(p && rvbuf[p]=='/') rvbuf[p--]=0; |
96 | /* strip trailing .git */ | 96 | /* strip trailing .git */ |
97 | if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) { | 97 | if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) { |
98 | p -= 3; rvbuf[p--] = 0; | 98 | p -= 3; rvbuf[p--] = 0; |
99 | } | 99 | } |
100 | /* strip more trailing slashes if any */ | 100 | /* strip more trailing slashes if any */ |
101 | while( p && rvbuf[p]=='/') rvbuf[p--]=0; | 101 | while( p && rvbuf[p]=='/') rvbuf[p--]=0; |
102 | /* find last slash in the remaining string */ | 102 | /* find last slash in the remaining string */ |
103 | rv = strrchr(rvbuf,'/'); | 103 | rv = strrchr(rvbuf,'/'); |
104 | if(rv) | 104 | if(rv) |
105 | return ++rv; | 105 | return ++rv; |
106 | return rvbuf; | 106 | return rvbuf; |
107 | } | 107 | } |
108 | 108 | ||
109 | char *cgit_currurl() | 109 | char *cgit_currurl() |
110 | { | 110 | { |
111 | if (!cgit_virtual_root) | 111 | if (!cgit_virtual_root) |
112 | return cgit_script_name; | 112 | return cgit_script_name; |
113 | else if (cgit_query_page) | 113 | else if (cgit_query_page) |
114 | return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); | 114 | return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); |
115 | else if (cgit_query_repo) | 115 | else if (cgit_query_repo) |
116 | return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); | 116 | return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); |
117 | else | 117 | else |
118 | return fmt("%s/", cgit_virtual_root); | 118 | return fmt("%s/", cgit_virtual_root); |
119 | } | 119 | } |
120 | 120 | ||
121 | static char *repolink(char *title, char *class, char *page, char *head, | 121 | static char *repolink(char *title, char *class, char *page, char *head, |
122 | char *path) | 122 | char *path) |
123 | { | 123 | { |
124 | char *delim = "?"; | 124 | char *delim = "?"; |
125 | 125 | ||
126 | html("<a"); | 126 | html("<a"); |
127 | if (title) { | 127 | if (title) { |
128 | html(" title='"); | 128 | html(" title='"); |
129 | html_attr(title); | 129 | html_attr(title); |
130 | html("'"); | 130 | html("'"); |
131 | } | 131 | } |
132 | if (class) { | 132 | if (class) { |
133 | html(" class='"); | 133 | html(" class='"); |
134 | html_attr(class); | 134 | html_attr(class); |
135 | html("'"); | 135 | html("'"); |
136 | } | 136 | } |
137 | html(" href='"); | 137 | html(" href='"); |
138 | if (cgit_virtual_root) { | 138 | if (cgit_virtual_root) { |
139 | html_attr(cgit_virtual_root); | 139 | html_attr(cgit_virtual_root); |
140 | if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/') | 140 | if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/') |
141 | html("/"); | 141 | html("/"); |
142 | html_attr(cgit_repo->url); | 142 | html_attr(cgit_repo->url); |
143 | if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') | 143 | if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') |
144 | html("/"); | 144 | html("/"); |
145 | if (page) { | 145 | if (page) { |
146 | html(page); | 146 | html(page); |
147 | html("/"); | 147 | html("/"); |
148 | if (path) | 148 | if (path) |
149 | html_attr(path); | 149 | html_attr(path); |
150 | } | 150 | } |
151 | } else { | 151 | } else { |
152 | html(cgit_script_name); | 152 | html(cgit_script_name); |
153 | html("?url="); | 153 | html("?url="); |
154 | html_attr(cgit_repo->url); | 154 | html_attr(cgit_repo->url); |
155 | if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') | 155 | if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') |
156 | html("/"); | 156 | html("/"); |
157 | if (page) { | 157 | if (page) { |
158 | html(page); | 158 | html(page); |
159 | html("/"); | 159 | html("/"); |
160 | if (path) | 160 | if (path) |
161 | html_attr(path); | 161 | html_attr(path); |
162 | } | 162 | } |
163 | delim = "&"; | 163 | delim = "&"; |
164 | } | 164 | } |
165 | if (head && strcmp(head, cgit_repo->defbranch)) { | 165 | if (head && strcmp(head, cgit_repo->defbranch)) { |
166 | html(delim); | 166 | html(delim); |
167 | html("h="); | 167 | html("h="); |
168 | html_attr(head); | 168 | html_attr(head); |
169 | delim = "&"; | 169 | delim = "&"; |
170 | } | 170 | } |
171 | return fmt("%s", delim); | 171 | return fmt("%s", delim); |
172 | } | 172 | } |
173 | 173 | ||
174 | static void reporevlink(char *page, char *name, char *title, char *class, | 174 | static void reporevlink(char *page, char *name, char *title, char *class, |
175 | char *head, char *rev, char *path) | 175 | char *head, char *rev, char *path) |
176 | { | 176 | { |
177 | char *delim; | 177 | char *delim; |
178 | 178 | ||
179 | delim = repolink(title, class, page, head, path); | 179 | delim = repolink(title, class, page, head, path); |
180 | if (rev && strcmp(rev, cgit_query_head)) { | 180 | if (rev && strcmp(rev, cgit_query_head)) { |
181 | html(delim); | 181 | html(delim); |
182 | html("id="); | 182 | html("id="); |
183 | html_attr(rev); | 183 | html_attr(rev); |
184 | } | 184 | } |
185 | html("'>"); | 185 | html("'>"); |
186 | html_txt(name); | 186 | html_txt(name); |
187 | html("</a>"); | 187 | html("</a>"); |
188 | } | 188 | } |
189 | 189 | ||
190 | void cgit_tree_link(char *name, char *title, char *class, char *head, | 190 | void cgit_tree_link(char *name, char *title, char *class, char *head, |
191 | char *rev, char *path) | 191 | char *rev, char *path) |
192 | { | 192 | { |
193 | reporevlink("tree", name, title, class, head, rev, path); | 193 | reporevlink("tree", name, title, class, head, rev, path); |
194 | } | 194 | } |
195 | 195 | ||
196 | void cgit_log_link(char *name, char *title, char *class, char *head, | 196 | void cgit_log_link(char *name, char *title, char *class, char *head, |
197 | char *rev, char *path, int ofs) | 197 | char *rev, char *path, int ofs, char *grep, char *pattern) |
198 | { | 198 | { |
199 | char *delim; | 199 | char *delim; |
200 | 200 | ||
201 | delim = repolink(title, class, "log", head, path); | 201 | delim = repolink(title, class, "log", head, path); |
202 | if (rev && strcmp(rev, cgit_query_head)) { | 202 | if (rev && strcmp(rev, cgit_query_head)) { |
203 | html(delim); | 203 | html(delim); |
204 | html("id="); | 204 | html("id="); |
205 | html_attr(rev); | 205 | html_attr(rev); |
206 | delim = "&"; | 206 | delim = "&"; |
207 | } | 207 | } |
208 | if (grep && pattern) { | ||
209 | html(delim); | ||
210 | html("qt="); | ||
211 | html_attr(grep); | ||
212 | delim = "&"; | ||
213 | html(delim); | ||
214 | html("q="); | ||
215 | html_attr(pattern); | ||
216 | } | ||
208 | if (ofs > 0) { | 217 | if (ofs > 0) { |
209 | html(delim); | 218 | html(delim); |
210 | html("ofs="); | 219 | html("ofs="); |
211 | htmlf("%d", ofs); | 220 | htmlf("%d", ofs); |
212 | } | 221 | } |
213 | html("'>"); | 222 | html("'>"); |
214 | html_txt(name); | 223 | html_txt(name); |
215 | html("</a>"); | 224 | html("</a>"); |
216 | } | 225 | } |
217 | 226 | ||
218 | void cgit_commit_link(char *name, char *title, char *class, char *head, | 227 | void cgit_commit_link(char *name, char *title, char *class, char *head, |
219 | char *rev) | 228 | char *rev) |
220 | { | 229 | { |
221 | if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) { | 230 | if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) { |
222 | name[cgit_max_msg_len] = '\0'; | 231 | name[cgit_max_msg_len] = '\0'; |
223 | name[cgit_max_msg_len - 1] = '.'; | 232 | name[cgit_max_msg_len - 1] = '.'; |
224 | name[cgit_max_msg_len - 2] = '.'; | 233 | name[cgit_max_msg_len - 2] = '.'; |
225 | name[cgit_max_msg_len - 3] = '.'; | 234 | name[cgit_max_msg_len - 3] = '.'; |
226 | } | 235 | } |
227 | reporevlink("commit", name, title, class, head, rev, NULL); | 236 | reporevlink("commit", name, title, class, head, rev, NULL); |
228 | } | 237 | } |
229 | 238 | ||
230 | void cgit_refs_link(char *name, char *title, char *class, char *head, | 239 | void cgit_refs_link(char *name, char *title, char *class, char *head, |
231 | char *rev, char *path) | 240 | char *rev, char *path) |
232 | { | 241 | { |
233 | reporevlink("refs", name, title, class, head, rev, path); | 242 | reporevlink("refs", name, title, class, head, rev, path); |
234 | } | 243 | } |
235 | 244 | ||
236 | void cgit_snapshot_link(char *name, char *title, char *class, char *head, | 245 | void cgit_snapshot_link(char *name, char *title, char *class, char *head, |
237 | char *rev, char *archivename) | 246 | char *rev, char *archivename) |
238 | { | 247 | { |
239 | reporevlink("snapshot", name, title, class, head, rev, archivename); | 248 | reporevlink("snapshot", name, title, class, head, rev, archivename); |
240 | } | 249 | } |
241 | 250 | ||
242 | void cgit_diff_link(char *name, char *title, char *class, char *head, | 251 | void cgit_diff_link(char *name, char *title, char *class, char *head, |
243 | char *new_rev, char *old_rev, char *path) | 252 | char *new_rev, char *old_rev, char *path) |
244 | { | 253 | { |
245 | char *delim; | 254 | char *delim; |
246 | 255 | ||
247 | delim = repolink(title, class, "diff", head, path); | 256 | delim = repolink(title, class, "diff", head, path); |
248 | if (new_rev && strcmp(new_rev, cgit_query_head)) { | 257 | if (new_rev && strcmp(new_rev, cgit_query_head)) { |
249 | html(delim); | 258 | html(delim); |
250 | html("id="); | 259 | html("id="); |
251 | html_attr(new_rev); | 260 | html_attr(new_rev); |
252 | delim = "&"; | 261 | delim = "&"; |
253 | } | 262 | } |
254 | if (old_rev) { | 263 | if (old_rev) { |
255 | html(delim); | 264 | html(delim); |
256 | html("id2="); | 265 | html("id2="); |
257 | html_attr(old_rev); | 266 | html_attr(old_rev); |
258 | } | 267 | } |
259 | html("'>"); | 268 | html("'>"); |
260 | html_txt(name); | 269 | html_txt(name); |
261 | html("</a>"); | 270 | html("</a>"); |
262 | } | 271 | } |
263 | 272 | ||
264 | void cgit_object_link(struct object *obj) | 273 | void cgit_object_link(struct object *obj) |
265 | { | 274 | { |
266 | char *page, *arg, *url; | 275 | char *page, *arg, *url; |
267 | 276 | ||
268 | if (obj->type == OBJ_COMMIT) { | 277 | if (obj->type == OBJ_COMMIT) { |
269 | cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, | 278 | cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, |
270 | cgit_query_head, sha1_to_hex(obj->sha1)); | 279 | cgit_query_head, sha1_to_hex(obj->sha1)); |
271 | return; | 280 | return; |
272 | } else if (obj->type == OBJ_TREE) { | 281 | } else if (obj->type == OBJ_TREE) { |
273 | page = "tree"; | 282 | page = "tree"; |
274 | arg = "id"; | 283 | arg = "id"; |
275 | } else if (obj->type == OBJ_TAG) { | 284 | } else if (obj->type == OBJ_TAG) { |
276 | page = "tag"; | 285 | page = "tag"; |
277 | arg = "id"; | 286 | arg = "id"; |
278 | } else { | 287 | } else { |
279 | page = "blob"; | 288 | page = "blob"; |
280 | arg = "id"; | 289 | arg = "id"; |
281 | } | 290 | } |
282 | 291 | ||
283 | url = cgit_pageurl(cgit_query_repo, page, | 292 | url = cgit_pageurl(cgit_query_repo, page, |
284 | fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); | 293 | fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); |
285 | html_link_open(url, NULL, NULL); | 294 | html_link_open(url, NULL, NULL); |
286 | htmlf("%s %s", typename(obj->type), | 295 | htmlf("%s %s", typename(obj->type), |
287 | sha1_to_hex(obj->sha1)); | 296 | sha1_to_hex(obj->sha1)); |
288 | html_link_close(); | 297 | html_link_close(); |
289 | } | 298 | } |
290 | 299 | ||
291 | void cgit_print_date(time_t secs, char *format) | 300 | void cgit_print_date(time_t secs, char *format) |
292 | { | 301 | { |
293 | char buf[64]; | 302 | char buf[64]; |
294 | struct tm *time; | 303 | struct tm *time; |
295 | 304 | ||
296 | time = gmtime(&secs); | 305 | time = gmtime(&secs); |
297 | strftime(buf, sizeof(buf)-1, format, time); | 306 | strftime(buf, sizeof(buf)-1, format, time); |
298 | html_txt(buf); | 307 | html_txt(buf); |
299 | } | 308 | } |
300 | 309 | ||
301 | void cgit_print_age(time_t t, time_t max_relative, char *format) | 310 | void cgit_print_age(time_t t, time_t max_relative, char *format) |
302 | { | 311 | { |
303 | time_t now, secs; | 312 | time_t now, secs; |
304 | 313 | ||
305 | time(&now); | 314 | time(&now); |
306 | secs = now - t; | 315 | secs = now - t; |
307 | 316 | ||
308 | if (secs > max_relative && max_relative >= 0) { | 317 | if (secs > max_relative && max_relative >= 0) { |
309 | cgit_print_date(t, format); | 318 | cgit_print_date(t, format); |
310 | return; | 319 | return; |
311 | } | 320 | } |
312 | 321 | ||
313 | if (secs < TM_HOUR * 2) { | 322 | if (secs < TM_HOUR * 2) { |
314 | htmlf("<span class='age-mins'>%.0f min.</span>", | 323 | htmlf("<span class='age-mins'>%.0f min.</span>", |
315 | secs * 1.0 / TM_MIN); | 324 | secs * 1.0 / TM_MIN); |
316 | return; | 325 | return; |
317 | } | 326 | } |
318 | if (secs < TM_DAY * 2) { | 327 | if (secs < TM_DAY * 2) { |
319 | htmlf("<span class='age-hours'>%.0f hours</span>", | 328 | htmlf("<span class='age-hours'>%.0f hours</span>", |
320 | secs * 1.0 / TM_HOUR); | 329 | secs * 1.0 / TM_HOUR); |
321 | return; | 330 | return; |
322 | } | 331 | } |
323 | if (secs < TM_WEEK * 2) { | 332 | if (secs < TM_WEEK * 2) { |
324 | htmlf("<span class='age-days'>%.0f days</span>", | 333 | htmlf("<span class='age-days'>%.0f days</span>", |
325 | secs * 1.0 / TM_DAY); | 334 | secs * 1.0 / TM_DAY); |
326 | return; | 335 | return; |
327 | } | 336 | } |
328 | if (secs < TM_MONTH * 2) { | 337 | if (secs < TM_MONTH * 2) { |
329 | htmlf("<span class='age-weeks'>%.0f weeks</span>", | 338 | htmlf("<span class='age-weeks'>%.0f weeks</span>", |
330 | secs * 1.0 / TM_WEEK); | 339 | secs * 1.0 / TM_WEEK); |
331 | return; | 340 | return; |
332 | } | 341 | } |
333 | if (secs < TM_YEAR * 2) { | 342 | if (secs < TM_YEAR * 2) { |
334 | htmlf("<span class='age-months'>%.0f months</span>", | 343 | htmlf("<span class='age-months'>%.0f months</span>", |
335 | secs * 1.0 / TM_MONTH); | 344 | secs * 1.0 / TM_MONTH); |
336 | return; | 345 | return; |
337 | } | 346 | } |
338 | htmlf("<span class='age-years'>%.0f years</span>", | 347 | htmlf("<span class='age-years'>%.0f years</span>", |
339 | secs * 1.0 / TM_YEAR); | 348 | secs * 1.0 / TM_YEAR); |
340 | } | 349 | } |
341 | 350 | ||
342 | void cgit_print_docstart(char *title, struct cacheitem *item) | 351 | void cgit_print_docstart(char *title, struct cacheitem *item) |
343 | { | 352 | { |
344 | html("Content-Type: text/html; charset=utf-8\n"); | 353 | html("Content-Type: text/html; charset=utf-8\n"); |
345 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); | 354 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); |
346 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + | 355 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + |
347 | ttl_seconds(item->ttl))); | 356 | ttl_seconds(item->ttl))); |
348 | html("\n"); | 357 | html("\n"); |
349 | html(cgit_doctype); | 358 | html(cgit_doctype); |
350 | html("<html>\n"); | 359 | html("<html>\n"); |
351 | html("<head>\n"); | 360 | html("<head>\n"); |
352 | html("<title>"); | 361 | html("<title>"); |
353 | html_txt(title); | 362 | html_txt(title); |
354 | html("</title>\n"); | 363 | html("</title>\n"); |
355 | htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); | 364 | htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); |
356 | html("<link rel='stylesheet' type='text/css' href='"); | 365 | html("<link rel='stylesheet' type='text/css' href='"); |
357 | html_attr(cgit_css); | 366 | html_attr(cgit_css); |
358 | html("'/>\n"); | 367 | html("'/>\n"); |
359 | html("</head>\n"); | 368 | html("</head>\n"); |
360 | html("<body>\n"); | 369 | html("<body>\n"); |
361 | } | 370 | } |
362 | 371 | ||
363 | void cgit_print_docend() | 372 | void cgit_print_docend() |
364 | { | 373 | { |
365 | html("</td>\n</tr>\n<table>\n</body>\n</html>\n"); | 374 | html("</td>\n</tr>\n<table>\n</body>\n</html>\n"); |
366 | } | 375 | } |
367 | 376 | ||
368 | int print_branch_option(const char *refname, const unsigned char *sha1, | 377 | int print_branch_option(const char *refname, const unsigned char *sha1, |
369 | int flags, void *cb_data) | 378 | int flags, void *cb_data) |
370 | { | 379 | { |
371 | char *name = (char *)refname; | 380 | char *name = (char *)refname; |
372 | html_option(name, name, cgit_query_head); | 381 | html_option(name, name, cgit_query_head); |
373 | return 0; | 382 | return 0; |
374 | } | 383 | } |
375 | 384 | ||
376 | int print_archive_ref(const char *refname, const unsigned char *sha1, | 385 | int print_archive_ref(const char *refname, const unsigned char *sha1, |
377 | int flags, void *cb_data) | 386 | int flags, void *cb_data) |
378 | { | 387 | { |
379 | struct tag *tag; | 388 | struct tag *tag; |
380 | struct taginfo *info; | 389 | struct taginfo *info; |
381 | struct object *obj; | 390 | struct object *obj; |
382 | char buf[256], *url; | 391 | char buf[256], *url; |
383 | unsigned char fileid[20]; | 392 | unsigned char fileid[20]; |
384 | int *header = (int *)cb_data; | 393 | int *header = (int *)cb_data; |
385 | 394 | ||
386 | if (prefixcmp(refname, "refs/archives")) | 395 | if (prefixcmp(refname, "refs/archives")) |
387 | return 0; | 396 | return 0; |
388 | strncpy(buf, refname+14, sizeof(buf)); | 397 | strncpy(buf, refname+14, sizeof(buf)); |
389 | obj = parse_object(sha1); | 398 | obj = parse_object(sha1); |
390 | if (!obj) | 399 | if (!obj) |
391 | return 1; | 400 | return 1; |
392 | if (obj->type == OBJ_TAG) { | 401 | if (obj->type == OBJ_TAG) { |
393 | tag = lookup_tag(sha1); | 402 | tag = lookup_tag(sha1); |
394 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) | 403 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) |
395 | return 0; | 404 | return 0; |
396 | hashcpy(fileid, tag->tagged->sha1); | 405 | hashcpy(fileid, tag->tagged->sha1); |
397 | } else if (obj->type != OBJ_BLOB) { | 406 | } else if (obj->type != OBJ_BLOB) { |
398 | return 0; | 407 | return 0; |
399 | } else { | 408 | } else { |
400 | hashcpy(fileid, sha1); | 409 | hashcpy(fileid, sha1); |
401 | } | 410 | } |
402 | if (!*header) { | 411 | if (!*header) { |
403 | html("<p><h1>download</h1>"); | 412 | html("<p><h1>download</h1>"); |
404 | *header = 1; | 413 | *header = 1; |
405 | } | 414 | } |
406 | url = cgit_pageurl(cgit_query_repo, "blob", | 415 | url = cgit_pageurl(cgit_query_repo, "blob", |
407 | fmt("id=%s&path=%s", sha1_to_hex(fileid), | 416 | fmt("id=%s&path=%s", sha1_to_hex(fileid), |
408 | buf)); | 417 | buf)); |
409 | html_link_open(url, NULL, "menu"); | 418 | html_link_open(url, NULL, "menu"); |
410 | html_txt(strlpart(buf, 20)); | 419 | html_txt(strlpart(buf, 20)); |
411 | html_link_close(); | 420 | html_link_close(); |
412 | return 0; | 421 | return 0; |
413 | } | 422 | } |
414 | 423 | ||
415 | void add_hidden_formfields(int incl_head, int incl_search) | 424 | void add_hidden_formfields(int incl_head, int incl_search) |
416 | { | 425 | { |
417 | if (!cgit_virtual_root) { | 426 | if (!cgit_virtual_root) { |
418 | if (cgit_query_repo) | 427 | if (cgit_query_repo) |
419 | html_hidden("r", cgit_query_repo); | 428 | html_hidden("r", cgit_query_repo); |
420 | if (cgit_query_page) | 429 | if (cgit_query_page) |
421 | html_hidden("p", cgit_query_page); | 430 | html_hidden("p", cgit_query_page); |
422 | } | 431 | } |
423 | 432 | ||
424 | if (incl_head && strcmp(cgit_query_head, cgit_repo->defbranch)) | 433 | if (incl_head && strcmp(cgit_query_head, cgit_repo->defbranch)) |
425 | html_hidden("h", cgit_query_head); | 434 | html_hidden("h", cgit_query_head); |
426 | 435 | ||
427 | if (cgit_query_sha1) | 436 | if (cgit_query_sha1) |
428 | html_hidden("id", cgit_query_sha1); | 437 | html_hidden("id", cgit_query_sha1); |
429 | if (cgit_query_sha2) | 438 | if (cgit_query_sha2) |
430 | html_hidden("id2", cgit_query_sha2); | 439 | html_hidden("id2", cgit_query_sha2); |
431 | 440 | ||
432 | if (incl_search) { | 441 | if (incl_search) { |
433 | if (cgit_query_grep) | 442 | if (cgit_query_grep) |
434 | html_hidden("qt", cgit_query_grep); | 443 | html_hidden("qt", cgit_query_grep); |
435 | if (cgit_query_search) | 444 | if (cgit_query_search) |
436 | html_hidden("q", cgit_query_search); | 445 | html_hidden("q", cgit_query_search); |
437 | } | 446 | } |
438 | } | 447 | } |
439 | 448 | ||
440 | void cgit_print_pageheader(char *title, int show_search) | 449 | void cgit_print_pageheader(char *title, int show_search) |
441 | { | 450 | { |
442 | static const char *default_info = "This is cgit, a fast webinterface for git repositories"; | 451 | static const char *default_info = "This is cgit, a fast webinterface for git repositories"; |
443 | int header = 0; | 452 | int header = 0; |
444 | 453 | ||
445 | html("<div id='sidebar'>\n"); | 454 | html("<div id='sidebar'>\n"); |
446 | html("<a href='"); | 455 | html("<a href='"); |
447 | html_attr(cgit_rooturl()); | 456 | html_attr(cgit_rooturl()); |
448 | htmlf("'><div id='logo'><img src='%s' alt='cgit'/></div></a>\n", | 457 | htmlf("'><div id='logo'><img src='%s' alt='cgit'/></div></a>\n", |
449 | cgit_logo); | 458 | cgit_logo); |
450 | html("<div class='infobox'>"); | 459 | html("<div class='infobox'>"); |
451 | if (cgit_query_repo) { | 460 | if (cgit_query_repo) { |
452 | html("<h1>"); | 461 | html("<h1>"); |
453 | html_txt(strrpart(cgit_repo->name, 20)); | 462 | html_txt(strrpart(cgit_repo->name, 20)); |
454 | html("</h1>\n"); | 463 | html("</h1>\n"); |
455 | html_txt(cgit_repo->desc); | 464 | html_txt(cgit_repo->desc); |
456 | if (cgit_repo->owner) { | 465 | if (cgit_repo->owner) { |
457 | html("<p>\n<h1>owner</h1>\n"); | 466 | html("<p>\n<h1>owner</h1>\n"); |
458 | html_txt(cgit_repo->owner); | 467 | html_txt(cgit_repo->owner); |
459 | } | 468 | } |
460 | html("<p>\n<h1>navigate</h1>\n"); | 469 | html("<p>\n<h1>navigate</h1>\n"); |
461 | reporevlink(NULL, "summary", NULL, "menu", cgit_query_head, | 470 | reporevlink(NULL, "summary", NULL, "menu", cgit_query_head, |
462 | NULL, NULL); | 471 | NULL, NULL); |
463 | cgit_log_link("log", NULL, "menu", cgit_query_head, | 472 | cgit_log_link("log", NULL, "menu", cgit_query_head, |
464 | cgit_query_sha1, cgit_query_path, 0); | 473 | cgit_query_sha1, cgit_query_path, 0, NULL, NULL); |
465 | cgit_tree_link("tree", NULL, "menu", cgit_query_head, | 474 | cgit_tree_link("tree", NULL, "menu", cgit_query_head, |
466 | cgit_query_sha1, NULL); | 475 | cgit_query_sha1, NULL); |
467 | cgit_commit_link("commit", NULL, "menu", cgit_query_head, | 476 | cgit_commit_link("commit", NULL, "menu", cgit_query_head, |
468 | cgit_query_sha1); | 477 | cgit_query_sha1); |
469 | cgit_diff_link("diff", NULL, "menu", cgit_query_head, | 478 | cgit_diff_link("diff", NULL, "menu", cgit_query_head, |
470 | cgit_query_sha1, cgit_query_sha2, | 479 | cgit_query_sha1, cgit_query_sha2, |
471 | cgit_query_path); | 480 | cgit_query_path); |
472 | 481 | ||
473 | for_each_ref(print_archive_ref, &header); | 482 | for_each_ref(print_archive_ref, &header); |
474 | 483 | ||
475 | html("<p>\n<h1>branch</h1>\n"); | 484 | html("<p>\n<h1>branch</h1>\n"); |
476 | html("<form method='get' action=''>\n"); | 485 | html("<form method='get' action=''>\n"); |
477 | add_hidden_formfields(0, 1); | 486 | add_hidden_formfields(0, 1); |
478 | html("<select name='h' onchange='this.form.submit();'>\n"); | 487 | html("<select name='h' onchange='this.form.submit();'>\n"); |
479 | for_each_branch_ref(print_branch_option, cgit_query_head); | 488 | for_each_branch_ref(print_branch_option, cgit_query_head); |
480 | html("</select>\n"); | 489 | html("</select>\n"); |
481 | html("</form>\n"); | 490 | html("</form>\n"); |
482 | 491 | ||
483 | html("<p>\n<h1>search</h1>\n"); | 492 | html("<p>\n<h1>search</h1>\n"); |
484 | html("<form method='get' action='"); | 493 | html("<form method='get' action='"); |
485 | html_attr(cgit_pageurl(cgit_query_repo, "log", NULL)); | 494 | html_attr(cgit_pageurl(cgit_query_repo, "log", NULL)); |
486 | html("'>\n"); | 495 | html("'>\n"); |
487 | add_hidden_formfields(1, 0); | 496 | add_hidden_formfields(1, 0); |
488 | html("<select name='qt'>\n"); | 497 | html("<select name='qt'>\n"); |
489 | html_option("grep", "log msg", cgit_query_grep); | 498 | html_option("grep", "log msg", cgit_query_grep); |
490 | html_option("author", "author", cgit_query_grep); | 499 | html_option("author", "author", cgit_query_grep); |
491 | html_option("committer", "committer", cgit_query_grep); | 500 | html_option("committer", "committer", cgit_query_grep); |
492 | html("</select>\n"); | 501 | html("</select>\n"); |
493 | html("<input class='txt' type='text' name='q' value='"); | 502 | html("<input class='txt' type='text' name='q' value='"); |
494 | html_attr(cgit_query_search); | 503 | html_attr(cgit_query_search); |
495 | html("'/>\n"); | 504 | html("'/>\n"); |
496 | html("</form>\n"); | 505 | html("</form>\n"); |
497 | } else { | 506 | } else { |
498 | if (!cgit_index_info || html_include(cgit_index_info)) | 507 | if (!cgit_index_info || html_include(cgit_index_info)) |
499 | html(default_info); | 508 | html(default_info); |
500 | } | 509 | } |
501 | 510 | ||
502 | html("</div>\n"); | 511 | html("</div>\n"); |
503 | 512 | ||
504 | html("</div>\n<table class='grid'><tr><td id='content'>\n"); | 513 | html("</div>\n<table class='grid'><tr><td id='content'>\n"); |
505 | } | 514 | } |
506 | 515 | ||
507 | 516 | ||
508 | void cgit_print_snapshot_start(const char *mimetype, const char *filename, | 517 | void cgit_print_snapshot_start(const char *mimetype, const char *filename, |
509 | struct cacheitem *item) | 518 | struct cacheitem *item) |
510 | { | 519 | { |
511 | htmlf("Content-Type: %s\n", mimetype); | 520 | htmlf("Content-Type: %s\n", mimetype); |
512 | htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); | 521 | htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); |
513 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); | 522 | htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); |
514 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + | 523 | htmlf("Expires: %s\n", http_date(item->st.st_mtime + |
515 | ttl_seconds(item->ttl))); | 524 | ttl_seconds(item->ttl))); |
516 | html("\n"); | 525 | html("\n"); |
517 | } | 526 | } |
518 | 527 | ||
519 | /* vim:set sw=8: */ | 528 | /* vim:set sw=8: */ |
diff --git a/ui-summary.c b/ui-summary.c index 39fe330..c856793 100644 --- a/ui-summary.c +++ b/ui-summary.c | |||
@@ -1,200 +1,200 @@ | |||
1 | /* ui-summary.c: functions for generating repo summary page | 1 | /* ui-summary.c: functions for generating repo summary page |
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 | static int header; | 11 | static int header; |
12 | 12 | ||
13 | static int cmp_age(int age1, int age2) | 13 | static int cmp_age(int age1, int age2) |
14 | { | 14 | { |
15 | if (age1 != 0 && age2 != 0) | 15 | if (age1 != 0 && age2 != 0) |
16 | return age2 - age1; | 16 | return age2 - age1; |
17 | 17 | ||
18 | if (age1 == 0 && age2 == 0) | 18 | if (age1 == 0 && age2 == 0) |
19 | return 0; | 19 | return 0; |
20 | 20 | ||
21 | if (age1 == 0) | 21 | if (age1 == 0) |
22 | return +1; | 22 | return +1; |
23 | 23 | ||
24 | return -1; | 24 | return -1; |
25 | } | 25 | } |
26 | 26 | ||
27 | static int cmp_ref_name(const void *a, const void *b) | 27 | static int cmp_ref_name(const void *a, const void *b) |
28 | { | 28 | { |
29 | struct refinfo *r1 = *(struct refinfo **)a; | 29 | struct refinfo *r1 = *(struct refinfo **)a; |
30 | struct refinfo *r2 = *(struct refinfo **)b; | 30 | struct refinfo *r2 = *(struct refinfo **)b; |
31 | 31 | ||
32 | return strcmp(r1->refname, r2->refname); | 32 | return strcmp(r1->refname, r2->refname); |
33 | } | 33 | } |
34 | 34 | ||
35 | static int cmp_branch_age(const void *a, const void *b) | 35 | static int cmp_branch_age(const void *a, const void *b) |
36 | { | 36 | { |
37 | struct refinfo *r1 = *(struct refinfo **)a; | 37 | struct refinfo *r1 = *(struct refinfo **)a; |
38 | struct refinfo *r2 = *(struct refinfo **)b; | 38 | struct refinfo *r2 = *(struct refinfo **)b; |
39 | 39 | ||
40 | return cmp_age(r1->commit->committer_date, r2->commit->committer_date); | 40 | return cmp_age(r1->commit->committer_date, r2->commit->committer_date); |
41 | } | 41 | } |
42 | 42 | ||
43 | static int cmp_tag_age(const void *a, const void *b) | 43 | static int cmp_tag_age(const void *a, const void *b) |
44 | { | 44 | { |
45 | struct refinfo *r1 = *(struct refinfo **)a; | 45 | struct refinfo *r1 = *(struct refinfo **)a; |
46 | struct refinfo *r2 = *(struct refinfo **)b; | 46 | struct refinfo *r2 = *(struct refinfo **)b; |
47 | 47 | ||
48 | return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); | 48 | return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); |
49 | } | 49 | } |
50 | 50 | ||
51 | static int print_branch(struct refinfo *ref) | 51 | static int print_branch(struct refinfo *ref) |
52 | { | 52 | { |
53 | struct commitinfo *info = ref->commit; | 53 | struct commitinfo *info = ref->commit; |
54 | char *name = (char *)ref->refname; | 54 | char *name = (char *)ref->refname; |
55 | 55 | ||
56 | if (!info) | 56 | if (!info) |
57 | return 1; | 57 | return 1; |
58 | html("<tr><td>"); | 58 | html("<tr><td>"); |
59 | cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0); | 59 | cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL); |
60 | html("</td><td>"); | 60 | html("</td><td>"); |
61 | 61 | ||
62 | if (ref->object->type == OBJ_COMMIT) { | 62 | if (ref->object->type == OBJ_COMMIT) { |
63 | cgit_print_age(info->commit->date, -1, NULL); | 63 | cgit_print_age(info->commit->date, -1, NULL); |
64 | html("</td><td>"); | 64 | html("</td><td>"); |
65 | html_txt(info->author); | 65 | html_txt(info->author); |
66 | html("</td><td>"); | 66 | html("</td><td>"); |
67 | cgit_commit_link(info->subject, NULL, NULL, name, NULL); | 67 | cgit_commit_link(info->subject, NULL, NULL, name, NULL); |
68 | } else { | 68 | } else { |
69 | html("</td><td></td><td>"); | 69 | html("</td><td></td><td>"); |
70 | cgit_object_link(ref->object); | 70 | cgit_object_link(ref->object); |
71 | } | 71 | } |
72 | html("</td></tr>\n"); | 72 | html("</td></tr>\n"); |
73 | return 0; | 73 | return 0; |
74 | } | 74 | } |
75 | 75 | ||
76 | static void print_tag_header() | 76 | static void print_tag_header() |
77 | { | 77 | { |
78 | html("<tr class='nohover'><th class='left'>Tag</th>" | 78 | html("<tr class='nohover'><th class='left'>Tag</th>" |
79 | "<th class='left'>Age</th>" | 79 | "<th class='left'>Age</th>" |
80 | "<th class='left'>Author</th>" | 80 | "<th class='left'>Author</th>" |
81 | "<th class='left'>Reference</th></tr>\n"); | 81 | "<th class='left'>Reference</th></tr>\n"); |
82 | header = 1; | 82 | header = 1; |
83 | } | 83 | } |
84 | 84 | ||
85 | static int print_tag(struct refinfo *ref) | 85 | static int print_tag(struct refinfo *ref) |
86 | { | 86 | { |
87 | struct tag *tag; | 87 | struct tag *tag; |
88 | struct taginfo *info; | 88 | struct taginfo *info; |
89 | char *url, *name = (char *)ref->refname; | 89 | char *url, *name = (char *)ref->refname; |
90 | 90 | ||
91 | if (ref->object->type == OBJ_TAG) { | 91 | if (ref->object->type == OBJ_TAG) { |
92 | tag = (struct tag *)ref->object; | 92 | tag = (struct tag *)ref->object; |
93 | info = ref->tag; | 93 | info = ref->tag; |
94 | if (!tag || !info) | 94 | if (!tag || !info) |
95 | return 1; | 95 | return 1; |
96 | html("<tr><td>"); | 96 | html("<tr><td>"); |
97 | url = cgit_pageurl(cgit_query_repo, "tag", | 97 | url = cgit_pageurl(cgit_query_repo, "tag", |
98 | fmt("id=%s", name)); | 98 | fmt("id=%s", name)); |
99 | html_link_open(url, NULL, NULL); | 99 | html_link_open(url, NULL, NULL); |
100 | html_txt(name); | 100 | html_txt(name); |
101 | html_link_close(); | 101 | html_link_close(); |
102 | html("</td><td>"); | 102 | html("</td><td>"); |
103 | if (info->tagger_date > 0) | 103 | if (info->tagger_date > 0) |
104 | cgit_print_age(info->tagger_date, -1, NULL); | 104 | cgit_print_age(info->tagger_date, -1, NULL); |
105 | html("</td><td>"); | 105 | html("</td><td>"); |
106 | if (info->tagger) | 106 | if (info->tagger) |
107 | html(info->tagger); | 107 | html(info->tagger); |
108 | html("</td><td>"); | 108 | html("</td><td>"); |
109 | cgit_object_link(tag->tagged); | 109 | cgit_object_link(tag->tagged); |
110 | html("</td></tr>\n"); | 110 | html("</td></tr>\n"); |
111 | } else { | 111 | } else { |
112 | if (!header) | 112 | if (!header) |
113 | print_tag_header(); | 113 | print_tag_header(); |
114 | html("<tr><td>"); | 114 | html("<tr><td>"); |
115 | html_txt(name); | 115 | html_txt(name); |
116 | html("</td><td colspan='2'/><td>"); | 116 | html("</td><td colspan='2'/><td>"); |
117 | cgit_object_link(ref->object); | 117 | cgit_object_link(ref->object); |
118 | html("</td></tr>\n"); | 118 | html("</td></tr>\n"); |
119 | } | 119 | } |
120 | return 0; | 120 | return 0; |
121 | } | 121 | } |
122 | 122 | ||
123 | static void print_refs_link(char *path) | 123 | static void print_refs_link(char *path) |
124 | { | 124 | { |
125 | html("<tr class='nohover'><td colspan='4'>"); | 125 | html("<tr class='nohover'><td colspan='4'>"); |
126 | cgit_refs_link("[...]", NULL, NULL, cgit_query_head, NULL, path); | 126 | cgit_refs_link("[...]", NULL, NULL, cgit_query_head, NULL, path); |
127 | html("</td></tr>"); | 127 | html("</td></tr>"); |
128 | } | 128 | } |
129 | 129 | ||
130 | void cgit_print_branches(int maxcount) | 130 | void cgit_print_branches(int maxcount) |
131 | { | 131 | { |
132 | struct reflist list; | 132 | struct reflist list; |
133 | int i; | 133 | int i; |
134 | 134 | ||
135 | html("<tr class='nohover'><th class='left'>Branch</th>" | 135 | html("<tr class='nohover'><th class='left'>Branch</th>" |
136 | "<th class='left'>Idle</th>" | 136 | "<th class='left'>Idle</th>" |
137 | "<th class='left'>Author</th>" | 137 | "<th class='left'>Author</th>" |
138 | "<th class='left'>Head commit</th></tr>\n"); | 138 | "<th class='left'>Head commit</th></tr>\n"); |
139 | 139 | ||
140 | list.refs = NULL; | 140 | list.refs = NULL; |
141 | list.alloc = list.count = 0; | 141 | list.alloc = list.count = 0; |
142 | for_each_branch_ref(cgit_refs_cb, &list); | 142 | for_each_branch_ref(cgit_refs_cb, &list); |
143 | 143 | ||
144 | if (maxcount == 0 || maxcount > list.count) | 144 | if (maxcount == 0 || maxcount > list.count) |
145 | maxcount = list.count; | 145 | maxcount = list.count; |
146 | 146 | ||
147 | if (maxcount < list.count) { | 147 | if (maxcount < list.count) { |
148 | qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); | 148 | qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); |
149 | qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); | 149 | qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); |
150 | } | 150 | } |
151 | 151 | ||
152 | for(i=0; i<maxcount; i++) | 152 | for(i=0; i<maxcount; i++) |
153 | print_branch(list.refs[i]); | 153 | print_branch(list.refs[i]); |
154 | 154 | ||
155 | if (maxcount < list.count) | 155 | if (maxcount < list.count) |
156 | print_refs_link("heads"); | 156 | print_refs_link("heads"); |
157 | } | 157 | } |
158 | 158 | ||
159 | void cgit_print_tags(int maxcount) | 159 | void cgit_print_tags(int maxcount) |
160 | { | 160 | { |
161 | struct reflist list; | 161 | struct reflist list; |
162 | int i; | 162 | int i; |
163 | 163 | ||
164 | header = 0; | 164 | header = 0; |
165 | list.refs = NULL; | 165 | list.refs = NULL; |
166 | list.alloc = list.count = 0; | 166 | list.alloc = list.count = 0; |
167 | for_each_tag_ref(cgit_refs_cb, &list); | 167 | for_each_tag_ref(cgit_refs_cb, &list); |
168 | if (list.count == 0) | 168 | if (list.count == 0) |
169 | return; | 169 | return; |
170 | qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); | 170 | qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); |
171 | if (!maxcount) | 171 | if (!maxcount) |
172 | maxcount = list.count; | 172 | maxcount = list.count; |
173 | else if (maxcount > list.count) | 173 | else if (maxcount > list.count) |
174 | maxcount = list.count; | 174 | maxcount = list.count; |
175 | print_tag_header(); | 175 | print_tag_header(); |
176 | for(i=0; i<maxcount; i++) | 176 | for(i=0; i<maxcount; i++) |
177 | print_tag(list.refs[i]); | 177 | print_tag(list.refs[i]); |
178 | 178 | ||
179 | if (maxcount < list.count) | 179 | if (maxcount < list.count) |
180 | print_refs_link("tags"); | 180 | print_refs_link("tags"); |
181 | } | 181 | } |
182 | 182 | ||
183 | void cgit_print_summary() | 183 | void cgit_print_summary() |
184 | { | 184 | { |
185 | if (cgit_repo->readme) { | 185 | if (cgit_repo->readme) { |
186 | html("<div id='summary'>"); | 186 | html("<div id='summary'>"); |
187 | html_include(cgit_repo->readme); | 187 | html_include(cgit_repo->readme); |
188 | html("</div>"); | 188 | html("</div>"); |
189 | } | 189 | } |
190 | if (cgit_summary_log > 0) | 190 | if (cgit_summary_log > 0) |
191 | cgit_print_log(cgit_query_head, 0, cgit_summary_log, NULL, | 191 | cgit_print_log(cgit_query_head, 0, cgit_summary_log, NULL, |
192 | NULL, NULL, 0); | 192 | NULL, NULL, 0); |
193 | html("<table class='list nowrap'>"); | 193 | html("<table class='list nowrap'>"); |
194 | if (cgit_summary_log > 0) | 194 | if (cgit_summary_log > 0) |
195 | html("<tr class='nohover'><td colspan='4'> </td></tr>"); | 195 | html("<tr class='nohover'><td colspan='4'> </td></tr>"); |
196 | cgit_print_branches(cgit_summary_branches); | 196 | cgit_print_branches(cgit_summary_branches); |
197 | html("<tr class='nohover'><td colspan='4'> </td></tr>"); | 197 | html("<tr class='nohover'><td colspan='4'> </td></tr>"); |
198 | cgit_print_tags(cgit_summary_tags); | 198 | cgit_print_tags(cgit_summary_tags); |
199 | html("</table>"); | 199 | html("</table>"); |
200 | } | 200 | } |
@@ -1,216 +1,216 @@ | |||
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 "cgit.h" | 9 | #include "cgit.h" |
10 | 10 | ||
11 | char *curr_rev; | 11 | char *curr_rev; |
12 | char *match_path; | 12 | char *match_path; |
13 | int header = 0; | 13 | int header = 0; |
14 | 14 | ||
15 | static void print_object(const unsigned char *sha1, char *path) | 15 | static void print_object(const unsigned char *sha1, char *path) |
16 | { | 16 | { |
17 | enum object_type type; | 17 | enum object_type type; |
18 | char *buf; | 18 | char *buf; |
19 | unsigned long size, lineno, start, idx; | 19 | unsigned long size, lineno, start, idx; |
20 | const char *linefmt = "<tr><td class='no'><a name='%1$d'>%1$d</a></td><td class='txt'>"; | 20 | const char *linefmt = "<tr><td class='no'><a name='%1$d'>%1$d</a></td><td class='txt'>"; |
21 | 21 | ||
22 | type = sha1_object_info(sha1, &size); | 22 | type = sha1_object_info(sha1, &size); |
23 | if (type == OBJ_BAD) { | 23 | if (type == OBJ_BAD) { |
24 | cgit_print_error(fmt("Bad object name: %s", | 24 | cgit_print_error(fmt("Bad object name: %s", |
25 | sha1_to_hex(sha1))); | 25 | sha1_to_hex(sha1))); |
26 | return; | 26 | return; |
27 | } | 27 | } |
28 | 28 | ||
29 | buf = read_sha1_file(sha1, &type, &size); | 29 | buf = read_sha1_file(sha1, &type, &size); |
30 | if (!buf) { | 30 | if (!buf) { |
31 | cgit_print_error(fmt("Error reading object %s", | 31 | cgit_print_error(fmt("Error reading object %s", |
32 | sha1_to_hex(sha1))); | 32 | sha1_to_hex(sha1))); |
33 | return; | 33 | return; |
34 | } | 34 | } |
35 | 35 | ||
36 | html(" blob: <a href='"); | 36 | html(" blob: <a href='"); |
37 | html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1)))); | 37 | html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1)))); |
38 | htmlf("'>%s</a>",sha1_to_hex(sha1)); | 38 | htmlf("'>%s</a>",sha1_to_hex(sha1)); |
39 | 39 | ||
40 | html("<table class='blob'>\n"); | 40 | html("<table class='blob'>\n"); |
41 | idx = 0; | 41 | idx = 0; |
42 | start = 0; | 42 | start = 0; |
43 | lineno = 0; | 43 | lineno = 0; |
44 | while(idx < size) { | 44 | while(idx < size) { |
45 | if (buf[idx] == '\n') { | 45 | if (buf[idx] == '\n') { |
46 | buf[idx] = '\0'; | 46 | buf[idx] = '\0'; |
47 | htmlf(linefmt, ++lineno); | 47 | htmlf(linefmt, ++lineno); |
48 | html_txt(buf + start); | 48 | html_txt(buf + start); |
49 | html("</td></tr>\n"); | 49 | html("</td></tr>\n"); |
50 | start = idx + 1; | 50 | start = idx + 1; |
51 | } | 51 | } |
52 | idx++; | 52 | idx++; |
53 | } | 53 | } |
54 | htmlf(linefmt, ++lineno); | 54 | htmlf(linefmt, ++lineno); |
55 | html_txt(buf + start); | 55 | html_txt(buf + start); |
56 | html("</td></tr>\n"); | 56 | html("</td></tr>\n"); |
57 | html("</table>\n"); | 57 | html("</table>\n"); |
58 | } | 58 | } |
59 | 59 | ||
60 | 60 | ||
61 | static int ls_item(const unsigned char *sha1, const char *base, int baselen, | 61 | static int ls_item(const unsigned char *sha1, const char *base, int baselen, |
62 | const char *pathname, unsigned int mode, int stage) | 62 | const char *pathname, unsigned int mode, int stage) |
63 | { | 63 | { |
64 | char *name; | 64 | char *name; |
65 | char *fullpath; | 65 | char *fullpath; |
66 | enum object_type type; | 66 | enum object_type type; |
67 | unsigned long size = 0; | 67 | unsigned long size = 0; |
68 | 68 | ||
69 | name = xstrdup(pathname); | 69 | name = xstrdup(pathname); |
70 | fullpath = fmt("%s%s%s", cgit_query_path ? cgit_query_path : "", | 70 | fullpath = fmt("%s%s%s", cgit_query_path ? cgit_query_path : "", |
71 | cgit_query_path ? "/" : "", name); | 71 | cgit_query_path ? "/" : "", name); |
72 | 72 | ||
73 | type = sha1_object_info(sha1, &size); | 73 | type = sha1_object_info(sha1, &size); |
74 | if (type == OBJ_BAD && !S_ISGITLINK(mode)) { | 74 | if (type == OBJ_BAD && !S_ISGITLINK(mode)) { |
75 | htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", | 75 | htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", |
76 | name, | 76 | name, |
77 | sha1_to_hex(sha1)); | 77 | sha1_to_hex(sha1)); |
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||
81 | html("<tr><td class='ls-mode'>"); | 81 | html("<tr><td class='ls-mode'>"); |
82 | html_filemode(mode); | 82 | html_filemode(mode); |
83 | html("</td><td>"); | 83 | html("</td><td>"); |
84 | if (S_ISGITLINK(mode)) { | 84 | if (S_ISGITLINK(mode)) { |
85 | htmlf("<a class='ls-mod' href='"); | 85 | htmlf("<a class='ls-mod' href='"); |
86 | html_attr(fmt(cgit_repo->module_link, | 86 | html_attr(fmt(cgit_repo->module_link, |
87 | name, | 87 | name, |
88 | sha1_to_hex(sha1))); | 88 | sha1_to_hex(sha1))); |
89 | html("'>"); | 89 | html("'>"); |
90 | html_txt(name); | 90 | html_txt(name); |
91 | html("</a>"); | 91 | html("</a>"); |
92 | } else if (S_ISDIR(mode)) { | 92 | } else if (S_ISDIR(mode)) { |
93 | cgit_tree_link(name, NULL, "ls-dir", cgit_query_head, | 93 | cgit_tree_link(name, NULL, "ls-dir", cgit_query_head, |
94 | curr_rev, fullpath); | 94 | curr_rev, fullpath); |
95 | } else { | 95 | } else { |
96 | cgit_tree_link(name, NULL, "ls-blob", cgit_query_head, | 96 | cgit_tree_link(name, NULL, "ls-blob", cgit_query_head, |
97 | curr_rev, fullpath); | 97 | curr_rev, fullpath); |
98 | } | 98 | } |
99 | htmlf("</td><td class='ls-size'>%li</td>", size); | 99 | htmlf("</td><td class='ls-size'>%li</td>", size); |
100 | 100 | ||
101 | html("<td>"); | 101 | html("<td>"); |
102 | cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev, | 102 | cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev, |
103 | fullpath, 0); | 103 | fullpath, 0, NULL, NULL); |
104 | html("</td></tr>\n"); | 104 | html("</td></tr>\n"); |
105 | free(name); | 105 | free(name); |
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | 108 | ||
109 | static void ls_head() | 109 | static void ls_head() |
110 | { | 110 | { |
111 | html("<table class='list'>\n"); | 111 | html("<table class='list'>\n"); |
112 | html("<tr class='nohover'>"); | 112 | html("<tr class='nohover'>"); |
113 | html("<th class='left'>Mode</th>"); | 113 | html("<th class='left'>Mode</th>"); |
114 | html("<th class='left'>Name</th>"); | 114 | html("<th class='left'>Name</th>"); |
115 | html("<th class='right'>Size</th>"); | 115 | html("<th class='right'>Size</th>"); |
116 | html("<th/>"); | 116 | html("<th/>"); |
117 | html("</tr>\n"); | 117 | html("</tr>\n"); |
118 | header = 1; | 118 | header = 1; |
119 | } | 119 | } |
120 | 120 | ||
121 | static void ls_tail() | 121 | static void ls_tail() |
122 | { | 122 | { |
123 | if (!header) | 123 | if (!header) |
124 | return; | 124 | return; |
125 | html("</table>\n"); | 125 | html("</table>\n"); |
126 | header = 0; | 126 | header = 0; |
127 | } | 127 | } |
128 | 128 | ||
129 | static void ls_tree(const unsigned char *sha1, char *path) | 129 | static void ls_tree(const unsigned char *sha1, char *path) |
130 | { | 130 | { |
131 | struct tree *tree; | 131 | struct tree *tree; |
132 | 132 | ||
133 | tree = parse_tree_indirect(sha1); | 133 | tree = parse_tree_indirect(sha1); |
134 | if (!tree) { | 134 | if (!tree) { |
135 | cgit_print_error(fmt("Not a tree object: %s", | 135 | cgit_print_error(fmt("Not a tree object: %s", |
136 | sha1_to_hex(sha1))); | 136 | sha1_to_hex(sha1))); |
137 | return; | 137 | return; |
138 | } | 138 | } |
139 | 139 | ||
140 | ls_head(); | 140 | ls_head(); |
141 | read_tree_recursive(tree, "", 0, 1, NULL, ls_item); | 141 | read_tree_recursive(tree, "", 0, 1, NULL, ls_item); |
142 | ls_tail(); | 142 | ls_tail(); |
143 | } | 143 | } |
144 | 144 | ||
145 | 145 | ||
146 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | 146 | static int walk_tree(const unsigned char *sha1, const char *base, int baselen, |
147 | const char *pathname, unsigned mode, int stage) | 147 | const char *pathname, unsigned mode, int stage) |
148 | { | 148 | { |
149 | static int state; | 149 | static int state; |
150 | static char buffer[PATH_MAX]; | 150 | static char buffer[PATH_MAX]; |
151 | char *url; | 151 | char *url; |
152 | 152 | ||
153 | if (state == 0) { | 153 | if (state == 0) { |
154 | memcpy(buffer, base, baselen); | 154 | memcpy(buffer, base, baselen); |
155 | strcpy(buffer+baselen, pathname); | 155 | strcpy(buffer+baselen, pathname); |
156 | url = cgit_pageurl(cgit_query_repo, "tree", | 156 | url = cgit_pageurl(cgit_query_repo, "tree", |
157 | fmt("h=%s&path=%s", curr_rev, buffer)); | 157 | fmt("h=%s&path=%s", curr_rev, buffer)); |
158 | html("/"); | 158 | html("/"); |
159 | cgit_tree_link(xstrdup(pathname), NULL, NULL, cgit_query_head, | 159 | cgit_tree_link(xstrdup(pathname), NULL, NULL, cgit_query_head, |
160 | curr_rev, buffer); | 160 | curr_rev, buffer); |
161 | 161 | ||
162 | if (strcmp(match_path, buffer)) | 162 | if (strcmp(match_path, buffer)) |
163 | return READ_TREE_RECURSIVE; | 163 | return READ_TREE_RECURSIVE; |
164 | 164 | ||
165 | if (S_ISDIR(mode)) { | 165 | if (S_ISDIR(mode)) { |
166 | state = 1; | 166 | state = 1; |
167 | ls_head(); | 167 | ls_head(); |
168 | return READ_TREE_RECURSIVE; | 168 | return READ_TREE_RECURSIVE; |
169 | } else { | 169 | } else { |
170 | print_object(sha1, buffer); | 170 | print_object(sha1, buffer); |
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | } | 173 | } |
174 | ls_item(sha1, base, baselen, pathname, mode, stage); | 174 | ls_item(sha1, base, baselen, pathname, mode, stage); |
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Show a tree or a blob | 180 | * Show a tree or a blob |
181 | * rev: the commit pointing at the root tree object | 181 | * rev: the commit pointing at the root tree object |
182 | * path: path to tree or blob | 182 | * path: path to tree or blob |
183 | */ | 183 | */ |
184 | void cgit_print_tree(const char *rev, char *path) | 184 | void cgit_print_tree(const char *rev, char *path) |
185 | { | 185 | { |
186 | unsigned char sha1[20]; | 186 | unsigned char sha1[20]; |
187 | struct commit *commit; | 187 | struct commit *commit; |
188 | const char *paths[] = {path, NULL}; | 188 | const char *paths[] = {path, NULL}; |
189 | 189 | ||
190 | if (!rev) | 190 | if (!rev) |
191 | rev = cgit_query_head; | 191 | rev = cgit_query_head; |
192 | 192 | ||
193 | curr_rev = xstrdup(rev); | 193 | curr_rev = xstrdup(rev); |
194 | if (get_sha1(rev, sha1)) { | 194 | if (get_sha1(rev, sha1)) { |
195 | cgit_print_error(fmt("Invalid revision name: %s", rev)); | 195 | cgit_print_error(fmt("Invalid revision name: %s", rev)); |
196 | return; | 196 | return; |
197 | } | 197 | } |
198 | commit = lookup_commit_reference(sha1); | 198 | commit = lookup_commit_reference(sha1); |
199 | if (!commit || parse_commit(commit)) { | 199 | if (!commit || parse_commit(commit)) { |
200 | cgit_print_error(fmt("Invalid commit reference: %s", rev)); | 200 | cgit_print_error(fmt("Invalid commit reference: %s", rev)); |
201 | return; | 201 | return; |
202 | } | 202 | } |
203 | 203 | ||
204 | html("path: <a href='"); | 204 | html("path: <a href='"); |
205 | html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev))); | 205 | html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev))); |
206 | html("'>root</a>"); | 206 | html("'>root</a>"); |
207 | 207 | ||
208 | if (path == NULL) { | 208 | if (path == NULL) { |
209 | ls_tree(commit->tree->object.sha1, NULL); | 209 | ls_tree(commit->tree->object.sha1, NULL); |
210 | return; | 210 | return; |
211 | } | 211 | } |
212 | 212 | ||
213 | match_path = path; | 213 | match_path = path; |
214 | read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree); | 214 | read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree); |
215 | ls_tail(); | 215 | ls_tail(); |
216 | } | 216 | } |