summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2008-04-08 19:11:36 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-04-08 19:11:36 (UTC)
commite87e89633383b8b75c68c98be3e0c14212109de2 (patch) (unidiff)
treef57e131ab854b58023387aee8efc0e4ee54653b5
parent20a33548b9a87a6eb23162ee5d137daa46d78613 (diff)
downloadcgit-e87e89633383b8b75c68c98be3e0c14212109de2.zip
cgit-e87e89633383b8b75c68c98be3e0c14212109de2.tar.gz
cgit-e87e89633383b8b75c68c98be3e0c14212109de2.tar.bz2
Move cgit_parse_query() from parsing.c to html.c as http_parse_querystring()
This is a generic http-function. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c3
-rw-r--r--cgit.h2
-rw-r--r--html.c64
-rw-r--r--html.h2
-rw-r--r--parsing.c49
-rw-r--r--shared.c12
6 files changed, 68 insertions, 64 deletions
diff --git a/cgit.c b/cgit.c
index 1f46e0d..763242a 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,108 +1,109 @@
1/* cgit.c: cgi for the git scm 1/* cgit.c: cgi for the git scm
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "cache.h" 10#include "cache.h"
11#include "cmd.h" 11#include "cmd.h"
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h"
13#include "ui-shared.h" 14#include "ui-shared.h"
14 15
15const char *cgit_version = CGIT_VERSION; 16const char *cgit_version = CGIT_VERSION;
16 17
17void config_cb(const char *name, const char *value) 18void config_cb(const char *name, const char *value)
18{ 19{
19 if (!strcmp(name, "root-title")) 20 if (!strcmp(name, "root-title"))
20 ctx.cfg.root_title = xstrdup(value); 21 ctx.cfg.root_title = xstrdup(value);
21 else if (!strcmp(name, "css")) 22 else if (!strcmp(name, "css"))
22 ctx.cfg.css = xstrdup(value); 23 ctx.cfg.css = xstrdup(value);
23 else if (!strcmp(name, "logo")) 24 else if (!strcmp(name, "logo"))
24 ctx.cfg.logo = xstrdup(value); 25 ctx.cfg.logo = xstrdup(value);
25 else if (!strcmp(name, "index-header")) 26 else if (!strcmp(name, "index-header"))
26 ctx.cfg.index_header = xstrdup(value); 27 ctx.cfg.index_header = xstrdup(value);
27 else if (!strcmp(name, "index-info")) 28 else if (!strcmp(name, "index-info"))
28 ctx.cfg.index_info = xstrdup(value); 29 ctx.cfg.index_info = xstrdup(value);
29 else if (!strcmp(name, "logo-link")) 30 else if (!strcmp(name, "logo-link"))
30 ctx.cfg.logo_link = xstrdup(value); 31 ctx.cfg.logo_link = xstrdup(value);
31 else if (!strcmp(name, "module-link")) 32 else if (!strcmp(name, "module-link"))
32 ctx.cfg.module_link = xstrdup(value); 33 ctx.cfg.module_link = xstrdup(value);
33 else if (!strcmp(name, "virtual-root")) { 34 else if (!strcmp(name, "virtual-root")) {
34 ctx.cfg.virtual_root = trim_end(value, '/'); 35 ctx.cfg.virtual_root = trim_end(value, '/');
35 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 36 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
36 ctx.cfg.virtual_root = ""; 37 ctx.cfg.virtual_root = "";
37 } else if (!strcmp(name, "nocache")) 38 } else if (!strcmp(name, "nocache"))
38 ctx.cfg.nocache = atoi(value); 39 ctx.cfg.nocache = atoi(value);
39 else if (!strcmp(name, "snapshots")) 40 else if (!strcmp(name, "snapshots"))
40 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 41 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
41 else if (!strcmp(name, "enable-index-links")) 42 else if (!strcmp(name, "enable-index-links"))
42 ctx.cfg.enable_index_links = atoi(value); 43 ctx.cfg.enable_index_links = atoi(value);
43 else if (!strcmp(name, "enable-log-filecount")) 44 else if (!strcmp(name, "enable-log-filecount"))
44 ctx.cfg.enable_log_filecount = atoi(value); 45 ctx.cfg.enable_log_filecount = atoi(value);
45 else if (!strcmp(name, "enable-log-linecount")) 46 else if (!strcmp(name, "enable-log-linecount"))
46 ctx.cfg.enable_log_linecount = atoi(value); 47 ctx.cfg.enable_log_linecount = atoi(value);
47 else if (!strcmp(name, "cache-root")) 48 else if (!strcmp(name, "cache-root"))
48 ctx.cfg.cache_root = xstrdup(value); 49 ctx.cfg.cache_root = xstrdup(value);
49 else if (!strcmp(name, "cache-root-ttl")) 50 else if (!strcmp(name, "cache-root-ttl"))
50 ctx.cfg.cache_root_ttl = atoi(value); 51 ctx.cfg.cache_root_ttl = atoi(value);
51 else if (!strcmp(name, "cache-repo-ttl")) 52 else if (!strcmp(name, "cache-repo-ttl"))
52 ctx.cfg.cache_repo_ttl = atoi(value); 53 ctx.cfg.cache_repo_ttl = atoi(value);
53 else if (!strcmp(name, "cache-static-ttl")) 54 else if (!strcmp(name, "cache-static-ttl"))
54 ctx.cfg.cache_static_ttl = atoi(value); 55 ctx.cfg.cache_static_ttl = atoi(value);
55 else if (!strcmp(name, "cache-dynamic-ttl")) 56 else if (!strcmp(name, "cache-dynamic-ttl"))
56 ctx.cfg.cache_dynamic_ttl = atoi(value); 57 ctx.cfg.cache_dynamic_ttl = atoi(value);
57 else if (!strcmp(name, "max-message-length")) 58 else if (!strcmp(name, "max-message-length"))
58 ctx.cfg.max_msg_len = atoi(value); 59 ctx.cfg.max_msg_len = atoi(value);
59 else if (!strcmp(name, "max-repodesc-length")) 60 else if (!strcmp(name, "max-repodesc-length"))
60 ctx.cfg.max_repodesc_len = atoi(value); 61 ctx.cfg.max_repodesc_len = atoi(value);
61 else if (!strcmp(name, "max-commit-count")) 62 else if (!strcmp(name, "max-commit-count"))
62 ctx.cfg.max_commit_count = atoi(value); 63 ctx.cfg.max_commit_count = atoi(value);
63 else if (!strcmp(name, "summary-log")) 64 else if (!strcmp(name, "summary-log"))
64 ctx.cfg.summary_log = atoi(value); 65 ctx.cfg.summary_log = atoi(value);
65 else if (!strcmp(name, "summary-branches")) 66 else if (!strcmp(name, "summary-branches"))
66 ctx.cfg.summary_branches = atoi(value); 67 ctx.cfg.summary_branches = atoi(value);
67 else if (!strcmp(name, "summary-tags")) 68 else if (!strcmp(name, "summary-tags"))
68 ctx.cfg.summary_tags = atoi(value); 69 ctx.cfg.summary_tags = atoi(value);
69 else if (!strcmp(name, "agefile")) 70 else if (!strcmp(name, "agefile"))
70 ctx.cfg.agefile = xstrdup(value); 71 ctx.cfg.agefile = xstrdup(value);
71 else if (!strcmp(name, "renamelimit")) 72 else if (!strcmp(name, "renamelimit"))
72 ctx.cfg.renamelimit = atoi(value); 73 ctx.cfg.renamelimit = atoi(value);
73 else if (!strcmp(name, "robots")) 74 else if (!strcmp(name, "robots"))
74 ctx.cfg.robots = xstrdup(value); 75 ctx.cfg.robots = xstrdup(value);
75 else if (!strcmp(name, "clone-prefix")) 76 else if (!strcmp(name, "clone-prefix"))
76 ctx.cfg.clone_prefix = xstrdup(value); 77 ctx.cfg.clone_prefix = xstrdup(value);
77 else if (!strcmp(name, "repo.group")) 78 else if (!strcmp(name, "repo.group"))
78 ctx.cfg.repo_group = xstrdup(value); 79 ctx.cfg.repo_group = xstrdup(value);
79 else if (!strcmp(name, "repo.url")) 80 else if (!strcmp(name, "repo.url"))
80 ctx.repo = cgit_add_repo(value); 81 ctx.repo = cgit_add_repo(value);
81 else if (!strcmp(name, "repo.name")) 82 else if (!strcmp(name, "repo.name"))
82 ctx.repo->name = xstrdup(value); 83 ctx.repo->name = xstrdup(value);
83 else if (ctx.repo && !strcmp(name, "repo.path")) 84 else if (ctx.repo && !strcmp(name, "repo.path"))
84 ctx.repo->path = trim_end(value, '/'); 85 ctx.repo->path = trim_end(value, '/');
85 else if (ctx.repo && !strcmp(name, "repo.clone-url")) 86 else if (ctx.repo && !strcmp(name, "repo.clone-url"))
86 ctx.repo->clone_url = xstrdup(value); 87 ctx.repo->clone_url = xstrdup(value);
87 else if (ctx.repo && !strcmp(name, "repo.desc")) 88 else if (ctx.repo && !strcmp(name, "repo.desc"))
88 ctx.repo->desc = xstrdup(value); 89 ctx.repo->desc = xstrdup(value);
89 else if (ctx.repo && !strcmp(name, "repo.owner")) 90 else if (ctx.repo && !strcmp(name, "repo.owner"))
90 ctx.repo->owner = xstrdup(value); 91 ctx.repo->owner = xstrdup(value);
91 else if (ctx.repo && !strcmp(name, "repo.defbranch")) 92 else if (ctx.repo && !strcmp(name, "repo.defbranch"))
92 ctx.repo->defbranch = xstrdup(value); 93 ctx.repo->defbranch = xstrdup(value);
93 else if (ctx.repo && !strcmp(name, "repo.snapshots")) 94 else if (ctx.repo && !strcmp(name, "repo.snapshots"))
94 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ 95 ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
95 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) 96 else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount"))
96 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 97 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
97 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 98 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
98 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 99 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
99 else if (ctx.repo && !strcmp(name, "repo.module-link")) 100 else if (ctx.repo && !strcmp(name, "repo.module-link"))
100 ctx.repo->module_link= xstrdup(value); 101 ctx.repo->module_link= xstrdup(value);
101 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 102 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
102 if (*value == '/') 103 if (*value == '/')
103 ctx.repo->readme = xstrdup(value); 104 ctx.repo->readme = xstrdup(value);
104 else 105 else
105 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); 106 ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value));
106 } else if (!strcmp(name, "include")) 107 } else if (!strcmp(name, "include"))
107 parse_configfile(value, config_cb); 108 parse_configfile(value, config_cb);
108} 109}
@@ -351,107 +352,107 @@ static void cgit_check_cache(struct cacheitem *item)
351{ 352{
352 int i = 0; 353 int i = 0;
353 354
354 top: 355 top:
355 if (++i > ctx.cfg.max_lock_attempts) { 356 if (++i > ctx.cfg.max_lock_attempts) {
356 die("cgit_refresh_cache: unable to lock %s: %s", 357 die("cgit_refresh_cache: unable to lock %s: %s",
357 item->name, strerror(errno)); 358 item->name, strerror(errno));
358 } 359 }
359 if (!cache_exist(item)) { 360 if (!cache_exist(item)) {
360 if (!cache_lock(item)) { 361 if (!cache_lock(item)) {
361 sleep(1); 362 sleep(1);
362 goto top; 363 goto top;
363 } 364 }
364 if (!cache_exist(item)) { 365 if (!cache_exist(item)) {
365 cgit_fill_cache(item, 1); 366 cgit_fill_cache(item, 1);
366 cache_unlock(item); 367 cache_unlock(item);
367 } else { 368 } else {
368 cache_cancel_lock(item); 369 cache_cancel_lock(item);
369 } 370 }
370 } else if (cache_expired(item) && cache_lock(item)) { 371 } else if (cache_expired(item) && cache_lock(item)) {
371 if (cache_expired(item)) { 372 if (cache_expired(item)) {
372 cgit_fill_cache(item, 1); 373 cgit_fill_cache(item, 1);
373 cache_unlock(item); 374 cache_unlock(item);
374 } else { 375 } else {
375 cache_cancel_lock(item); 376 cache_cancel_lock(item);
376 } 377 }
377 } 378 }
378} 379}
379 380
380static void cgit_print_cache(struct cacheitem *item) 381static void cgit_print_cache(struct cacheitem *item)
381{ 382{
382 static char buf[4096]; 383 static char buf[4096];
383 ssize_t i; 384 ssize_t i;
384 385
385 int fd = open(item->name, O_RDONLY); 386 int fd = open(item->name, O_RDONLY);
386 if (fd<0) 387 if (fd<0)
387 die("Unable to open cached file %s", item->name); 388 die("Unable to open cached file %s", item->name);
388 389
389 while((i=read(fd, buf, sizeof(buf))) > 0) 390 while((i=read(fd, buf, sizeof(buf))) > 0)
390 write(STDOUT_FILENO, buf, i); 391 write(STDOUT_FILENO, buf, i);
391 392
392 close(fd); 393 close(fd);
393} 394}
394 395
395static void cgit_parse_args(int argc, const char **argv) 396static void cgit_parse_args(int argc, const char **argv)
396{ 397{
397 int i; 398 int i;
398 399
399 for (i = 1; i < argc; i++) { 400 for (i = 1; i < argc; i++) {
400 if (!strncmp(argv[i], "--cache=", 8)) { 401 if (!strncmp(argv[i], "--cache=", 8)) {
401 ctx.cfg.cache_root = xstrdup(argv[i]+8); 402 ctx.cfg.cache_root = xstrdup(argv[i]+8);
402 } 403 }
403 if (!strcmp(argv[i], "--nocache")) { 404 if (!strcmp(argv[i], "--nocache")) {
404 ctx.cfg.nocache = 1; 405 ctx.cfg.nocache = 1;
405 } 406 }
406 if (!strncmp(argv[i], "--query=", 8)) { 407 if (!strncmp(argv[i], "--query=", 8)) {
407 ctx.qry.raw = xstrdup(argv[i]+8); 408 ctx.qry.raw = xstrdup(argv[i]+8);
408 } 409 }
409 if (!strncmp(argv[i], "--repo=", 7)) { 410 if (!strncmp(argv[i], "--repo=", 7)) {
410 ctx.qry.repo = xstrdup(argv[i]+7); 411 ctx.qry.repo = xstrdup(argv[i]+7);
411 } 412 }
412 if (!strncmp(argv[i], "--page=", 7)) { 413 if (!strncmp(argv[i], "--page=", 7)) {
413 ctx.qry.page = xstrdup(argv[i]+7); 414 ctx.qry.page = xstrdup(argv[i]+7);
414 } 415 }
415 if (!strncmp(argv[i], "--head=", 7)) { 416 if (!strncmp(argv[i], "--head=", 7)) {
416 ctx.qry.head = xstrdup(argv[i]+7); 417 ctx.qry.head = xstrdup(argv[i]+7);
417 ctx.qry.has_symref = 1; 418 ctx.qry.has_symref = 1;
418 } 419 }
419 if (!strncmp(argv[i], "--sha1=", 7)) { 420 if (!strncmp(argv[i], "--sha1=", 7)) {
420 ctx.qry.sha1 = xstrdup(argv[i]+7); 421 ctx.qry.sha1 = xstrdup(argv[i]+7);
421 ctx.qry.has_sha1 = 1; 422 ctx.qry.has_sha1 = 1;
422 } 423 }
423 if (!strncmp(argv[i], "--ofs=", 6)) { 424 if (!strncmp(argv[i], "--ofs=", 6)) {
424 ctx.qry.ofs = atoi(argv[i]+6); 425 ctx.qry.ofs = atoi(argv[i]+6);
425 } 426 }
426 } 427 }
427} 428}
428 429
429int main(int argc, const char **argv) 430int main(int argc, const char **argv)
430{ 431{
431 struct cacheitem item; 432 struct cacheitem item;
432 const char *cgit_config_env = getenv("CGIT_CONFIG"); 433 const char *cgit_config_env = getenv("CGIT_CONFIG");
433 434
434 prepare_context(&ctx); 435 prepare_context(&ctx);
435 item.st.st_mtime = time(NULL); 436 item.st.st_mtime = time(NULL);
436 cgit_repolist.length = 0; 437 cgit_repolist.length = 0;
437 cgit_repolist.count = 0; 438 cgit_repolist.count = 0;
438 cgit_repolist.repos = NULL; 439 cgit_repolist.repos = NULL;
439 440
440 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, 441 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
441 config_cb); 442 config_cb);
442 if (getenv("SCRIPT_NAME")) 443 if (getenv("SCRIPT_NAME"))
443 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME")); 444 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));
444 if (getenv("QUERY_STRING")) 445 if (getenv("QUERY_STRING"))
445 ctx.qry.raw = xstrdup(getenv("QUERY_STRING")); 446 ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));
446 cgit_parse_args(argc, argv); 447 cgit_parse_args(argc, argv);
447 cgit_parse_query(ctx.qry.raw, querystring_cb); 448 http_parse_querystring(ctx.qry.raw, querystring_cb);
448 if (!cgit_prepare_cache(&item)) 449 if (!cgit_prepare_cache(&item))
449 return 0; 450 return 0;
450 if (ctx.cfg.nocache) { 451 if (ctx.cfg.nocache) {
451 cgit_fill_cache(&item, 0); 452 cgit_fill_cache(&item, 0);
452 } else { 453 } else {
453 cgit_check_cache(&item); 454 cgit_check_cache(&item);
454 cgit_print_cache(&item); 455 cgit_print_cache(&item);
455 } 456 }
456 return 0; 457 return 0;
457} 458}
diff --git a/cgit.h b/cgit.h
index 91d18f8..ee8c716 100644
--- a/cgit.h
+++ b/cgit.h
@@ -98,129 +98,127 @@ struct refinfo {
98}; 98};
99 99
100struct reflist { 100struct reflist {
101 struct refinfo **refs; 101 struct refinfo **refs;
102 int alloc; 102 int alloc;
103 int count; 103 int count;
104}; 104};
105 105
106struct cgit_query { 106struct cgit_query {
107 int has_symref; 107 int has_symref;
108 int has_sha1; 108 int has_sha1;
109 char *raw; 109 char *raw;
110 char *repo; 110 char *repo;
111 char *page; 111 char *page;
112 char *search; 112 char *search;
113 char *grep; 113 char *grep;
114 char *head; 114 char *head;
115 char *sha1; 115 char *sha1;
116 char *sha2; 116 char *sha2;
117 char *path; 117 char *path;
118 char *name; 118 char *name;
119 int ofs; 119 int ofs;
120}; 120};
121 121
122struct cgit_config { 122struct cgit_config {
123 char *agefile; 123 char *agefile;
124 char *cache_root; 124 char *cache_root;
125 char *clone_prefix; 125 char *clone_prefix;
126 char *css; 126 char *css;
127 char *index_header; 127 char *index_header;
128 char *index_info; 128 char *index_info;
129 char *logo; 129 char *logo;
130 char *logo_link; 130 char *logo_link;
131 char *module_link; 131 char *module_link;
132 char *repo_group; 132 char *repo_group;
133 char *robots; 133 char *robots;
134 char *root_title; 134 char *root_title;
135 char *script_name; 135 char *script_name;
136 char *virtual_root; 136 char *virtual_root;
137 int cache_dynamic_ttl; 137 int cache_dynamic_ttl;
138 int cache_max_create_time; 138 int cache_max_create_time;
139 int cache_repo_ttl; 139 int cache_repo_ttl;
140 int cache_root_ttl; 140 int cache_root_ttl;
141 int cache_static_ttl; 141 int cache_static_ttl;
142 int enable_index_links; 142 int enable_index_links;
143 int enable_log_filecount; 143 int enable_log_filecount;
144 int enable_log_linecount; 144 int enable_log_linecount;
145 int max_commit_count; 145 int max_commit_count;
146 int max_lock_attempts; 146 int max_lock_attempts;
147 int max_msg_len; 147 int max_msg_len;
148 int max_repodesc_len; 148 int max_repodesc_len;
149 int nocache; 149 int nocache;
150 int renamelimit; 150 int renamelimit;
151 int snapshots; 151 int snapshots;
152 int summary_branches; 152 int summary_branches;
153 int summary_log; 153 int summary_log;
154 int summary_tags; 154 int summary_tags;
155}; 155};
156 156
157struct cgit_page { 157struct cgit_page {
158 time_t modified; 158 time_t modified;
159 time_t expires; 159 time_t expires;
160 char *mimetype; 160 char *mimetype;
161 char *charset; 161 char *charset;
162 char *filename; 162 char *filename;
163 char *title; 163 char *title;
164}; 164};
165 165
166struct cgit_context { 166struct cgit_context {
167 struct cgit_query qry; 167 struct cgit_query qry;
168 struct cgit_config cfg; 168 struct cgit_config cfg;
169 struct cgit_repo *repo; 169 struct cgit_repo *repo;
170 struct cgit_page page; 170 struct cgit_page page;
171}; 171};
172 172
173struct cgit_snapshot_format { 173struct cgit_snapshot_format {
174 const char *suffix; 174 const char *suffix;
175 const char *mimetype; 175 const char *mimetype;
176 write_archive_fn_t write_func; 176 write_archive_fn_t write_func;
177 int bit; 177 int bit;
178}; 178};
179 179
180extern const char *cgit_version; 180extern const char *cgit_version;
181 181
182extern struct cgit_repolist cgit_repolist; 182extern struct cgit_repolist cgit_repolist;
183extern struct cgit_context ctx; 183extern struct cgit_context ctx;
184extern const struct cgit_snapshot_format cgit_snapshot_formats[]; 184extern const struct cgit_snapshot_format cgit_snapshot_formats[];
185 185
186extern struct cgit_repo *cgit_add_repo(const char *url); 186extern struct cgit_repo *cgit_add_repo(const char *url);
187extern struct cgit_repo *cgit_get_repoinfo(const char *url); 187extern struct cgit_repo *cgit_get_repoinfo(const char *url);
188extern void cgit_repo_config_cb(const char *name, const char *value); 188extern void cgit_repo_config_cb(const char *name, const char *value);
189 189
190extern int chk_zero(int result, char *msg); 190extern int chk_zero(int result, char *msg);
191extern int chk_positive(int result, char *msg); 191extern int chk_positive(int result, char *msg);
192extern int chk_non_negative(int result, char *msg); 192extern int chk_non_negative(int result, char *msg);
193 193
194extern int hextoint(char c);
195extern char *trim_end(const char *str, char c); 194extern char *trim_end(const char *str, char c);
196extern char *strlpart(char *txt, int maxlen); 195extern char *strlpart(char *txt, int maxlen);
197extern char *strrpart(char *txt, int maxlen); 196extern char *strrpart(char *txt, int maxlen);
198 197
199extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 198extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
200extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 199extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
201 int flags, void *cb_data); 200 int flags, void *cb_data);
202 201
203extern void *cgit_free_commitinfo(struct commitinfo *info); 202extern void *cgit_free_commitinfo(struct commitinfo *info);
204 203
205extern int cgit_diff_files(const unsigned char *old_sha1, 204extern int cgit_diff_files(const unsigned char *old_sha1,
206 const unsigned char *new_sha1, 205 const unsigned char *new_sha1,
207 linediff_fn fn); 206 linediff_fn fn);
208 207
209extern void cgit_diff_tree(const unsigned char *old_sha1, 208extern void cgit_diff_tree(const unsigned char *old_sha1,
210 const unsigned char *new_sha1, 209 const unsigned char *new_sha1,
211 filepair_fn fn, const char *prefix); 210 filepair_fn fn, const char *prefix);
212 211
213extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 212extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
214 213
215extern char *fmt(const char *format,...); 214extern char *fmt(const char *format,...);
216 215
217extern int cgit_parse_query(char *txt, configfn fn);
218extern struct commitinfo *cgit_parse_commit(struct commit *commit); 216extern struct commitinfo *cgit_parse_commit(struct commit *commit);
219extern struct taginfo *cgit_parse_tag(struct tag *tag); 217extern struct taginfo *cgit_parse_tag(struct tag *tag);
220extern void cgit_parse_url(const char *url); 218extern void cgit_parse_url(const char *url);
221 219
222extern const char *cgit_repobasename(const char *reponame); 220extern const char *cgit_repobasename(const char *reponame);
223 221
224extern int cgit_parse_snapshots_mask(const char *str); 222extern int cgit_parse_snapshots_mask(const char *str);
225 223
226#endif /* CGIT_H */ 224#endif /* CGIT_H */
diff --git a/html.c b/html.c
index 0962e71..98ffaf9 100644
--- a/html.c
+++ b/html.c
@@ -92,96 +92,160 @@ void html_ntxt(int len, char *txt)
92 } 92 }
93 t++; 93 t++;
94 } 94 }
95 if (t!=txt) { 95 if (t!=txt) {
96 char c = *t; 96 char c = *t;
97 *t = '\0'; 97 *t = '\0';
98 html(txt); 98 html(txt);
99 *t = c; 99 *t = c;
100 } 100 }
101 if (len<0) 101 if (len<0)
102 html("..."); 102 html("...");
103} 103}
104 104
105void html_attr(char *txt) 105void html_attr(char *txt)
106{ 106{
107 char *t = txt; 107 char *t = txt;
108 while(t && *t){ 108 while(t && *t){
109 int c = *t; 109 int c = *t;
110 if (c=='<' || c=='>' || c=='\'') { 110 if (c=='<' || c=='>' || c=='\'') {
111 *t = '\0'; 111 *t = '\0';
112 html(txt); 112 html(txt);
113 *t = c; 113 *t = c;
114 if (c=='>') 114 if (c=='>')
115 html("&gt;"); 115 html("&gt;");
116 else if (c=='<') 116 else if (c=='<')
117 html("&lt;"); 117 html("&lt;");
118 else if (c=='\'') 118 else if (c=='\'')
119 html("&quote;"); 119 html("&quote;");
120 txt = t+1; 120 txt = t+1;
121 } 121 }
122 t++; 122 t++;
123 } 123 }
124 if (t!=txt) 124 if (t!=txt)
125 html(txt); 125 html(txt);
126} 126}
127 127
128void html_hidden(char *name, char *value) 128void html_hidden(char *name, char *value)
129{ 129{
130 html("<input type='hidden' name='"); 130 html("<input type='hidden' name='");
131 html_attr(name); 131 html_attr(name);
132 html("' value='"); 132 html("' value='");
133 html_attr(value); 133 html_attr(value);
134 html("'/>"); 134 html("'/>");
135} 135}
136 136
137void html_option(char *value, char *text, char *selected_value) 137void html_option(char *value, char *text, char *selected_value)
138{ 138{
139 html("<option value='"); 139 html("<option value='");
140 html_attr(value); 140 html_attr(value);
141 html("'"); 141 html("'");
142 if (selected_value && !strcmp(selected_value, value)) 142 if (selected_value && !strcmp(selected_value, value))
143 html(" selected='selected'"); 143 html(" selected='selected'");
144 html(">"); 144 html(">");
145 html_txt(text); 145 html_txt(text);
146 html("</option>\n"); 146 html("</option>\n");
147} 147}
148 148
149void html_link_open(char *url, char *title, char *class) 149void html_link_open(char *url, char *title, char *class)
150{ 150{
151 html("<a href='"); 151 html("<a href='");
152 html_attr(url); 152 html_attr(url);
153 if (title) { 153 if (title) {
154 html("' title='"); 154 html("' title='");
155 html_attr(title); 155 html_attr(title);
156 } 156 }
157 if (class) { 157 if (class) {
158 html("' class='"); 158 html("' class='");
159 html_attr(class); 159 html_attr(class);
160 } 160 }
161 html("'>"); 161 html("'>");
162} 162}
163 163
164void html_link_close(void) 164void html_link_close(void)
165{ 165{
166 html("</a>"); 166 html("</a>");
167} 167}
168 168
169void html_fileperm(unsigned short mode) 169void html_fileperm(unsigned short mode)
170{ 170{
171 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'), 171 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
172 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-')); 172 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
173} 173}
174 174
175int html_include(const char *filename) 175int html_include(const char *filename)
176{ 176{
177 FILE *f; 177 FILE *f;
178 char buf[4096]; 178 char buf[4096];
179 size_t len; 179 size_t len;
180 180
181 if (!(f = fopen(filename, "r"))) 181 if (!(f = fopen(filename, "r")))
182 return -1; 182 return -1;
183 while((len = fread(buf, 1, 4096, f)) > 0) 183 while((len = fread(buf, 1, 4096, f)) > 0)
184 write(htmlfd, buf, len); 184 write(htmlfd, buf, len);
185 fclose(f); 185 fclose(f);
186 return 0; 186 return 0;
187} 187}
188
189int hextoint(char c)
190{
191 if (c >= 'a' && c <= 'f')
192 return 10 + c - 'a';
193 else if (c >= 'A' && c <= 'F')
194 return 10 + c - 'A';
195 else if (c >= '0' && c <= '9')
196 return c - '0';
197 else
198 return -1;
199}
200
201char *convert_query_hexchar(char *txt)
202{
203 int d1, d2;
204 if (strlen(txt) < 3) {
205 *txt = '\0';
206 return txt-1;
207 }
208 d1 = hextoint(*(txt+1));
209 d2 = hextoint(*(txt+2));
210 if (d1<0 || d2<0) {
211 strcpy(txt, txt+3);
212 return txt-1;
213 } else {
214 *txt = d1 * 16 + d2;
215 strcpy(txt+1, txt+3);
216 return txt;
217 }
218}
219
220int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value))
221{
222 char *t, *value = NULL, c;
223
224 if (!txt)
225 return 0;
226
227 t = txt = strdup(txt);
228 if (t == NULL) {
229 printf("Out of memory\n");
230 exit(1);
231 }
232 while((c=*t) != '\0') {
233 if (c=='=') {
234 *t = '\0';
235 value = t+1;
236 } else if (c=='+') {
237 *t = ' ';
238 } else if (c=='%') {
239 t = convert_query_hexchar(t);
240 } else if (c=='&') {
241 *t = '\0';
242 (*fn)(txt, value);
243 txt = t+1;
244 value = NULL;
245 }
246 t++;
247 }
248 if (t!=txt)
249 (*fn)(txt, value);
250 return 0;
251}
diff --git a/html.h b/html.h
index 63f4551..e6fdc54 100644
--- a/html.h
+++ b/html.h
@@ -1,18 +1,20 @@
1#ifndef HTML_H 1#ifndef HTML_H
2#define HTML_H 2#define HTML_H
3 3
4extern int htmlfd; 4extern int htmlfd;
5 5
6extern void html(const char *txt); 6extern void html(const char *txt);
7extern void htmlf(const char *format,...); 7extern void htmlf(const char *format,...);
8extern void html_txt(char *txt); 8extern void html_txt(char *txt);
9extern void html_ntxt(int len, char *txt); 9extern void html_ntxt(int len, char *txt);
10extern void html_attr(char *txt); 10extern void html_attr(char *txt);
11extern void html_hidden(char *name, char *value); 11extern void html_hidden(char *name, char *value);
12extern void html_option(char *value, char *text, char *selected_value); 12extern void html_option(char *value, char *text, char *selected_value);
13extern void html_link_open(char *url, char *title, char *class); 13extern void html_link_open(char *url, char *title, char *class);
14extern void html_link_close(void); 14extern void html_link_close(void);
15extern void html_fileperm(unsigned short mode); 15extern void html_fileperm(unsigned short mode);
16extern int html_include(const char *filename); 16extern int html_include(const char *filename);
17 17
18extern int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value));
19
18#endif /* HTML_H */ 20#endif /* HTML_H */
diff --git a/parsing.c b/parsing.c
index 9a4a7a3..66e8b3d 100644
--- a/parsing.c
+++ b/parsing.c
@@ -1,155 +1,106 @@
1/* config.c: parsing of config files 1/* config.c: parsing of config files
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
11char *convert_query_hexchar(char *txt)
12{
13 int d1, d2;
14 if (strlen(txt) < 3) {
15 *txt = '\0';
16 return txt-1;
17 }
18 d1 = hextoint(*(txt+1));
19 d2 = hextoint(*(txt+2));
20 if (d1<0 || d2<0) {
21 strcpy(txt, txt+3);
22 return txt-1;
23 } else {
24 *txt = d1 * 16 + d2;
25 strcpy(txt+1, txt+3);
26 return txt;
27 }
28}
29
30int cgit_parse_query(char *txt, configfn fn)
31{
32 char *t, *value = NULL, c;
33
34 if (!txt)
35 return 0;
36
37 t = txt = xstrdup(txt);
38
39 while((c=*t) != '\0') {
40 if (c=='=') {
41 *t = '\0';
42 value = t+1;
43 } else if (c=='+') {
44 *t = ' ';
45 } else if (c=='%') {
46 t = convert_query_hexchar(t);
47 } else if (c=='&') {
48 *t = '\0';
49 (*fn)(txt, value);
50 txt = t+1;
51 value = NULL;
52 }
53 t++;
54 }
55 if (t!=txt)
56 (*fn)(txt, value);
57 return 0;
58}
59
60/* 11/*
61 * url syntax: [repo ['/' cmd [ '/' path]]] 12 * url syntax: [repo ['/' cmd [ '/' path]]]
62 * repo: any valid repo url, may contain '/' 13 * repo: any valid repo url, may contain '/'
63 * cmd: log | commit | diff | tree | view | blob | snapshot 14 * cmd: log | commit | diff | tree | view | blob | snapshot
64 * path: any valid path, may contain '/' 15 * path: any valid path, may contain '/'
65 * 16 *
66 */ 17 */
67void cgit_parse_url(const char *url) 18void cgit_parse_url(const char *url)
68{ 19{
69 char *cmd, *p; 20 char *cmd, *p;
70 21
71 ctx.repo = NULL; 22 ctx.repo = NULL;
72 if (!url || url[0] == '\0') 23 if (!url || url[0] == '\0')
73 return; 24 return;
74 25
75 ctx.repo = cgit_get_repoinfo(url); 26 ctx.repo = cgit_get_repoinfo(url);
76 if (ctx.repo) { 27 if (ctx.repo) {
77 ctx.qry.repo = ctx.repo->url; 28 ctx.qry.repo = ctx.repo->url;
78 return; 29 return;
79 } 30 }
80 31
81 cmd = strchr(url, '/'); 32 cmd = strchr(url, '/');
82 while (!ctx.repo && cmd) { 33 while (!ctx.repo && cmd) {
83 cmd[0] = '\0'; 34 cmd[0] = '\0';
84 ctx.repo = cgit_get_repoinfo(url); 35 ctx.repo = cgit_get_repoinfo(url);
85 if (ctx.repo == NULL) { 36 if (ctx.repo == NULL) {
86 cmd[0] = '/'; 37 cmd[0] = '/';
87 cmd = strchr(cmd + 1, '/'); 38 cmd = strchr(cmd + 1, '/');
88 continue; 39 continue;
89 } 40 }
90 41
91 ctx.qry.repo = ctx.repo->url; 42 ctx.qry.repo = ctx.repo->url;
92 p = strchr(cmd + 1, '/'); 43 p = strchr(cmd + 1, '/');
93 if (p) { 44 if (p) {
94 p[0] = '\0'; 45 p[0] = '\0';
95 if (p[1]) 46 if (p[1])
96 ctx.qry.path = trim_end(p + 1, '/'); 47 ctx.qry.path = trim_end(p + 1, '/');
97 } 48 }
98 if (cmd[1]) 49 if (cmd[1])
99 ctx.qry.page = xstrdup(cmd + 1); 50 ctx.qry.page = xstrdup(cmd + 1);
100 return; 51 return;
101 } 52 }
102} 53}
103 54
104char *substr(const char *head, const char *tail) 55char *substr(const char *head, const char *tail)
105{ 56{
106 char *buf; 57 char *buf;
107 58
108 buf = xmalloc(tail - head + 1); 59 buf = xmalloc(tail - head + 1);
109 strncpy(buf, head, tail - head); 60 strncpy(buf, head, tail - head);
110 buf[tail - head] = '\0'; 61 buf[tail - head] = '\0';
111 return buf; 62 return buf;
112} 63}
113 64
114struct commitinfo *cgit_parse_commit(struct commit *commit) 65struct commitinfo *cgit_parse_commit(struct commit *commit)
115{ 66{
116 struct commitinfo *ret; 67 struct commitinfo *ret;
117 char *p = commit->buffer, *t = commit->buffer; 68 char *p = commit->buffer, *t = commit->buffer;
118 69
119 ret = xmalloc(sizeof(*ret)); 70 ret = xmalloc(sizeof(*ret));
120 ret->commit = commit; 71 ret->commit = commit;
121 ret->author = NULL; 72 ret->author = NULL;
122 ret->author_email = NULL; 73 ret->author_email = NULL;
123 ret->committer = NULL; 74 ret->committer = NULL;
124 ret->committer_email = NULL; 75 ret->committer_email = NULL;
125 ret->subject = NULL; 76 ret->subject = NULL;
126 ret->msg = NULL; 77 ret->msg = NULL;
127 ret->msg_encoding = NULL; 78 ret->msg_encoding = NULL;
128 79
129 if (p == NULL) 80 if (p == NULL)
130 return ret; 81 return ret;
131 82
132 if (strncmp(p, "tree ", 5)) 83 if (strncmp(p, "tree ", 5))
133 die("Bad commit: %s", sha1_to_hex(commit->object.sha1)); 84 die("Bad commit: %s", sha1_to_hex(commit->object.sha1));
134 else 85 else
135 p += 46; // "tree " + hex[40] + "\n" 86 p += 46; // "tree " + hex[40] + "\n"
136 87
137 while (!strncmp(p, "parent ", 7)) 88 while (!strncmp(p, "parent ", 7))
138 p += 48; // "parent " + hex[40] + "\n" 89 p += 48; // "parent " + hex[40] + "\n"
139 90
140 if (!strncmp(p, "author ", 7)) { 91 if (!strncmp(p, "author ", 7)) {
141 p += 7; 92 p += 7;
142 t = strchr(p, '<') - 1; 93 t = strchr(p, '<') - 1;
143 ret->author = substr(p, t); 94 ret->author = substr(p, t);
144 p = t; 95 p = t;
145 t = strchr(t, '>') + 1; 96 t = strchr(t, '>') + 1;
146 ret->author_email = substr(p, t); 97 ret->author_email = substr(p, t);
147 ret->author_date = atol(t+1); 98 ret->author_date = atol(t+1);
148 p = strchr(t, '\n') + 1; 99 p = strchr(t, '\n') + 1;
149 } 100 }
150 101
151 if (!strncmp(p, "committer ", 9)) { 102 if (!strncmp(p, "committer ", 9)) {
152 p += 9; 103 p += 9;
153 t = strchr(p, '<') - 1; 104 t = strchr(p, '<') - 1;
154 ret->committer = substr(p, t); 105 ret->committer = substr(p, t);
155 p = t; 106 p = t;
diff --git a/shared.c b/shared.c
index 48002ac..f5875e4 100644
--- a/shared.c
+++ b/shared.c
@@ -1,199 +1,187 @@
1/* shared.c: global vars + some callback functions 1/* shared.c: global vars + some callback functions
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11struct cgit_repolist cgit_repolist; 11struct cgit_repolist cgit_repolist;
12struct cgit_context ctx; 12struct cgit_context ctx;
13int cgit_cmd; 13int cgit_cmd;
14 14
15int chk_zero(int result, char *msg) 15int chk_zero(int result, char *msg)
16{ 16{
17 if (result != 0) 17 if (result != 0)
18 die("%s: %s", msg, strerror(errno)); 18 die("%s: %s", msg, strerror(errno));
19 return result; 19 return result;
20} 20}
21 21
22int chk_positive(int result, char *msg) 22int chk_positive(int result, char *msg)
23{ 23{
24 if (result <= 0) 24 if (result <= 0)
25 die("%s: %s", msg, strerror(errno)); 25 die("%s: %s", msg, strerror(errno));
26 return result; 26 return result;
27} 27}
28 28
29int chk_non_negative(int result, char *msg) 29int chk_non_negative(int result, char *msg)
30{ 30{
31 if (result < 0) 31 if (result < 0)
32 die("%s: %s",msg, strerror(errno)); 32 die("%s: %s",msg, strerror(errno));
33 return result; 33 return result;
34} 34}
35 35
36struct cgit_repo *cgit_add_repo(const char *url) 36struct cgit_repo *cgit_add_repo(const char *url)
37{ 37{
38 struct cgit_repo *ret; 38 struct cgit_repo *ret;
39 39
40 if (++cgit_repolist.count > cgit_repolist.length) { 40 if (++cgit_repolist.count > cgit_repolist.length) {
41 if (cgit_repolist.length == 0) 41 if (cgit_repolist.length == 0)
42 cgit_repolist.length = 8; 42 cgit_repolist.length = 8;
43 else 43 else
44 cgit_repolist.length *= 2; 44 cgit_repolist.length *= 2;
45 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 45 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
46 cgit_repolist.length * 46 cgit_repolist.length *
47 sizeof(struct cgit_repo)); 47 sizeof(struct cgit_repo));
48 } 48 }
49 49
50 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 50 ret = &cgit_repolist.repos[cgit_repolist.count-1];
51 ret->url = trim_end(url, '/'); 51 ret->url = trim_end(url, '/');
52 ret->name = ret->url; 52 ret->name = ret->url;
53 ret->path = NULL; 53 ret->path = NULL;
54 ret->desc = "[no description]"; 54 ret->desc = "[no description]";
55 ret->owner = NULL; 55 ret->owner = NULL;
56 ret->group = ctx.cfg.repo_group; 56 ret->group = ctx.cfg.repo_group;
57 ret->defbranch = "master"; 57 ret->defbranch = "master";
58 ret->snapshots = ctx.cfg.snapshots; 58 ret->snapshots = ctx.cfg.snapshots;
59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount; 60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
61 ret->module_link = ctx.cfg.module_link; 61 ret->module_link = ctx.cfg.module_link;
62 ret->readme = NULL; 62 ret->readme = NULL;
63 return ret; 63 return ret;
64} 64}
65 65
66struct cgit_repo *cgit_get_repoinfo(const char *url) 66struct cgit_repo *cgit_get_repoinfo(const char *url)
67{ 67{
68 int i; 68 int i;
69 struct cgit_repo *repo; 69 struct cgit_repo *repo;
70 70
71 for (i=0; i<cgit_repolist.count; i++) { 71 for (i=0; i<cgit_repolist.count; i++) {
72 repo = &cgit_repolist.repos[i]; 72 repo = &cgit_repolist.repos[i];
73 if (!strcmp(repo->url, url)) 73 if (!strcmp(repo->url, url))
74 return repo; 74 return repo;
75 } 75 }
76 return NULL; 76 return NULL;
77} 77}
78 78
79void *cgit_free_commitinfo(struct commitinfo *info) 79void *cgit_free_commitinfo(struct commitinfo *info)
80{ 80{
81 free(info->author); 81 free(info->author);
82 free(info->author_email); 82 free(info->author_email);
83 free(info->committer); 83 free(info->committer);
84 free(info->committer_email); 84 free(info->committer_email);
85 free(info->subject); 85 free(info->subject);
86 free(info->msg); 86 free(info->msg);
87 free(info->msg_encoding); 87 free(info->msg_encoding);
88 free(info); 88 free(info);
89 return NULL; 89 return NULL;
90} 90}
91 91
92int hextoint(char c)
93{
94 if (c >= 'a' && c <= 'f')
95 return 10 + c - 'a';
96 else if (c >= 'A' && c <= 'F')
97 return 10 + c - 'A';
98 else if (c >= '0' && c <= '9')
99 return c - '0';
100 else
101 return -1;
102}
103
104char *trim_end(const char *str, char c) 92char *trim_end(const char *str, char c)
105{ 93{
106 int len; 94 int len;
107 char *s, *t; 95 char *s, *t;
108 96
109 if (str == NULL) 97 if (str == NULL)
110 return NULL; 98 return NULL;
111 t = (char *)str; 99 t = (char *)str;
112 len = strlen(t); 100 len = strlen(t);
113 while(len > 0 && t[len - 1] == c) 101 while(len > 0 && t[len - 1] == c)
114 len--; 102 len--;
115 103
116 if (len == 0) 104 if (len == 0)
117 return NULL; 105 return NULL;
118 106
119 c = t[len]; 107 c = t[len];
120 t[len] = '\0'; 108 t[len] = '\0';
121 s = xstrdup(t); 109 s = xstrdup(t);
122 t[len] = c; 110 t[len] = c;
123 return s; 111 return s;
124} 112}
125 113
126char *strlpart(char *txt, int maxlen) 114char *strlpart(char *txt, int maxlen)
127{ 115{
128 char *result; 116 char *result;
129 117
130 if (!txt) 118 if (!txt)
131 return txt; 119 return txt;
132 120
133 if (strlen(txt) <= maxlen) 121 if (strlen(txt) <= maxlen)
134 return txt; 122 return txt;
135 result = xmalloc(maxlen + 1); 123 result = xmalloc(maxlen + 1);
136 memcpy(result, txt, maxlen - 3); 124 memcpy(result, txt, maxlen - 3);
137 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.'; 125 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.';
138 result[maxlen] = '\0'; 126 result[maxlen] = '\0';
139 return result; 127 return result;
140} 128}
141 129
142char *strrpart(char *txt, int maxlen) 130char *strrpart(char *txt, int maxlen)
143{ 131{
144 char *result; 132 char *result;
145 133
146 if (!txt) 134 if (!txt)
147 return txt; 135 return txt;
148 136
149 if (strlen(txt) <= maxlen) 137 if (strlen(txt) <= maxlen)
150 return txt; 138 return txt;
151 result = xmalloc(maxlen + 1); 139 result = xmalloc(maxlen + 1);
152 memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3); 140 memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3);
153 result[0] = result[1] = result[2] = '.'; 141 result[0] = result[1] = result[2] = '.';
154 return result; 142 return result;
155} 143}
156 144
157void cgit_add_ref(struct reflist *list, struct refinfo *ref) 145void cgit_add_ref(struct reflist *list, struct refinfo *ref)
158{ 146{
159 size_t size; 147 size_t size;
160 148
161 if (list->count >= list->alloc) { 149 if (list->count >= list->alloc) {
162 list->alloc += (list->alloc ? list->alloc : 4); 150 list->alloc += (list->alloc ? list->alloc : 4);
163 size = list->alloc * sizeof(struct refinfo *); 151 size = list->alloc * sizeof(struct refinfo *);
164 list->refs = xrealloc(list->refs, size); 152 list->refs = xrealloc(list->refs, size);
165 } 153 }
166 list->refs[list->count++] = ref; 154 list->refs[list->count++] = ref;
167} 155}
168 156
169struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1) 157struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1)
170{ 158{
171 struct refinfo *ref; 159 struct refinfo *ref;
172 160
173 ref = xmalloc(sizeof (struct refinfo)); 161 ref = xmalloc(sizeof (struct refinfo));
174 ref->refname = xstrdup(refname); 162 ref->refname = xstrdup(refname);
175 ref->object = parse_object(sha1); 163 ref->object = parse_object(sha1);
176 switch (ref->object->type) { 164 switch (ref->object->type) {
177 case OBJ_TAG: 165 case OBJ_TAG:
178 ref->tag = cgit_parse_tag((struct tag *)ref->object); 166 ref->tag = cgit_parse_tag((struct tag *)ref->object);
179 break; 167 break;
180 case OBJ_COMMIT: 168 case OBJ_COMMIT:
181 ref->commit = cgit_parse_commit((struct commit *)ref->object); 169 ref->commit = cgit_parse_commit((struct commit *)ref->object);
182 break; 170 break;
183 } 171 }
184 return ref; 172 return ref;
185} 173}
186 174
187int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags, 175int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags,
188 void *cb_data) 176 void *cb_data)
189{ 177{
190 struct reflist *list = (struct reflist *)cb_data; 178 struct reflist *list = (struct reflist *)cb_data;
191 struct refinfo *info = cgit_mk_refinfo(refname, sha1); 179 struct refinfo *info = cgit_mk_refinfo(refname, sha1);
192 180
193 if (info) 181 if (info)
194 cgit_add_ref(list, info); 182 cgit_add_ref(list, info);
195 return 0; 183 return 0;
196} 184}
197 185
198void cgit_diff_tree_cb(struct diff_queue_struct *q, 186void cgit_diff_tree_cb(struct diff_queue_struct *q,
199 struct diff_options *options, void *data) 187 struct diff_options *options, void *data)