-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | cgit.c | 5 | ||||
-rw-r--r-- | html.c | 2 | ||||
-rw-r--r-- | ui-shared.c | 2 |
4 files changed, 7 insertions, 6 deletions
@@ -1,244 +1,244 @@ | |||
1 | CGIT_VERSION = v0.8.3.4 | 1 | CGIT_VERSION = v0.8.3.5 |
2 | CGIT_SCRIPT_NAME = cgit.cgi | 2 | CGIT_SCRIPT_NAME = cgit.cgi |
3 | CGIT_SCRIPT_PATH = /var/www/htdocs/cgit | 3 | CGIT_SCRIPT_PATH = /var/www/htdocs/cgit |
4 | CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) | 4 | CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) |
5 | CGIT_CONFIG = /etc/cgitrc | 5 | CGIT_CONFIG = /etc/cgitrc |
6 | CACHE_ROOT = /var/cache/cgit | 6 | CACHE_ROOT = /var/cache/cgit |
7 | prefix = /usr | 7 | prefix = /usr |
8 | libdir = $(prefix)/lib | 8 | libdir = $(prefix)/lib |
9 | filterdir = $(libdir)/cgit/filters | 9 | filterdir = $(libdir)/cgit/filters |
10 | docdir = $(prefix)/share/doc/cgit | 10 | docdir = $(prefix)/share/doc/cgit |
11 | htmldir = $(docdir) | 11 | htmldir = $(docdir) |
12 | pdfdir = $(docdir) | 12 | pdfdir = $(docdir) |
13 | mandir = $(prefix)/share/man | 13 | mandir = $(prefix)/share/man |
14 | SHA1_HEADER = <openssl/sha.h> | 14 | SHA1_HEADER = <openssl/sha.h> |
15 | GIT_VER = 1.7.4 | 15 | GIT_VER = 1.7.4 |
16 | GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 | 16 | GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 |
17 | INSTALL = install | 17 | INSTALL = install |
18 | MAN5_TXT = $(wildcard *.5.txt) | 18 | MAN5_TXT = $(wildcard *.5.txt) |
19 | MAN_TXT = $(MAN5_TXT) | 19 | MAN_TXT = $(MAN5_TXT) |
20 | DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT)) | 20 | DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT)) |
21 | DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT)) | 21 | DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT)) |
22 | DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT)) | 22 | DOC_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 | ||
43 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') | 43 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') |
44 | uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') | 44 | uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') |
45 | uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') | 45 | uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') |
46 | 46 | ||
47 | ifeq ($(uname_O),Cygwin) | 47 | ifeq ($(uname_O),Cygwin) |
48 | NO_STRCASESTR = YesPlease | 48 | NO_STRCASESTR = YesPlease |
49 | NEEDS_LIBICONV = YesPlease | 49 | NEEDS_LIBICONV = YesPlease |
50 | endif | 50 | endif |
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 | # |
61 | QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir | 61 | QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir |
62 | QUIET_SUBDIR1 = | 62 | QUIET_SUBDIR1 = |
63 | 63 | ||
64 | ifneq ($(findstring $(MAKEFLAGS),w),w) | 64 | ifneq ($(findstring $(MAKEFLAGS),w),w) |
65 | PRINT_DIR = --no-print-directory | 65 | PRINT_DIR = --no-print-directory |
66 | else # "make -w" | 66 | else # "make -w" |
67 | NO_SUBDIR = : | 67 | NO_SUBDIR = : |
68 | endif | 68 | endif |
69 | 69 | ||
70 | ifndef V | 70 | ifndef 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 |
76 | endif | 76 | endif |
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 | ||
91 | EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lpthread | 91 | EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lpthread |
92 | OBJECTS = | 92 | OBJECTS = |
93 | OBJECTS += cache.o | 93 | OBJECTS += cache.o |
94 | OBJECTS += cgit.o | 94 | OBJECTS += cgit.o |
95 | OBJECTS += cmd.o | 95 | OBJECTS += cmd.o |
96 | OBJECTS += configfile.o | 96 | OBJECTS += configfile.o |
97 | OBJECTS += html.o | 97 | OBJECTS += html.o |
98 | OBJECTS += parsing.o | 98 | OBJECTS += parsing.o |
99 | OBJECTS += scan-tree.o | 99 | OBJECTS += scan-tree.o |
100 | OBJECTS += shared.o | 100 | OBJECTS += shared.o |
101 | OBJECTS += ui-atom.o | 101 | OBJECTS += ui-atom.o |
102 | OBJECTS += ui-blob.o | 102 | OBJECTS += ui-blob.o |
103 | OBJECTS += ui-clone.o | 103 | OBJECTS += ui-clone.o |
104 | OBJECTS += ui-commit.o | 104 | OBJECTS += ui-commit.o |
105 | OBJECTS += ui-diff.o | 105 | OBJECTS += ui-diff.o |
106 | OBJECTS += ui-log.o | 106 | OBJECTS += ui-log.o |
107 | OBJECTS += ui-patch.o | 107 | OBJECTS += ui-patch.o |
108 | OBJECTS += ui-plain.o | 108 | OBJECTS += ui-plain.o |
109 | OBJECTS += ui-refs.o | 109 | OBJECTS += ui-refs.o |
110 | OBJECTS += ui-repolist.o | 110 | OBJECTS += ui-repolist.o |
111 | OBJECTS += ui-shared.o | 111 | OBJECTS += ui-shared.o |
112 | OBJECTS += ui-snapshot.o | 112 | OBJECTS += ui-snapshot.o |
113 | OBJECTS += ui-ssdiff.o | 113 | OBJECTS += ui-ssdiff.o |
114 | OBJECTS += ui-stats.o | 114 | OBJECTS += ui-stats.o |
115 | OBJECTS += ui-summary.o | 115 | OBJECTS += ui-summary.o |
116 | OBJECTS += ui-tag.o | 116 | OBJECTS += ui-tag.o |
117 | OBJECTS += ui-tree.o | 117 | OBJECTS += ui-tree.o |
118 | OBJECTS += vector.o | 118 | OBJECTS += vector.o |
119 | 119 | ||
120 | ifdef NEEDS_LIBICONV | 120 | ifdef NEEDS_LIBICONV |
121 | EXTLIBS += -liconv | 121 | EXTLIBS += -liconv |
122 | endif | 122 | endif |
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 | ||
129 | all: cgit | 129 | all: cgit |
130 | 130 | ||
131 | VERSION: force-version | 131 | VERSION: force-version |
132 | @./gen-version.sh "$(CGIT_VERSION)" | 132 | @./gen-version.sh "$(CGIT_VERSION)" |
133 | -include VERSION | 133 | -include VERSION |
134 | 134 | ||
135 | 135 | ||
136 | CFLAGS += -g -Wall -Igit | 136 | CFLAGS += -g -Wall -Igit |
137 | CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)' | 137 | CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)' |
138 | CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"' | 138 | CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"' |
139 | CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' | 139 | CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' |
140 | CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' | 140 | CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' |
141 | CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' | 141 | CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' |
142 | 142 | ||
143 | GIT_OPTIONS = prefix=/usr | 143 | GIT_OPTIONS = prefix=/usr |
144 | 144 | ||
145 | ifdef NO_ICONV | 145 | ifdef NO_ICONV |
146 | CFLAGS += -DNO_ICONV | 146 | CFLAGS += -DNO_ICONV |
147 | endif | 147 | endif |
148 | ifdef NO_STRCASESTR | 148 | ifdef NO_STRCASESTR |
149 | CFLAGS += -DNO_STRCASESTR | 149 | CFLAGS += -DNO_STRCASESTR |
150 | endif | 150 | endif |
151 | ifdef NO_C99_FORMAT | 151 | ifdef NO_C99_FORMAT |
152 | CFLAGS += -DNO_C99_FORMAT | 152 | CFLAGS += -DNO_C99_FORMAT |
153 | endif | 153 | endif |
154 | ifdef NO_OPENSSL | 154 | ifdef NO_OPENSSL |
155 | CFLAGS += -DNO_OPENSSL | 155 | CFLAGS += -DNO_OPENSSL |
156 | GIT_OPTIONS += NO_OPENSSL=1 | 156 | GIT_OPTIONS += NO_OPENSSL=1 |
157 | else | 157 | else |
158 | EXTLIBS += -lcrypto | 158 | EXTLIBS += -lcrypto |
159 | endif | 159 | endif |
160 | 160 | ||
161 | cgit: $(OBJECTS) libgit | 161 | cgit: $(OBJECTS) libgit |
162 | $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) | 162 | $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) |
163 | 163 | ||
164 | cgit.o: VERSION | 164 | cgit.o: VERSION |
165 | 165 | ||
166 | ifneq "$(MAKECMDGOALS)" "clean" | 166 | ifneq "$(MAKECMDGOALS)" "clean" |
167 | -include $(OBJECTS:.o=.d) | 167 | -include $(OBJECTS:.o=.d) |
168 | endif | 168 | endif |
169 | 169 | ||
170 | libgit: | 170 | libgit: |
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 | ||
174 | test: all | 174 | test: all |
175 | $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all | 175 | $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all |
176 | 176 | ||
177 | install: all | 177 | install: 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 | ||
186 | install-doc: install-man install-html install-pdf | 186 | install-doc: install-man install-html install-pdf |
187 | 187 | ||
188 | install-man: doc-man | 188 | install-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 | ||
192 | install-html: doc-html | 192 | install-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 | ||
196 | install-pdf: doc-pdf | 196 | install-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 | ||
200 | uninstall: | 200 | uninstall: |
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 | ||
205 | uninstall-doc: uninstall-man uninstall-html uninstall-pdf | 205 | uninstall-doc: uninstall-man uninstall-html uninstall-pdf |
206 | 206 | ||
207 | uninstall-man: | 207 | uninstall-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 | ||
212 | uninstall-html: | 212 | uninstall-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 | ||
217 | uninstall-pdf: | 217 | uninstall-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 | ||
222 | doc: doc-man doc-html doc-pdf | 222 | doc: doc-man doc-html doc-pdf |
223 | doc-man: doc-man5 | 223 | doc-man: doc-man5 |
224 | doc-man5: $(DOC_MAN5) | 224 | doc-man5: $(DOC_MAN5) |
225 | doc-html: $(DOC_HTML) | 225 | doc-html: $(DOC_HTML) |
226 | doc-pdf: $(DOC_PDF) | 226 | doc-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 | ||
237 | clean: clean-doc | 237 | clean: clean-doc |
238 | rm -f cgit VERSION *.o *.d | 238 | rm -f cgit VERSION *.o *.d |
239 | 239 | ||
240 | clean-doc: | 240 | clean-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 | ||
243 | get-git: | 243 | get-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 |
@@ -627,165 +627,166 @@ static void process_cached_repolist(const char *path) | |||
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 | ||
662 | static void cgit_parse_args(int argc, const char **argv) | 662 | static 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 | ||
721 | static int calc_ttl() | 721 | static 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 | ||
738 | int main(int argc, const char **argv) | 738 | int 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 | } |
@@ -152,169 +152,169 @@ void html_attr(const char *txt) | |||
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 | ||
159 | void html_url_path(const char *txt) | 159 | void 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 | ||
176 | void html_url_arg(const char *txt) | 176 | void 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 | ||
193 | void html_hidden(const char *name, const char *value) | 193 | void 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 | ||
202 | void html_option(const char *value, const char *text, const char *selected_value) | 202 | void 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 | ||
214 | void html_link_open(const char *url, const char *title, const char *class) | 214 | void 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 | ||
229 | void html_link_close(void) | 229 | void html_link_close(void) |
230 | { | 230 | { |
231 | html("</a>"); | 231 | html("</a>"); |
232 | } | 232 | } |
233 | 233 | ||
234 | void html_fileperm(unsigned short mode) | 234 | void 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 | ||
240 | int html_include(const char *filename) | 240 | int 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 | ||
257 | int hextoint(char c) | 257 | int 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 | ||
269 | char *convert_query_hexchar(char *txt) | 269 | char *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 | ||
289 | int http_parse_querystring(const char *txt_, void (*fn)(const char *name, const char *value)) | 289 | int 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 | |||
@@ -449,257 +449,257 @@ void cgit_self_link(char *name, const char *title, const char *class, | |||
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 | ||
485 | void cgit_object_link(struct object *obj) | 485 | void 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 | ||
506 | void cgit_print_date(time_t secs, const char *format, int local_time) | 506 | void 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 | ||
521 | void cgit_print_age(time_t t, time_t max_relative, const char *format) | 521 | void 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 | ||
564 | void cgit_print_http_headers(struct cgit_context *ctx) | 564 | void 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 | ||
590 | void cgit_print_docstart(struct cgit_context *ctx) | 590 | void 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 | ||
632 | void cgit_print_docend() | 632 | void 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 | ||
653 | int print_branch_option(const char *refname, const unsigned char *sha1, | 653 | int 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 | ||
661 | int print_archive_ref(const char *refname, const unsigned char *sha1, | 661 | int 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&path=%s", sha1_to_hex(fileid), | 692 | fmt("id=%s&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 | ||
700 | void cgit_add_hidden_formfields(int incl_head, int incl_search, | 700 | void 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) { |