summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile4
-rw-r--r--cgit.c5
-rw-r--r--html.c2
-rw-r--r--ui-shared.c2
4 files changed, 7 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index a988751..14b4df4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,244 +1,244 @@
1CGIT_VERSION = v0.8.3.4 1CGIT_VERSION = v0.8.3.5
2CGIT_SCRIPT_NAME = cgit.cgi 2CGIT_SCRIPT_NAME = cgit.cgi
3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit 3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) 4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
5CGIT_CONFIG = /etc/cgitrc 5CGIT_CONFIG = /etc/cgitrc
6CACHE_ROOT = /var/cache/cgit 6CACHE_ROOT = /var/cache/cgit
7prefix = /usr 7prefix = /usr
8libdir = $(prefix)/lib 8libdir = $(prefix)/lib
9filterdir = $(libdir)/cgit/filters 9filterdir = $(libdir)/cgit/filters
10docdir = $(prefix)/share/doc/cgit 10docdir = $(prefix)/share/doc/cgit
11htmldir = $(docdir) 11htmldir = $(docdir)
12pdfdir = $(docdir) 12pdfdir = $(docdir)
13mandir = $(prefix)/share/man 13mandir = $(prefix)/share/man
14SHA1_HEADER = <openssl/sha.h> 14SHA1_HEADER = <openssl/sha.h>
15GIT_VER = 1.7.4 15GIT_VER = 1.7.4
16GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 16GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
17INSTALL = install 17INSTALL = install
18MAN5_TXT = $(wildcard *.5.txt) 18MAN5_TXT = $(wildcard *.5.txt)
19MAN_TXT = $(MAN5_TXT) 19MAN_TXT = $(MAN5_TXT)
20DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT)) 20DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT))
21DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT)) 21DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
22DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT)) 22DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT))
23 23
24# Define NO_STRCASESTR if you don't have strcasestr. 24# Define NO_STRCASESTR if you don't have strcasestr.
25# 25#
26# Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1 26# Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1
27# implementation (slower). 27# implementation (slower).
28# 28#
29# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). 29# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin).
30# 30#
31# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) 31# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
32# do not support the 'size specifiers' introduced by C99, namely ll, hh, 32# do not support the 'size specifiers' introduced by C99, namely ll, hh,
33# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). 33# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
34# some C compilers supported these specifiers prior to C99 as an extension. 34# some C compilers supported these specifiers prior to C99 as an extension.
35# 35#
36 36
37#-include config.mak 37#-include config.mak
38 38
39# 39#
40# Platform specific tweaks 40# Platform specific tweaks
41# 41#
42 42
43uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 43uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
44uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') 44uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
45uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') 45uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
46 46
47ifeq ($(uname_O),Cygwin) 47ifeq ($(uname_O),Cygwin)
48 NO_STRCASESTR = YesPlease 48 NO_STRCASESTR = YesPlease
49 NEEDS_LIBICONV = YesPlease 49 NEEDS_LIBICONV = YesPlease
50endif 50endif
51 51
52# 52#
53# Let the user override the above settings. 53# Let the user override the above settings.
54# 54#
55-include cgit.conf 55-include cgit.conf
56 56
57# 57#
58# Define a way to invoke make in subdirs quietly, shamelessly ripped 58# Define a way to invoke make in subdirs quietly, shamelessly ripped
59# from git.git 59# from git.git
60# 60#
61QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir 61QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
62QUIET_SUBDIR1 = 62QUIET_SUBDIR1 =
63 63
64ifneq ($(findstring $(MAKEFLAGS),w),w) 64ifneq ($(findstring $(MAKEFLAGS),w),w)
65PRINT_DIR = --no-print-directory 65PRINT_DIR = --no-print-directory
66else # "make -w" 66else # "make -w"
67NO_SUBDIR = : 67NO_SUBDIR = :
68endif 68endif
69 69
70ifndef V 70ifndef V
71 QUIET_CC = @echo ' ' CC $@; 71 QUIET_CC = @echo ' ' CC $@;
72 QUIET_MM = @echo ' ' MM $@; 72 QUIET_MM = @echo ' ' MM $@;
73 QUIET_SUBDIR0 = +@subdir= 73 QUIET_SUBDIR0 = +@subdir=
74 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ 74 QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
75 $(MAKE) $(PRINT_DIR) -C $$subdir 75 $(MAKE) $(PRINT_DIR) -C $$subdir
76endif 76endif
77 77
78# 78#
79# Define a pattern rule for automatic dependency building 79# Define a pattern rule for automatic dependency building
80# 80#
81%.d: %.c 81%.d: %.c
82 $(QUIET_MM)$(CC) $(CFLAGS) -MM -MP $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@ 82 $(QUIET_MM)$(CC) $(CFLAGS) -MM -MP $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@
83 83
84# 84#
85# Define a pattern rule for silent object building 85# Define a pattern rule for silent object building
86# 86#
87%.o: %.c 87%.o: %.c
88 $(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $< 88 $(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $<
89 89
90 90
91EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lpthread 91EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lpthread
92OBJECTS = 92OBJECTS =
93OBJECTS += cache.o 93OBJECTS += cache.o
94OBJECTS += cgit.o 94OBJECTS += cgit.o
95OBJECTS += cmd.o 95OBJECTS += cmd.o
96OBJECTS += configfile.o 96OBJECTS += configfile.o
97OBJECTS += html.o 97OBJECTS += html.o
98OBJECTS += parsing.o 98OBJECTS += parsing.o
99OBJECTS += scan-tree.o 99OBJECTS += scan-tree.o
100OBJECTS += shared.o 100OBJECTS += shared.o
101OBJECTS += ui-atom.o 101OBJECTS += ui-atom.o
102OBJECTS += ui-blob.o 102OBJECTS += ui-blob.o
103OBJECTS += ui-clone.o 103OBJECTS += ui-clone.o
104OBJECTS += ui-commit.o 104OBJECTS += ui-commit.o
105OBJECTS += ui-diff.o 105OBJECTS += ui-diff.o
106OBJECTS += ui-log.o 106OBJECTS += ui-log.o
107OBJECTS += ui-patch.o 107OBJECTS += ui-patch.o
108OBJECTS += ui-plain.o 108OBJECTS += ui-plain.o
109OBJECTS += ui-refs.o 109OBJECTS += ui-refs.o
110OBJECTS += ui-repolist.o 110OBJECTS += ui-repolist.o
111OBJECTS += ui-shared.o 111OBJECTS += ui-shared.o
112OBJECTS += ui-snapshot.o 112OBJECTS += ui-snapshot.o
113OBJECTS += ui-ssdiff.o 113OBJECTS += ui-ssdiff.o
114OBJECTS += ui-stats.o 114OBJECTS += ui-stats.o
115OBJECTS += ui-summary.o 115OBJECTS += ui-summary.o
116OBJECTS += ui-tag.o 116OBJECTS += ui-tag.o
117OBJECTS += ui-tree.o 117OBJECTS += ui-tree.o
118OBJECTS += vector.o 118OBJECTS += vector.o
119 119
120ifdef NEEDS_LIBICONV 120ifdef NEEDS_LIBICONV
121 EXTLIBS += -liconv 121 EXTLIBS += -liconv
122endif 122endif
123 123
124 124
125.PHONY: all libgit test install uninstall clean force-version get-git \ 125.PHONY: all libgit test install uninstall clean force-version get-git \
126 doc clean-doc install-doc install-man install-html install-pdf \ 126 doc clean-doc install-doc install-man install-html install-pdf \
127 uninstall-doc uninstall-man uninstall-html uninstall-pdf 127 uninstall-doc uninstall-man uninstall-html uninstall-pdf
128 128
129all: cgit 129all: cgit
130 130
131VERSION: force-version 131VERSION: force-version
132 @./gen-version.sh "$(CGIT_VERSION)" 132 @./gen-version.sh "$(CGIT_VERSION)"
133-include VERSION 133-include VERSION
134 134
135 135
136CFLAGS += -g -Wall -Igit 136CFLAGS += -g -Wall -Igit
137CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)' 137CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)'
138CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"' 138CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"'
139CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' 139CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
140CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' 140CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
141CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' 141CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
142 142
143GIT_OPTIONS = prefix=/usr 143GIT_OPTIONS = prefix=/usr
144 144
145ifdef NO_ICONV 145ifdef NO_ICONV
146 CFLAGS += -DNO_ICONV 146 CFLAGS += -DNO_ICONV
147endif 147endif
148ifdef NO_STRCASESTR 148ifdef NO_STRCASESTR
149 CFLAGS += -DNO_STRCASESTR 149 CFLAGS += -DNO_STRCASESTR
150endif 150endif
151ifdef NO_C99_FORMAT 151ifdef NO_C99_FORMAT
152 CFLAGS += -DNO_C99_FORMAT 152 CFLAGS += -DNO_C99_FORMAT
153endif 153endif
154ifdef NO_OPENSSL 154ifdef NO_OPENSSL
155 CFLAGS += -DNO_OPENSSL 155 CFLAGS += -DNO_OPENSSL
156 GIT_OPTIONS += NO_OPENSSL=1 156 GIT_OPTIONS += NO_OPENSSL=1
157else 157else
158 EXTLIBS += -lcrypto 158 EXTLIBS += -lcrypto
159endif 159endif
160 160
161cgit: $(OBJECTS) libgit 161cgit: $(OBJECTS) libgit
162 $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) 162 $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS)
163 163
164cgit.o: VERSION 164cgit.o: VERSION
165 165
166ifneq "$(MAKECMDGOALS)" "clean" 166ifneq "$(MAKECMDGOALS)" "clean"
167 -include $(OBJECTS:.o=.d) 167 -include $(OBJECTS:.o=.d)
168endif 168endif
169 169
170libgit: 170libgit:
171 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) libgit.a 171 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) libgit.a
172 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) xdiff/lib.a 172 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) xdiff/lib.a
173 173
174test: all 174test: all
175 $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all 175 $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all
176 176
177install: all 177install: all
178 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_SCRIPT_PATH) 178 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_SCRIPT_PATH)
179 $(INSTALL) -m 0755 cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 179 $(INSTALL) -m 0755 cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
180 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH) 180 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH)
181 $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css 181 $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css
182 $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png 182 $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png
183 $(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir) 183 $(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir)
184 $(INSTALL) -m 0755 filters/* $(DESTDIR)$(filterdir) 184 $(INSTALL) -m 0755 filters/* $(DESTDIR)$(filterdir)
185 185
186install-doc: install-man install-html install-pdf 186install-doc: install-man install-html install-pdf
187 187
188install-man: doc-man 188install-man: doc-man
189 $(INSTALL) -m 0755 -d $(DESTDIR)$(mandir)/man5 189 $(INSTALL) -m 0755 -d $(DESTDIR)$(mandir)/man5
190 $(INSTALL) -m 0644 $(DOC_MAN5) $(DESTDIR)$(mandir)/man5 190 $(INSTALL) -m 0644 $(DOC_MAN5) $(DESTDIR)$(mandir)/man5
191 191
192install-html: doc-html 192install-html: doc-html
193 $(INSTALL) -m 0755 -d $(DESTDIR)$(htmldir) 193 $(INSTALL) -m 0755 -d $(DESTDIR)$(htmldir)
194 $(INSTALL) -m 0644 $(DOC_HTML) $(DESTDIR)$(htmldir) 194 $(INSTALL) -m 0644 $(DOC_HTML) $(DESTDIR)$(htmldir)
195 195
196install-pdf: doc-pdf 196install-pdf: doc-pdf
197 $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir) 197 $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir)
198 $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir) 198 $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir)
199 199
200uninstall: 200uninstall:
201 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 201 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
202 rm -f $(CGIT_DATA_PATH)/cgit.css 202 rm -f $(CGIT_DATA_PATH)/cgit.css
203 rm -f $(CGIT_DATA_PATH)/cgit.png 203 rm -f $(CGIT_DATA_PATH)/cgit.png
204 204
205uninstall-doc: uninstall-man uninstall-html uninstall-pdf 205uninstall-doc: uninstall-man uninstall-html uninstall-pdf
206 206
207uninstall-man: 207uninstall-man:
208 @for i in $(DOC_MAN5); do \ 208 @for i in $(DOC_MAN5); do \
209 rm -fv $(DESTDIR)$(mandir)/man5/$$i; \ 209 rm -fv $(DESTDIR)$(mandir)/man5/$$i; \
210 done 210 done
211 211
212uninstall-html: 212uninstall-html:
213 @for i in $(DOC_HTML); do \ 213 @for i in $(DOC_HTML); do \
214 rm -fv $(DESTDIR)$(htmldir)/$$i; \ 214 rm -fv $(DESTDIR)$(htmldir)/$$i; \
215 done 215 done
216 216
217uninstall-pdf: 217uninstall-pdf:
218 @for i in $(DOC_PDF); do \ 218 @for i in $(DOC_PDF); do \
219 rm -fv $(DESTDIR)$(pdfdir)/$$i; \ 219 rm -fv $(DESTDIR)$(pdfdir)/$$i; \
220 done 220 done
221 221
222doc: doc-man doc-html doc-pdf 222doc: doc-man doc-html doc-pdf
223doc-man: doc-man5 223doc-man: doc-man5
224doc-man5: $(DOC_MAN5) 224doc-man5: $(DOC_MAN5)
225doc-html: $(DOC_HTML) 225doc-html: $(DOC_HTML)
226doc-pdf: $(DOC_PDF) 226doc-pdf: $(DOC_PDF)
227 227
228%.5 : %.5.txt 228%.5 : %.5.txt
229 a2x -f manpage $< 229 a2x -f manpage $<
230 230
231$(DOC_HTML): %.html : %.txt 231$(DOC_HTML): %.html : %.txt
232 a2x -f xhtml --stylesheet=cgit-doc.css $< 232 a2x -f xhtml --stylesheet=cgit-doc.css $<
233 233
234$(DOC_PDF): %.pdf : %.txt 234$(DOC_PDF): %.pdf : %.txt
235 a2x -f pdf cgitrc.5.txt 235 a2x -f pdf cgitrc.5.txt
236 236
237clean: clean-doc 237clean: clean-doc
238 rm -f cgit VERSION *.o *.d 238 rm -f cgit VERSION *.o *.d
239 239
240clean-doc: 240clean-doc:
241 rm -f cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo 241 rm -f cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo
242 242
243get-git: 243get-git:
244 curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git 244 curl $(GIT_URL) | tar -xjf - && rm -rf git && mv git-$(GIT_VER) git
diff --git a/cgit.c b/cgit.c
index 916feb4..f4dd6ef 100644
--- a/cgit.c
+++ b/cgit.c
@@ -563,229 +563,230 @@ void print_repo(FILE *f, struct cgit_repo *repo)
563 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); 563 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd);
564 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) 564 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter)
565 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); 565 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd);
566 if (repo->snapshots != ctx.cfg.snapshots) { 566 if (repo->snapshots != ctx.cfg.snapshots) {
567 char *tmp = build_snapshot_setting(repo->snapshots); 567 char *tmp = build_snapshot_setting(repo->snapshots);
568 fprintf(f, "repo.snapshots=%s\n", tmp); 568 fprintf(f, "repo.snapshots=%s\n", tmp);
569 free(tmp); 569 free(tmp);
570 } 570 }
571 if (repo->max_stats != ctx.cfg.max_stats) 571 if (repo->max_stats != ctx.cfg.max_stats)
572 fprintf(f, "repo.max-stats=%s\n", 572 fprintf(f, "repo.max-stats=%s\n",
573 cgit_find_stats_periodname(repo->max_stats)); 573 cgit_find_stats_periodname(repo->max_stats));
574 fprintf(f, "\n"); 574 fprintf(f, "\n");
575} 575}
576 576
577void print_repolist(FILE *f, struct cgit_repolist *list, int start) 577void print_repolist(FILE *f, struct cgit_repolist *list, int start)
578{ 578{
579 int i; 579 int i;
580 580
581 for(i = start; i < list->count; i++) 581 for(i = start; i < list->count; i++)
582 print_repo(f, &list->repos[i]); 582 print_repo(f, &list->repos[i]);
583} 583}
584 584
585/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 585/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
586 * and return 0 on success. 586 * and return 0 on success.
587 */ 587 */
588static int generate_cached_repolist(const char *path, const char *cached_rc) 588static int generate_cached_repolist(const char *path, const char *cached_rc)
589{ 589{
590 char *locked_rc; 590 char *locked_rc;
591 int idx; 591 int idx;
592 FILE *f; 592 FILE *f;
593 593
594 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 594 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
595 f = fopen(locked_rc, "wx"); 595 f = fopen(locked_rc, "wx");
596 if (!f) { 596 if (!f) {
597 /* Inform about the error unless the lockfile already existed, 597 /* Inform about the error unless the lockfile already existed,
598 * since that only means we've got concurrent requests. 598 * since that only means we've got concurrent requests.
599 */ 599 */
600 if (errno != EEXIST) 600 if (errno != EEXIST)
601 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 601 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
602 locked_rc, strerror(errno), errno); 602 locked_rc, strerror(errno), errno);
603 return errno; 603 return errno;
604 } 604 }
605 idx = cgit_repolist.count; 605 idx = cgit_repolist.count;
606 if (ctx.cfg.project_list) 606 if (ctx.cfg.project_list)
607 scan_projects(path, ctx.cfg.project_list, repo_config); 607 scan_projects(path, ctx.cfg.project_list, repo_config);
608 else 608 else
609 scan_tree(path, repo_config); 609 scan_tree(path, repo_config);
610 print_repolist(f, &cgit_repolist, idx); 610 print_repolist(f, &cgit_repolist, idx);
611 if (rename(locked_rc, cached_rc)) 611 if (rename(locked_rc, cached_rc))
612 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 612 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
613 locked_rc, cached_rc, strerror(errno), errno); 613 locked_rc, cached_rc, strerror(errno), errno);
614 fclose(f); 614 fclose(f);
615 return 0; 615 return 0;
616} 616}
617 617
618static void process_cached_repolist(const char *path) 618static void process_cached_repolist(const char *path)
619{ 619{
620 struct stat st; 620 struct stat st;
621 char *cached_rc; 621 char *cached_rc;
622 time_t age; 622 time_t age;
623 unsigned long hash; 623 unsigned long hash;
624 624
625 hash = hash_str(path); 625 hash = hash_str(path);
626 if (ctx.cfg.project_list) 626 if (ctx.cfg.project_list)
627 hash += hash_str(ctx.cfg.project_list); 627 hash += hash_str(ctx.cfg.project_list);
628 cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); 628 cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash));
629 629
630 if (stat(cached_rc, &st)) { 630 if (stat(cached_rc, &st)) {
631 /* Nothing is cached, we need to scan without forking. And 631 /* Nothing is cached, we need to scan without forking. And
632 * if we fail to generate a cached repolist, we need to 632 * if we fail to generate a cached repolist, we need to
633 * invoke scan_tree manually. 633 * invoke scan_tree manually.
634 */ 634 */
635 if (generate_cached_repolist(path, cached_rc)) { 635 if (generate_cached_repolist(path, cached_rc)) {
636 if (ctx.cfg.project_list) 636 if (ctx.cfg.project_list)
637 scan_projects(path, ctx.cfg.project_list, 637 scan_projects(path, ctx.cfg.project_list,
638 repo_config); 638 repo_config);
639 else 639 else
640 scan_tree(path, repo_config); 640 scan_tree(path, repo_config);
641 } 641 }
642 return; 642 return;
643 } 643 }
644 644
645 parse_configfile(cached_rc, config_cb); 645 parse_configfile(cached_rc, config_cb);
646 646
647 /* If the cached configfile hasn't expired, lets exit now */ 647 /* If the cached configfile hasn't expired, lets exit now */
648 age = time(NULL) - st.st_mtime; 648 age = time(NULL) - st.st_mtime;
649 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 649 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
650 return; 650 return;
651 651
652 /* The cached repolist has been parsed, but it was old. So lets 652 /* The cached repolist has been parsed, but it was old. So lets
653 * rescan the specified path and generate a new cached repolist 653 * rescan the specified path and generate a new cached repolist
654 * in a child-process to avoid latency for the current request. 654 * in a child-process to avoid latency for the current request.
655 */ 655 */
656 if (fork()) 656 if (fork())
657 return; 657 return;
658 658
659 exit(generate_cached_repolist(path, cached_rc)); 659 exit(generate_cached_repolist(path, cached_rc));
660} 660}
661 661
662static void cgit_parse_args(int argc, const char **argv) 662static void cgit_parse_args(int argc, const char **argv)
663{ 663{
664 int i; 664 int i;
665 int scan = 0; 665 int scan = 0;
666 666
667 for (i = 1; i < argc; i++) { 667 for (i = 1; i < argc; i++) {
668 if (!strncmp(argv[i], "--cache=", 8)) { 668 if (!strncmp(argv[i], "--cache=", 8)) {
669 ctx.cfg.cache_root = xstrdup(argv[i]+8); 669 ctx.cfg.cache_root = xstrdup(argv[i]+8);
670 } 670 }
671 if (!strcmp(argv[i], "--nocache")) { 671 if (!strcmp(argv[i], "--nocache")) {
672 ctx.cfg.nocache = 1; 672 ctx.cfg.nocache = 1;
673 } 673 }
674 if (!strcmp(argv[i], "--nohttp")) { 674 if (!strcmp(argv[i], "--nohttp")) {
675 ctx.env.no_http = "1"; 675 ctx.env.no_http = "1";
676 } 676 }
677 if (!strncmp(argv[i], "--query=", 8)) { 677 if (!strncmp(argv[i], "--query=", 8)) {
678 ctx.qry.raw = xstrdup(argv[i]+8); 678 ctx.qry.raw = xstrdup(argv[i]+8);
679 } 679 }
680 if (!strncmp(argv[i], "--repo=", 7)) { 680 if (!strncmp(argv[i], "--repo=", 7)) {
681 ctx.qry.repo = xstrdup(argv[i]+7); 681 ctx.qry.repo = xstrdup(argv[i]+7);
682 } 682 }
683 if (!strncmp(argv[i], "--page=", 7)) { 683 if (!strncmp(argv[i], "--page=", 7)) {
684 ctx.qry.page = xstrdup(argv[i]+7); 684 ctx.qry.page = xstrdup(argv[i]+7);
685 } 685 }
686 if (!strncmp(argv[i], "--head=", 7)) { 686 if (!strncmp(argv[i], "--head=", 7)) {
687 ctx.qry.head = xstrdup(argv[i]+7); 687 ctx.qry.head = xstrdup(argv[i]+7);
688 ctx.qry.has_symref = 1; 688 ctx.qry.has_symref = 1;
689 } 689 }
690 if (!strncmp(argv[i], "--sha1=", 7)) { 690 if (!strncmp(argv[i], "--sha1=", 7)) {
691 ctx.qry.sha1 = xstrdup(argv[i]+7); 691 ctx.qry.sha1 = xstrdup(argv[i]+7);
692 ctx.qry.has_sha1 = 1; 692 ctx.qry.has_sha1 = 1;
693 } 693 }
694 if (!strncmp(argv[i], "--ofs=", 6)) { 694 if (!strncmp(argv[i], "--ofs=", 6)) {
695 ctx.qry.ofs = atoi(argv[i]+6); 695 ctx.qry.ofs = atoi(argv[i]+6);
696 } 696 }
697 if (!strncmp(argv[i], "--scan-tree=", 12) || 697 if (!strncmp(argv[i], "--scan-tree=", 12) ||
698 !strncmp(argv[i], "--scan-path=", 12)) { 698 !strncmp(argv[i], "--scan-path=", 12)) {
699 /* HACK: the global snapshot bitmask defines the 699 /* HACK: the global snapshot bitmask defines the
700 * set of allowed snapshot formats, but the config 700 * set of allowed snapshot formats, but the config
701 * file hasn't been parsed yet so the mask is 701 * file hasn't been parsed yet so the mask is
702 * currently 0. By setting all bits high before 702 * currently 0. By setting all bits high before
703 * scanning we make sure that any in-repo cgitrc 703 * scanning we make sure that any in-repo cgitrc
704 * snapshot setting is respected by scan_tree(). 704 * snapshot setting is respected by scan_tree().
705 * BTW: we assume that there'll never be more than 705 * BTW: we assume that there'll never be more than
706 * 255 different snapshot formats supported by cgit... 706 * 255 different snapshot formats supported by cgit...
707 */ 707 */
708 ctx.cfg.snapshots = 0xFF; 708 ctx.cfg.snapshots = 0xFF;
709 scan++; 709 scan++;
710 scan_tree(argv[i] + 12, repo_config); 710 scan_tree(argv[i] + 12, repo_config);
711 } 711 }
712 } 712 }
713 if (scan) { 713 if (scan) {
714 qsort(cgit_repolist.repos, cgit_repolist.count, 714 qsort(cgit_repolist.repos, cgit_repolist.count,
715 sizeof(struct cgit_repo), cmp_repos); 715 sizeof(struct cgit_repo), cmp_repos);
716 print_repolist(stdout, &cgit_repolist, 0); 716 print_repolist(stdout, &cgit_repolist, 0);
717 exit(0); 717 exit(0);
718 } 718 }
719} 719}
720 720
721static int calc_ttl() 721static int calc_ttl()
722{ 722{
723 if (!ctx.repo) 723 if (!ctx.repo)
724 return ctx.cfg.cache_root_ttl; 724 return ctx.cfg.cache_root_ttl;
725 725
726 if (!ctx.qry.page) 726 if (!ctx.qry.page)
727 return ctx.cfg.cache_repo_ttl; 727 return ctx.cfg.cache_repo_ttl;
728 728
729 if (ctx.qry.has_symref) 729 if (ctx.qry.has_symref)
730 return ctx.cfg.cache_dynamic_ttl; 730 return ctx.cfg.cache_dynamic_ttl;
731 731
732 if (ctx.qry.has_sha1) 732 if (ctx.qry.has_sha1)
733 return ctx.cfg.cache_static_ttl; 733 return ctx.cfg.cache_static_ttl;
734 734
735 return ctx.cfg.cache_repo_ttl; 735 return ctx.cfg.cache_repo_ttl;
736} 736}
737 737
738int main(int argc, const char **argv) 738int main(int argc, const char **argv)
739{ 739{
740 const char *path; 740 const char *path;
741 char *qry; 741 char *qry;
742 int err, ttl; 742 int err, ttl;
743 743
744 prepare_context(&ctx); 744 prepare_context(&ctx);
745 cgit_repolist.length = 0; 745 cgit_repolist.length = 0;
746 cgit_repolist.count = 0; 746 cgit_repolist.count = 0;
747 cgit_repolist.repos = NULL; 747 cgit_repolist.repos = NULL;
748 748
749 cgit_parse_args(argc, argv); 749 cgit_parse_args(argc, argv);
750 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); 750 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb);
751 ctx.repo = NULL; 751 ctx.repo = NULL;
752 http_parse_querystring(ctx.qry.raw, querystring_cb); 752 http_parse_querystring(ctx.qry.raw, querystring_cb);
753 753
754 /* If virtual-root isn't specified in cgitrc, lets pretend 754 /* If virtual-root isn't specified in cgitrc, lets pretend
755 * that virtual-root equals SCRIPT_NAME. 755 * that virtual-root equals SCRIPT_NAME, minus any possibly
756 * trailing slashes.
756 */ 757 */
757 if (!ctx.cfg.virtual_root) 758 if (!ctx.cfg.virtual_root)
758 ctx.cfg.virtual_root = ctx.cfg.script_name; 759 ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/');
759 760
760 /* If no url parameter is specified on the querystring, lets 761 /* If no url parameter is specified on the querystring, lets
761 * use PATH_INFO as url. This allows cgit to work with virtual 762 * use PATH_INFO as url. This allows cgit to work with virtual
762 * urls without the need for rewriterules in the webserver (as 763 * urls without the need for rewriterules in the webserver (as
763 * long as PATH_INFO is included in the cache lookup key). 764 * long as PATH_INFO is included in the cache lookup key).
764 */ 765 */
765 path = ctx.env.path_info; 766 path = ctx.env.path_info;
766 if (!ctx.qry.url && path) { 767 if (!ctx.qry.url && path) {
767 if (path[0] == '/') 768 if (path[0] == '/')
768 path++; 769 path++;
769 ctx.qry.url = xstrdup(path); 770 ctx.qry.url = xstrdup(path);
770 if (ctx.qry.raw) { 771 if (ctx.qry.raw) {
771 qry = ctx.qry.raw; 772 qry = ctx.qry.raw;
772 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 773 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
773 free(qry); 774 free(qry);
774 } else 775 } else
775 ctx.qry.raw = xstrdup(ctx.qry.url); 776 ctx.qry.raw = xstrdup(ctx.qry.url);
776 cgit_parse_url(ctx.qry.url); 777 cgit_parse_url(ctx.qry.url);
777 } 778 }
778 779
779 ttl = calc_ttl(); 780 ttl = calc_ttl();
780 ctx.page.expires += ttl*60; 781 ctx.page.expires += ttl*60;
781 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 782 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
782 ctx.cfg.nocache = 1; 783 ctx.cfg.nocache = 1;
783 if (ctx.cfg.nocache) 784 if (ctx.cfg.nocache)
784 ctx.cfg.cache_size = 0; 785 ctx.cfg.cache_size = 0;
785 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 786 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
786 ctx.qry.raw, ttl, process_request, &ctx); 787 ctx.qry.raw, ttl, process_request, &ctx);
787 if (err) 788 if (err)
788 cgit_print_error(fmt("Error processing page: %s (%d)", 789 cgit_print_error(fmt("Error processing page: %s (%d)",
789 strerror(err), err)); 790 strerror(err), err));
790 return err; 791 return err;
791} 792}
diff --git a/html.c b/html.c
index a1fe87d..a60bc13 100644
--- a/html.c
+++ b/html.c
@@ -88,233 +88,233 @@ void html_status(int code, const char *msg, int more_headers)
88 if (!more_headers) 88 if (!more_headers)
89 html("\n"); 89 html("\n");
90} 90}
91 91
92void html_txt(const char *txt) 92void html_txt(const char *txt)
93{ 93{
94 const char *t = txt; 94 const char *t = txt;
95 while(t && *t){ 95 while(t && *t){
96 int c = *t; 96 int c = *t;
97 if (c=='<' || c=='>' || c=='&') { 97 if (c=='<' || c=='>' || c=='&') {
98 html_raw(txt, t - txt); 98 html_raw(txt, t - txt);
99 if (c=='>') 99 if (c=='>')
100 html("&gt;"); 100 html("&gt;");
101 else if (c=='<') 101 else if (c=='<')
102 html("&lt;"); 102 html("&lt;");
103 else if (c=='&') 103 else if (c=='&')
104 html("&amp;"); 104 html("&amp;");
105 txt = t+1; 105 txt = t+1;
106 } 106 }
107 t++; 107 t++;
108 } 108 }
109 if (t!=txt) 109 if (t!=txt)
110 html(txt); 110 html(txt);
111} 111}
112 112
113void html_ntxt(int len, const char *txt) 113void html_ntxt(int len, const char *txt)
114{ 114{
115 const char *t = txt; 115 const char *t = txt;
116 while(t && *t && len--){ 116 while(t && *t && len--){
117 int c = *t; 117 int c = *t;
118 if (c=='<' || c=='>' || c=='&') { 118 if (c=='<' || c=='>' || c=='&') {
119 html_raw(txt, t - txt); 119 html_raw(txt, t - txt);
120 if (c=='>') 120 if (c=='>')
121 html("&gt;"); 121 html("&gt;");
122 else if (c=='<') 122 else if (c=='<')
123 html("&lt;"); 123 html("&lt;");
124 else if (c=='&') 124 else if (c=='&')
125 html("&amp;"); 125 html("&amp;");
126 txt = t+1; 126 txt = t+1;
127 } 127 }
128 t++; 128 t++;
129 } 129 }
130 if (t!=txt) 130 if (t!=txt)
131 html_raw(txt, t - txt); 131 html_raw(txt, t - txt);
132 if (len<0) 132 if (len<0)
133 html("..."); 133 html("...");
134} 134}
135 135
136void html_attr(const char *txt) 136void html_attr(const char *txt)
137{ 137{
138 const char *t = txt; 138 const char *t = txt;
139 while(t && *t){ 139 while(t && *t){
140 int c = *t; 140 int c = *t;
141 if (c=='<' || c=='>' || c=='\'' || c=='\"') { 141 if (c=='<' || c=='>' || c=='\'' || c=='\"') {
142 html_raw(txt, t - txt); 142 html_raw(txt, t - txt);
143 if (c=='>') 143 if (c=='>')
144 html("&gt;"); 144 html("&gt;");
145 else if (c=='<') 145 else if (c=='<')
146 html("&lt;"); 146 html("&lt;");
147 else if (c=='\'') 147 else if (c=='\'')
148 html("&#x27;"); 148 html("&#x27;");
149 else if (c=='"') 149 else if (c=='"')
150 html("&quot;"); 150 html("&quot;");
151 txt = t+1; 151 txt = t+1;
152 } 152 }
153 t++; 153 t++;
154 } 154 }
155 if (t!=txt) 155 if (t!=txt)
156 html(txt); 156 html(txt);
157} 157}
158 158
159void html_url_path(const char *txt) 159void html_url_path(const char *txt)
160{ 160{
161 const char *t = txt; 161 const char *t = txt;
162 while(t && *t){ 162 while(t && *t){
163 int c = *t; 163 int c = *t;
164 const char *e = url_escape_table[c]; 164 const char *e = url_escape_table[c];
165 if (e && c!='+' && c!='&' && c!='+') { 165 if (e && c!='+' && c!='&' && c!='+') {
166 html_raw(txt, t - txt); 166 html_raw(txt, t - txt);
167 html_raw(e, 3); 167 html_raw(e, 3);
168 txt = t+1; 168 txt = t+1;
169 } 169 }
170 t++; 170 t++;
171 } 171 }
172 if (t!=txt) 172 if (t!=txt)
173 html(txt); 173 html(txt);
174} 174}
175 175
176void html_url_arg(const char *txt) 176void html_url_arg(const char *txt)
177{ 177{
178 const char *t = txt; 178 const char *t = txt;
179 while(t && *t){ 179 while(t && *t){
180 int c = *t; 180 int c = *t;
181 const char *e = url_escape_table[c]; 181 const char *e = url_escape_table[c];
182 if (e) { 182 if (e) {
183 html_raw(txt, t - txt); 183 html_raw(txt, t - txt);
184 html_raw(e, strlen(e)); 184 html_raw(e, strlen(e));
185 txt = t+1; 185 txt = t+1;
186 } 186 }
187 t++; 187 t++;
188 } 188 }
189 if (t!=txt) 189 if (t!=txt)
190 html(txt); 190 html(txt);
191} 191}
192 192
193void html_hidden(const char *name, const char *value) 193void html_hidden(const char *name, const char *value)
194{ 194{
195 html("<input type='hidden' name='"); 195 html("<input type='hidden' name='");
196 html_attr(name); 196 html_attr(name);
197 html("' value='"); 197 html("' value='");
198 html_attr(value); 198 html_attr(value);
199 html("'/>"); 199 html("'/>");
200} 200}
201 201
202void html_option(const char *value, const char *text, const char *selected_value) 202void html_option(const char *value, const char *text, const char *selected_value)
203{ 203{
204 html("<option value='"); 204 html("<option value='");
205 html_attr(value); 205 html_attr(value);
206 html("'"); 206 html("'");
207 if (selected_value && !strcmp(selected_value, value)) 207 if (selected_value && !strcmp(selected_value, value))
208 html(" selected='selected'"); 208 html(" selected='selected'");
209 html(">"); 209 html(">");
210 html_txt(text); 210 html_txt(text);
211 html("</option>\n"); 211 html("</option>\n");
212} 212}
213 213
214void html_link_open(const char *url, const char *title, const char *class) 214void html_link_open(const char *url, const char *title, const char *class)
215{ 215{
216 html("<a href='"); 216 html("<a href='");
217 html_attr(url); 217 html_attr(url);
218 if (title) { 218 if (title) {
219 html("' title='"); 219 html("' title='");
220 html_attr(title); 220 html_attr(title);
221 } 221 }
222 if (class) { 222 if (class) {
223 html("' class='"); 223 html("' class='");
224 html_attr(class); 224 html_attr(class);
225 } 225 }
226 html("'>"); 226 html("'>");
227} 227}
228 228
229void html_link_close(void) 229void html_link_close(void)
230{ 230{
231 html("</a>"); 231 html("</a>");
232} 232}
233 233
234void html_fileperm(unsigned short mode) 234void html_fileperm(unsigned short mode)
235{ 235{
236 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'), 236 htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),
237 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-')); 237 (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));
238} 238}
239 239
240int html_include(const char *filename) 240int html_include(const char *filename)
241{ 241{
242 FILE *f; 242 FILE *f;
243 char buf[4096]; 243 char buf[4096];
244 size_t len; 244 size_t len;
245 245
246 if (!(f = fopen(filename, "r"))) { 246 if (!(f = fopen(filename, "r"))) {
247 fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n", 247 fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n",
248 filename, strerror(errno), errno); 248 filename, strerror(errno), errno);
249 return -1; 249 return -1;
250 } 250 }
251 while((len = fread(buf, 1, 4096, f)) > 0) 251 while((len = fread(buf, 1, 4096, f)) > 0)
252 html_raw(buf, len); 252 html_raw(buf, len);
253 fclose(f); 253 fclose(f);
254 return 0; 254 return 0;
255} 255}
256 256
257int hextoint(char c) 257int hextoint(char c)
258{ 258{
259 if (c >= 'a' && c <= 'f') 259 if (c >= 'a' && c <= 'f')
260 return 10 + c - 'a'; 260 return 10 + c - 'a';
261 else if (c >= 'A' && c <= 'F') 261 else if (c >= 'A' && c <= 'F')
262 return 10 + c - 'A'; 262 return 10 + c - 'A';
263 else if (c >= '0' && c <= '9') 263 else if (c >= '0' && c <= '9')
264 return c - '0'; 264 return c - '0';
265 else 265 else
266 return -1; 266 return -1;
267} 267}
268 268
269char *convert_query_hexchar(char *txt) 269char *convert_query_hexchar(char *txt)
270{ 270{
271 int d1, d2, n; 271 int d1, d2, n;
272 n = strlen(txt); 272 n = strlen(txt);
273 if (n < 3) { 273 if (n < 3) {
274 *txt = '\0'; 274 *txt = '\0';
275 return txt-1; 275 return txt-1;
276 } 276 }
277 d1 = hextoint(*(txt+1)); 277 d1 = hextoint(*(txt+1));
278 d2 = hextoint(*(txt+2)); 278 d2 = hextoint(*(txt+2));
279 if (d1<0 || d2<0) { 279 if (d1<0 || d2<0) {
280 memmove(txt, txt+3, n-3); 280 memmove(txt, txt+3, n-2);
281 return txt-1; 281 return txt-1;
282 } else { 282 } else {
283 *txt = d1 * 16 + d2; 283 *txt = d1 * 16 + d2;
284 memmove(txt+1, txt+3, n-2); 284 memmove(txt+1, txt+3, n-2);
285 return txt; 285 return txt;
286 } 286 }
287} 287}
288 288
289int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value)) 289int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value))
290{ 290{
291 char *t, *txt, *value = NULL, c; 291 char *t, *txt, *value = NULL, c;
292 292
293 if (!txt_) 293 if (!txt_)
294 return 0; 294 return 0;
295 295
296 t = txt = strdup(txt_); 296 t = txt = strdup(txt_);
297 if (t == NULL) { 297 if (t == NULL) {
298 printf("Out of memory\n"); 298 printf("Out of memory\n");
299 exit(1); 299 exit(1);
300 } 300 }
301 while((c=*t) != '\0') { 301 while((c=*t) != '\0') {
302 if (c=='=') { 302 if (c=='=') {
303 *t = '\0'; 303 *t = '\0';
304 value = t+1; 304 value = t+1;
305 } else if (c=='+') { 305 } else if (c=='+') {
306 *t = ' '; 306 *t = ' ';
307 } else if (c=='%') { 307 } else if (c=='%') {
308 t = convert_query_hexchar(t); 308 t = convert_query_hexchar(t);
309 } else if (c=='&') { 309 } else if (c=='&') {
310 *t = '\0'; 310 *t = '\0';
311 (*fn)(txt, value); 311 (*fn)(txt, value);
312 txt = t+1; 312 txt = t+1;
313 value = NULL; 313 value = NULL;
314 } 314 }
315 t++; 315 t++;
316 } 316 }
317 if (t!=txt) 317 if (t!=txt)
318 (*fn)(txt, value); 318 (*fn)(txt, value);
319 return 0; 319 return 0;
320} 320}
diff --git a/ui-shared.c b/ui-shared.c
index 7efae7a..5aa9119 100644
--- a/ui-shared.c
+++ b/ui-shared.c
@@ -385,385 +385,385 @@ void cgit_diff_link(const char *name, const char *title, const char *class,
385 html_url_arg(new_rev); 385 html_url_arg(new_rev);
386 delim = "&amp;"; 386 delim = "&amp;";
387 } 387 }
388 if (old_rev) { 388 if (old_rev) {
389 html(delim); 389 html(delim);
390 html("id2="); 390 html("id2=");
391 html_url_arg(old_rev); 391 html_url_arg(old_rev);
392 delim = "&amp;"; 392 delim = "&amp;";
393 } 393 }
394 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) { 394 if ((ctx.qry.ssdiff && !toggle_ssdiff) || (!ctx.qry.ssdiff && toggle_ssdiff)) {
395 html(delim); 395 html(delim);
396 html("ss=1"); 396 html("ss=1");
397 delim = "&amp;"; 397 delim = "&amp;";
398 } 398 }
399 if (ctx.qry.context > 0 && ctx.qry.context != 3) { 399 if (ctx.qry.context > 0 && ctx.qry.context != 3) {
400 html(delim); 400 html(delim);
401 html("context="); 401 html("context=");
402 htmlf("%d", ctx.qry.context); 402 htmlf("%d", ctx.qry.context);
403 delim = "&amp;"; 403 delim = "&amp;";
404 } 404 }
405 if (ctx.qry.ignorews) { 405 if (ctx.qry.ignorews) {
406 html(delim); 406 html(delim);
407 html("ignorews=1"); 407 html("ignorews=1");
408 delim = "&amp;"; 408 delim = "&amp;";
409 } 409 }
410 html("'>"); 410 html("'>");
411 html_txt(name); 411 html_txt(name);
412 html("</a>"); 412 html("</a>");
413} 413}
414 414
415void cgit_patch_link(const char *name, const char *title, const char *class, 415void cgit_patch_link(const char *name, const char *title, const char *class,
416 const char *head, const char *rev, const char *path) 416 const char *head, const char *rev, const char *path)
417{ 417{
418 reporevlink("patch", name, title, class, head, rev, path); 418 reporevlink("patch", name, title, class, head, rev, path);
419} 419}
420 420
421void cgit_stats_link(const char *name, const char *title, const char *class, 421void cgit_stats_link(const char *name, const char *title, const char *class,
422 const char *head, const char *path) 422 const char *head, const char *path)
423{ 423{
424 reporevlink("stats", name, title, class, head, NULL, path); 424 reporevlink("stats", name, title, class, head, NULL, path);
425} 425}
426 426
427void cgit_self_link(char *name, const char *title, const char *class, 427void cgit_self_link(char *name, const char *title, const char *class,
428 struct cgit_context *ctx) 428 struct cgit_context *ctx)
429{ 429{
430 if (!strcmp(ctx->qry.page, "repolist")) 430 if (!strcmp(ctx->qry.page, "repolist"))
431 return cgit_index_link(name, title, class, ctx->qry.search, 431 return cgit_index_link(name, title, class, ctx->qry.search,
432 ctx->qry.ofs); 432 ctx->qry.ofs);
433 else if (!strcmp(ctx->qry.page, "summary")) 433 else if (!strcmp(ctx->qry.page, "summary"))
434 return cgit_summary_link(name, title, class, ctx->qry.head); 434 return cgit_summary_link(name, title, class, ctx->qry.head);
435 else if (!strcmp(ctx->qry.page, "tag")) 435 else if (!strcmp(ctx->qry.page, "tag"))
436 return cgit_tag_link(name, title, class, ctx->qry.head, 436 return cgit_tag_link(name, title, class, ctx->qry.head,
437 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL); 437 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL);
438 else if (!strcmp(ctx->qry.page, "tree")) 438 else if (!strcmp(ctx->qry.page, "tree"))
439 return cgit_tree_link(name, title, class, ctx->qry.head, 439 return cgit_tree_link(name, title, class, ctx->qry.head,
440 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 440 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
441 ctx->qry.path); 441 ctx->qry.path);
442 else if (!strcmp(ctx->qry.page, "plain")) 442 else if (!strcmp(ctx->qry.page, "plain"))
443 return cgit_plain_link(name, title, class, ctx->qry.head, 443 return cgit_plain_link(name, title, class, ctx->qry.head,
444 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 444 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
445 ctx->qry.path); 445 ctx->qry.path);
446 else if (!strcmp(ctx->qry.page, "log")) 446 else if (!strcmp(ctx->qry.page, "log"))
447 return cgit_log_link(name, title, class, ctx->qry.head, 447 return cgit_log_link(name, title, class, ctx->qry.head,
448 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 448 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
449 ctx->qry.path, ctx->qry.ofs, 449 ctx->qry.path, ctx->qry.ofs,
450 ctx->qry.grep, ctx->qry.search, 450 ctx->qry.grep, ctx->qry.search,
451 ctx->qry.showmsg); 451 ctx->qry.showmsg);
452 else if (!strcmp(ctx->qry.page, "commit")) 452 else if (!strcmp(ctx->qry.page, "commit"))
453 return cgit_commit_link(name, title, class, ctx->qry.head, 453 return cgit_commit_link(name, title, class, ctx->qry.head,
454 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 454 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
455 ctx->qry.path, 0); 455 ctx->qry.path, 0);
456 else if (!strcmp(ctx->qry.page, "patch")) 456 else if (!strcmp(ctx->qry.page, "patch"))
457 return cgit_patch_link(name, title, class, ctx->qry.head, 457 return cgit_patch_link(name, title, class, ctx->qry.head,
458 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 458 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
459 ctx->qry.path); 459 ctx->qry.path);
460 else if (!strcmp(ctx->qry.page, "refs")) 460 else if (!strcmp(ctx->qry.page, "refs"))
461 return cgit_refs_link(name, title, class, ctx->qry.head, 461 return cgit_refs_link(name, title, class, ctx->qry.head,
462 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 462 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
463 ctx->qry.path); 463 ctx->qry.path);
464 else if (!strcmp(ctx->qry.page, "snapshot")) 464 else if (!strcmp(ctx->qry.page, "snapshot"))
465 return cgit_snapshot_link(name, title, class, ctx->qry.head, 465 return cgit_snapshot_link(name, title, class, ctx->qry.head,
466 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL, 466 ctx->qry.has_sha1 ? ctx->qry.sha1 : NULL,
467 ctx->qry.path); 467 ctx->qry.path);
468 else if (!strcmp(ctx->qry.page, "diff")) 468 else if (!strcmp(ctx->qry.page, "diff"))
469 return cgit_diff_link(name, title, class, ctx->qry.head, 469 return cgit_diff_link(name, title, class, ctx->qry.head,
470 ctx->qry.sha1, ctx->qry.sha2, 470 ctx->qry.sha1, ctx->qry.sha2,
471 ctx->qry.path, 0); 471 ctx->qry.path, 0);
472 else if (!strcmp(ctx->qry.page, "stats")) 472 else if (!strcmp(ctx->qry.page, "stats"))
473 return cgit_stats_link(name, title, class, ctx->qry.head, 473 return cgit_stats_link(name, title, class, ctx->qry.head,
474 ctx->qry.path); 474 ctx->qry.path);
475 475
476 /* Don't known how to make link for this page */ 476 /* Don't known how to make link for this page */
477 repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path); 477 repolink(title, class, ctx->qry.page, ctx->qry.head, ctx->qry.path);
478 html("><!-- cgit_self_link() doesn't know how to make link for page '"); 478 html("><!-- cgit_self_link() doesn't know how to make link for page '");
479 html_txt(ctx->qry.page); 479 html_txt(ctx->qry.page);
480 html("' -->"); 480 html("' -->");
481 html_txt(name); 481 html_txt(name);
482 html("</a>"); 482 html("</a>");
483} 483}
484 484
485void cgit_object_link(struct object *obj) 485void cgit_object_link(struct object *obj)
486{ 486{
487 char *page, *shortrev, *fullrev, *name; 487 char *page, *shortrev, *fullrev, *name;
488 488
489 fullrev = sha1_to_hex(obj->sha1); 489 fullrev = sha1_to_hex(obj->sha1);
490 shortrev = xstrdup(fullrev); 490 shortrev = xstrdup(fullrev);
491 shortrev[10] = '\0'; 491 shortrev[10] = '\0';
492 if (obj->type == OBJ_COMMIT) { 492 if (obj->type == OBJ_COMMIT) {
493 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, 493 cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL,
494 ctx.qry.head, fullrev, NULL, 0); 494 ctx.qry.head, fullrev, NULL, 0);
495 return; 495 return;
496 } else if (obj->type == OBJ_TREE) 496 } else if (obj->type == OBJ_TREE)
497 page = "tree"; 497 page = "tree";
498 else if (obj->type == OBJ_TAG) 498 else if (obj->type == OBJ_TAG)
499 page = "tag"; 499 page = "tag";
500 else 500 else
501 page = "blob"; 501 page = "blob";
502 name = fmt("%s %s...", typename(obj->type), shortrev); 502 name = fmt("%s %s...", typename(obj->type), shortrev);
503 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); 503 reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL);
504} 504}
505 505
506void cgit_print_date(time_t secs, const char *format, int local_time) 506void cgit_print_date(time_t secs, const char *format, int local_time)
507{ 507{
508 char buf[64]; 508 char buf[64];
509 struct tm *time; 509 struct tm *time;
510 510
511 if (!secs) 511 if (!secs)
512 return; 512 return;
513 if(local_time) 513 if(local_time)
514 time = localtime(&secs); 514 time = localtime(&secs);
515 else 515 else
516 time = gmtime(&secs); 516 time = gmtime(&secs);
517 strftime(buf, sizeof(buf)-1, format, time); 517 strftime(buf, sizeof(buf)-1, format, time);
518 html_txt(buf); 518 html_txt(buf);
519} 519}
520 520
521void cgit_print_age(time_t t, time_t max_relative, const char *format) 521void cgit_print_age(time_t t, time_t max_relative, const char *format)
522{ 522{
523 time_t now, secs; 523 time_t now, secs;
524 524
525 if (!t) 525 if (!t)
526 return; 526 return;
527 time(&now); 527 time(&now);
528 secs = now - t; 528 secs = now - t;
529 529
530 if (secs > max_relative && max_relative >= 0) { 530 if (secs > max_relative && max_relative >= 0) {
531 cgit_print_date(t, format, ctx.cfg.local_time); 531 cgit_print_date(t, format, ctx.cfg.local_time);
532 return; 532 return;
533 } 533 }
534 534
535 if (secs < TM_HOUR * 2) { 535 if (secs < TM_HOUR * 2) {
536 htmlf("<span class='age-mins'>%.0f min.</span>", 536 htmlf("<span class='age-mins'>%.0f min.</span>",
537 secs * 1.0 / TM_MIN); 537 secs * 1.0 / TM_MIN);
538 return; 538 return;
539 } 539 }
540 if (secs < TM_DAY * 2) { 540 if (secs < TM_DAY * 2) {
541 htmlf("<span class='age-hours'>%.0f hours</span>", 541 htmlf("<span class='age-hours'>%.0f hours</span>",
542 secs * 1.0 / TM_HOUR); 542 secs * 1.0 / TM_HOUR);
543 return; 543 return;
544 } 544 }
545 if (secs < TM_WEEK * 2) { 545 if (secs < TM_WEEK * 2) {
546 htmlf("<span class='age-days'>%.0f days</span>", 546 htmlf("<span class='age-days'>%.0f days</span>",
547 secs * 1.0 / TM_DAY); 547 secs * 1.0 / TM_DAY);
548 return; 548 return;
549 } 549 }
550 if (secs < TM_MONTH * 2) { 550 if (secs < TM_MONTH * 2) {
551 htmlf("<span class='age-weeks'>%.0f weeks</span>", 551 htmlf("<span class='age-weeks'>%.0f weeks</span>",
552 secs * 1.0 / TM_WEEK); 552 secs * 1.0 / TM_WEEK);
553 return; 553 return;
554 } 554 }
555 if (secs < TM_YEAR * 2) { 555 if (secs < TM_YEAR * 2) {
556 htmlf("<span class='age-months'>%.0f months</span>", 556 htmlf("<span class='age-months'>%.0f months</span>",
557 secs * 1.0 / TM_MONTH); 557 secs * 1.0 / TM_MONTH);
558 return; 558 return;
559 } 559 }
560 htmlf("<span class='age-years'>%.0f years</span>", 560 htmlf("<span class='age-years'>%.0f years</span>",
561 secs * 1.0 / TM_YEAR); 561 secs * 1.0 / TM_YEAR);
562} 562}
563 563
564void cgit_print_http_headers(struct cgit_context *ctx) 564void cgit_print_http_headers(struct cgit_context *ctx)
565{ 565{
566 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1")) 566 if (ctx->env.no_http && !strcmp(ctx->env.no_http, "1"))
567 return; 567 return;
568 568
569 if (ctx->page.status) 569 if (ctx->page.status)
570 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg); 570 htmlf("Status: %d %s\n", ctx->page.status, ctx->page.statusmsg);
571 if (ctx->page.mimetype && ctx->page.charset) 571 if (ctx->page.mimetype && ctx->page.charset)
572 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, 572 htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype,
573 ctx->page.charset); 573 ctx->page.charset);
574 else if (ctx->page.mimetype) 574 else if (ctx->page.mimetype)
575 htmlf("Content-Type: %s\n", ctx->page.mimetype); 575 htmlf("Content-Type: %s\n", ctx->page.mimetype);
576 if (ctx->page.size) 576 if (ctx->page.size)
577 htmlf("Content-Length: %ld\n", ctx->page.size); 577 htmlf("Content-Length: %zd\n", ctx->page.size);
578 if (ctx->page.filename) 578 if (ctx->page.filename)
579 htmlf("Content-Disposition: inline; filename=\"%s\"\n", 579 htmlf("Content-Disposition: inline; filename=\"%s\"\n",
580 ctx->page.filename); 580 ctx->page.filename);
581 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); 581 htmlf("Last-Modified: %s\n", http_date(ctx->page.modified));
582 htmlf("Expires: %s\n", http_date(ctx->page.expires)); 582 htmlf("Expires: %s\n", http_date(ctx->page.expires));
583 if (ctx->page.etag) 583 if (ctx->page.etag)
584 htmlf("ETag: \"%s\"\n", ctx->page.etag); 584 htmlf("ETag: \"%s\"\n", ctx->page.etag);
585 html("\n"); 585 html("\n");
586 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD")) 586 if (ctx->env.request_method && !strcmp(ctx->env.request_method, "HEAD"))
587 exit(0); 587 exit(0);
588} 588}
589 589
590void cgit_print_docstart(struct cgit_context *ctx) 590void cgit_print_docstart(struct cgit_context *ctx)
591{ 591{
592 if (ctx->cfg.embedded) { 592 if (ctx->cfg.embedded) {
593 if (ctx->cfg.header) 593 if (ctx->cfg.header)
594 html_include(ctx->cfg.header); 594 html_include(ctx->cfg.header);
595 return; 595 return;
596 } 596 }
597 597
598 char *host = cgit_hosturl(); 598 char *host = cgit_hosturl();
599 html(cgit_doctype); 599 html(cgit_doctype);
600 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n"); 600 html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");
601 html("<head>\n"); 601 html("<head>\n");
602 html("<title>"); 602 html("<title>");
603 html_txt(ctx->page.title); 603 html_txt(ctx->page.title);
604 html("</title>\n"); 604 html("</title>\n");
605 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); 605 htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version);
606 if (ctx->cfg.robots && *ctx->cfg.robots) 606 if (ctx->cfg.robots && *ctx->cfg.robots)
607 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots); 607 htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);
608 html("<link rel='stylesheet' type='text/css' href='"); 608 html("<link rel='stylesheet' type='text/css' href='");
609 html_attr(ctx->cfg.css); 609 html_attr(ctx->cfg.css);
610 html("'/>\n"); 610 html("'/>\n");
611 if (ctx->cfg.favicon) { 611 if (ctx->cfg.favicon) {
612 html("<link rel='shortcut icon' href='"); 612 html("<link rel='shortcut icon' href='");
613 html_attr(ctx->cfg.favicon); 613 html_attr(ctx->cfg.favicon);
614 html("'/>\n"); 614 html("'/>\n");
615 } 615 }
616 if (host && ctx->repo) { 616 if (host && ctx->repo) {
617 html("<link rel='alternate' title='Atom feed' href='"); 617 html("<link rel='alternate' title='Atom feed' href='");
618 html(cgit_httpscheme()); 618 html(cgit_httpscheme());
619 html_attr(cgit_hosturl()); 619 html_attr(cgit_hosturl());
620 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, 620 html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath,
621 fmt("h=%s", ctx->qry.head))); 621 fmt("h=%s", ctx->qry.head)));
622 html("' type='application/atom+xml'/>\n"); 622 html("' type='application/atom+xml'/>\n");
623 } 623 }
624 if (ctx->cfg.head_include) 624 if (ctx->cfg.head_include)
625 html_include(ctx->cfg.head_include); 625 html_include(ctx->cfg.head_include);
626 html("</head>\n"); 626 html("</head>\n");
627 html("<body>\n"); 627 html("<body>\n");
628 if (ctx->cfg.header) 628 if (ctx->cfg.header)
629 html_include(ctx->cfg.header); 629 html_include(ctx->cfg.header);
630} 630}
631 631
632void cgit_print_docend() 632void cgit_print_docend()
633{ 633{
634 html("</div> <!-- class=content -->\n"); 634 html("</div> <!-- class=content -->\n");
635 if (ctx.cfg.embedded) { 635 if (ctx.cfg.embedded) {
636 html("</div> <!-- id=cgit -->\n"); 636 html("</div> <!-- id=cgit -->\n");
637 if (ctx.cfg.footer) 637 if (ctx.cfg.footer)
638 html_include(ctx.cfg.footer); 638 html_include(ctx.cfg.footer);
639 return; 639 return;
640 } 640 }
641 if (ctx.cfg.footer) 641 if (ctx.cfg.footer)
642 html_include(ctx.cfg.footer); 642 html_include(ctx.cfg.footer);
643 else { 643 else {
644 htmlf("<div class='footer'>generated by cgit %s at ", 644 htmlf("<div class='footer'>generated by cgit %s at ",
645 cgit_version); 645 cgit_version);
646 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time); 646 cgit_print_date(time(NULL), FMT_LONGDATE, ctx.cfg.local_time);
647 html("</div>\n"); 647 html("</div>\n");
648 } 648 }
649 html("</div> <!-- id=cgit -->\n"); 649 html("</div> <!-- id=cgit -->\n");
650 html("</body>\n</html>\n"); 650 html("</body>\n</html>\n");
651} 651}
652 652
653int print_branch_option(const char *refname, const unsigned char *sha1, 653int print_branch_option(const char *refname, const unsigned char *sha1,
654 int flags, void *cb_data) 654 int flags, void *cb_data)
655{ 655{
656 char *name = (char *)refname; 656 char *name = (char *)refname;
657 html_option(name, name, ctx.qry.head); 657 html_option(name, name, ctx.qry.head);
658 return 0; 658 return 0;
659} 659}
660 660
661int print_archive_ref(const char *refname, const unsigned char *sha1, 661int print_archive_ref(const char *refname, const unsigned char *sha1,
662 int flags, void *cb_data) 662 int flags, void *cb_data)
663{ 663{
664 struct tag *tag; 664 struct tag *tag;
665 struct taginfo *info; 665 struct taginfo *info;
666 struct object *obj; 666 struct object *obj;
667 char buf[256], *url; 667 char buf[256], *url;
668 unsigned char fileid[20]; 668 unsigned char fileid[20];
669 int *header = (int *)cb_data; 669 int *header = (int *)cb_data;
670 670
671 if (prefixcmp(refname, "refs/archives")) 671 if (prefixcmp(refname, "refs/archives"))
672 return 0; 672 return 0;
673 strncpy(buf, refname+14, sizeof(buf)); 673 strncpy(buf, refname+14, sizeof(buf));
674 obj = parse_object(sha1); 674 obj = parse_object(sha1);
675 if (!obj) 675 if (!obj)
676 return 1; 676 return 1;
677 if (obj->type == OBJ_TAG) { 677 if (obj->type == OBJ_TAG) {
678 tag = lookup_tag(sha1); 678 tag = lookup_tag(sha1);
679 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) 679 if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag)))
680 return 0; 680 return 0;
681 hashcpy(fileid, tag->tagged->sha1); 681 hashcpy(fileid, tag->tagged->sha1);
682 } else if (obj->type != OBJ_BLOB) { 682 } else if (obj->type != OBJ_BLOB) {
683 return 0; 683 return 0;
684 } else { 684 } else {
685 hashcpy(fileid, sha1); 685 hashcpy(fileid, sha1);
686 } 686 }
687 if (!*header) { 687 if (!*header) {
688 html("<h1>download</h1>\n"); 688 html("<h1>download</h1>\n");
689 *header = 1; 689 *header = 1;
690 } 690 }
691 url = cgit_pageurl(ctx.qry.repo, "blob", 691 url = cgit_pageurl(ctx.qry.repo, "blob",
692 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid), 692 fmt("id=%s&amp;path=%s", sha1_to_hex(fileid),
693 buf)); 693 buf));
694 html_link_open(url, NULL, "menu"); 694 html_link_open(url, NULL, "menu");
695 html_txt(strlpart(buf, 20)); 695 html_txt(strlpart(buf, 20));
696 html_link_close(); 696 html_link_close();
697 return 0; 697 return 0;
698} 698}
699 699
700void cgit_add_hidden_formfields(int incl_head, int incl_search, 700void cgit_add_hidden_formfields(int incl_head, int incl_search,
701 const char *page) 701 const char *page)
702{ 702{
703 char *url; 703 char *url;
704 704
705 if (!ctx.cfg.virtual_root) { 705 if (!ctx.cfg.virtual_root) {
706 url = fmt("%s/%s", ctx.qry.repo, page); 706 url = fmt("%s/%s", ctx.qry.repo, page);
707 if (ctx.qry.vpath) 707 if (ctx.qry.vpath)
708 url = fmt("%s/%s", url, ctx.qry.vpath); 708 url = fmt("%s/%s", url, ctx.qry.vpath);
709 html_hidden("url", url); 709 html_hidden("url", url);
710 } 710 }
711 711
712 if (incl_head && ctx.qry.head && ctx.repo->defbranch && 712 if (incl_head && ctx.qry.head && ctx.repo->defbranch &&
713 strcmp(ctx.qry.head, ctx.repo->defbranch)) 713 strcmp(ctx.qry.head, ctx.repo->defbranch))
714 html_hidden("h", ctx.qry.head); 714 html_hidden("h", ctx.qry.head);
715 715
716 if (ctx.qry.sha1) 716 if (ctx.qry.sha1)
717 html_hidden("id", ctx.qry.sha1); 717 html_hidden("id", ctx.qry.sha1);
718 if (ctx.qry.sha2) 718 if (ctx.qry.sha2)
719 html_hidden("id2", ctx.qry.sha2); 719 html_hidden("id2", ctx.qry.sha2);
720 if (ctx.qry.showmsg) 720 if (ctx.qry.showmsg)
721 html_hidden("showmsg", "1"); 721 html_hidden("showmsg", "1");
722 722
723 if (incl_search) { 723 if (incl_search) {
724 if (ctx.qry.grep) 724 if (ctx.qry.grep)
725 html_hidden("qt", ctx.qry.grep); 725 html_hidden("qt", ctx.qry.grep);
726 if (ctx.qry.search) 726 if (ctx.qry.search)
727 html_hidden("q", ctx.qry.search); 727 html_hidden("q", ctx.qry.search);
728 } 728 }
729} 729}
730 730
731static const char *hc(struct cgit_context *ctx, const char *page) 731static const char *hc(struct cgit_context *ctx, const char *page)
732{ 732{
733 return strcmp(ctx->qry.page, page) ? NULL : "active"; 733 return strcmp(ctx->qry.page, page) ? NULL : "active";
734} 734}
735 735
736static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path) 736static void cgit_print_path_crumbs(struct cgit_context *ctx, char *path)
737{ 737{
738 char *old_path = ctx->qry.path; 738 char *old_path = ctx->qry.path;
739 char *p = path, *q, *end = path + strlen(path); 739 char *p = path, *q, *end = path + strlen(path);
740 740
741 ctx->qry.path = NULL; 741 ctx->qry.path = NULL;
742 cgit_self_link("root", NULL, NULL, ctx); 742 cgit_self_link("root", NULL, NULL, ctx);
743 ctx->qry.path = p = path; 743 ctx->qry.path = p = path;
744 while (p < end) { 744 while (p < end) {
745 if (!(q = strchr(p, '/'))) 745 if (!(q = strchr(p, '/')))
746 q = end; 746 q = end;
747 *q = '\0'; 747 *q = '\0';
748 html_txt("/"); 748 html_txt("/");
749 cgit_self_link(p, NULL, NULL, ctx); 749 cgit_self_link(p, NULL, NULL, ctx);
750 if (q < end) 750 if (q < end)
751 *q = '/'; 751 *q = '/';
752 p = q + 1; 752 p = q + 1;
753 } 753 }
754 ctx->qry.path = old_path; 754 ctx->qry.path = old_path;
755} 755}
756 756
757static void print_header(struct cgit_context *ctx) 757static void print_header(struct cgit_context *ctx)
758{ 758{
759 char *logo = NULL, *logo_link = NULL; 759 char *logo = NULL, *logo_link = NULL;
760 760
761 html("<table id='header'>\n"); 761 html("<table id='header'>\n");
762 html("<tr>\n"); 762 html("<tr>\n");
763 763
764 if (ctx->repo && ctx->repo->logo && *ctx->repo->logo) 764 if (ctx->repo && ctx->repo->logo && *ctx->repo->logo)
765 logo = ctx->repo->logo; 765 logo = ctx->repo->logo;
766 else 766 else
767 logo = ctx->cfg.logo; 767 logo = ctx->cfg.logo;
768 if (ctx->repo && ctx->repo->logo_link && *ctx->repo->logo_link) 768 if (ctx->repo && ctx->repo->logo_link && *ctx->repo->logo_link)
769 logo_link = ctx->repo->logo_link; 769 logo_link = ctx->repo->logo_link;