diff options
| author | Lars Hjemli <hjemli@gmail.com> | 2008-04-08 21:29:21 +0200 | 
|---|---|---|
| committer | Lars Hjemli <hjemli@gmail.com> | 2008-04-08 21:29:21 +0200 | 
| commit | 23296ad648c0e2a9e3cf40a3de322b10ad25cce3 (patch) | |
| tree | 136493d8228b0ff4971feb06b0e8aee296367b00 | |
| parent | Use GIT-1.5.5-rc2 (diff) | |
| parent | Reset ctx.repo to NULL when the config parser is finished (diff) | |
| download | cgit-23296ad648c0e2a9e3cf40a3de322b10ad25cce3.tar.gz cgit-23296ad648c0e2a9e3cf40a3de322b10ad25cce3.tar.bz2 cgit-23296ad648c0e2a9e3cf40a3de322b10ad25cce3.zip | |
Merge branch 'lh/cleanup'
* lh/cleanup: (21 commits)
  Reset ctx.repo to NULL when the config parser is finished
  Move cgit_parse_query() from parsing.c to html.c as http_parse_querystring()
  Move function for configfile parsing into configfile.[ch]
  Add cache.h
  Remove global and obsolete cgit_cmd
  Makefile: copy the QUIET constructs from the Makefile in git.git
  Move cgit_version from shared.c to cgit.c
  Makefile: autobuild dependency rules
  Initial Makefile cleanup
  Move non-generic functions from shared.c to cgit.c
  Add ui-shared.h
  Add separate header-files for each page/view
  Refactor snapshot support
  Add command dispatcher
  Remove obsolete cacheitem parameter to ui-functions
  Add struct cgit_page to cgit_context
  Introduce html.h
  Improve initialization of git directory
  Move cgit_repo into cgit_context
  Add all config variables into struct cgit_context
  ...
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 75 | ||||
| -rw-r--r-- | cache.c | 21 | ||||
| -rw-r--r-- | cache.h | 23 | ||||
| -rw-r--r-- | cgit.c | 389 | ||||
| -rw-r--r-- | cgit.h | 227 | ||||
| -rw-r--r-- | cmd.c | 112 | ||||
| -rw-r--r-- | cmd.h | 15 | ||||
| -rw-r--r-- | configfile.c | 87 | ||||
| -rw-r--r-- | configfile.h | 8 | ||||
| -rw-r--r-- | html.c | 95 | ||||
| -rw-r--r-- | html.h | 20 | ||||
| -rw-r--r-- | parsing.c | 146 | ||||
| -rw-r--r-- | shared.c | 257 | ||||
| -rw-r--r-- | ui-blob.c | 16 | ||||
| -rw-r--r-- | ui-blob.h | 6 | ||||
| -rw-r--r-- | ui-commit.c | 26 | ||||
| -rw-r--r-- | ui-commit.h | 6 | ||||
| -rw-r--r-- | ui-diff.c | 9 | ||||
| -rw-r--r-- | ui-diff.h | 7 | ||||
| -rw-r--r-- | ui-log.c | 32 | ||||
| -rw-r--r-- | ui-log.h | 7 | ||||
| -rw-r--r-- | ui-patch.c | 10 | ||||
| -rw-r--r-- | ui-patch.h | 6 | ||||
| -rw-r--r-- | ui-refs.c | 175 | ||||
| -rw-r--r-- | ui-refs.h | 8 | ||||
| -rw-r--r-- | ui-repolist.c | 54 | ||||
| -rw-r--r-- | ui-repolist.h | 6 | ||||
| -rw-r--r-- | ui-shared.c | 237 | ||||
| -rw-r--r-- | ui-shared.h | 36 | ||||
| -rw-r--r-- | ui-snapshot.c | 121 | ||||
| -rw-r--r-- | ui-snapshot.h | 8 | ||||
| -rw-r--r-- | ui-summary.c | 189 | ||||
| -rw-r--r-- | ui-summary.h | 6 | ||||
| -rw-r--r-- | ui-tag.c | 3 | ||||
| -rw-r--r-- | ui-tag.h | 6 | ||||
| -rw-r--r-- | ui-tree.c | 26 | ||||
| -rw-r--r-- | ui-tree.h | 6 | 
38 files changed, 1372 insertions, 1110 deletions
| @@ -3,3 +3,4 @@ cgit  cgit.conf  VERSION  *.o +*.d @@ -12,13 +12,62 @@ GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2  #  -include cgit.conf +# +# Define a way to invoke make in subdirs quietly, shamelessly ripped +# from git.git +# +QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1  = -EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto -OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \ -	ui-summary.o ui-log.o ui-tree.o ui-commit.o ui-diff.o \ -	ui-snapshot.o ui-blob.o ui-tag.o ui-refs.o ui-patch.o +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + +ifndef V +	QUIET_CC       = @echo '   ' CC $@; +	QUIET_MM       = @echo '   ' MM $@; +	QUIET_SUBDIR0  = +@subdir= +	QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \ +			 $(MAKE) $(PRINT_DIR) -C $$subdir +endif + +# +# Define a pattern rule for automatic dependency building +# +%.d: %.c +	$(QUIET_MM)$(CC) $(CFLAGS) -MM $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@ + +# +# Define a pattern rule for silent object building +# +%.o: %.c +	$(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $< +EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto +OBJECTS = +OBJECTS += cache.o +OBJECTS += cgit.o +OBJECTS += cmd.o +OBJECTS += configfile.o +OBJECTS += html.o +OBJECTS += parsing.o +OBJECTS += shared.o +OBJECTS += ui-blob.o +OBJECTS += ui-commit.o +OBJECTS += ui-diff.o +OBJECTS += ui-log.o +OBJECTS += ui-patch.o +OBJECTS += ui-refs.o +OBJECTS += ui-repolist.o +OBJECTS += ui-shared.o +OBJECTS += ui-snapshot.o +OBJECTS += ui-summary.o +OBJECTS += ui-tag.o +OBJECTS += ui-tree.o +  ifdef NEEDS_LIBICONV  	EXTLIBS += -liconv  endif @@ -41,21 +90,25 @@ CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'  CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' -cgit: cgit.c $(OBJECTS) -	$(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS) +cgit: $(OBJECTS) +	$(QUIET_CC)$(CC) $(CFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) + +$(OBJECTS): git/xdiff/lib.a git/libgit.a + +cgit.o: VERSION -$(OBJECTS): cgit.h git/xdiff/lib.a git/libgit.a VERSION +-include $(OBJECTS:.o=.d)  git/xdiff/lib.a: | git  git/libgit.a: | git  git: -	cd git && $(MAKE) xdiff/lib.a -	cd git && $(MAKE) libgit.a +	$(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) xdiff/lib.a +	$(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) libgit.a  test: all -	$(MAKE) -C tests +	$(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all  install: all  	mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH) @@ -69,7 +122,7 @@ uninstall:  	rm -f $(CGIT_SCRIPT_PATH)/cgit.png  clean: -	rm -f cgit VERSION *.o +	rm -f cgit VERSION *.o *.d  	cd git && $(MAKE) clean  distclean: clean @@ -7,6 +7,7 @@   */  #include "cgit.h" +#include "cache.h"  const int NOLOCK = -1; @@ -44,23 +45,23 @@ int cache_create_dirs()  {  	char *path; -	path = fmt("%s", cgit_cache_root); +	path = fmt("%s", ctx.cfg.cache_root);  	if (mkdir(path, S_IRWXU) && errno!=EEXIST)  		return 0; -	if (!cgit_repo) +	if (!ctx.repo)  		return 0; -	path = fmt("%s/%s", cgit_cache_root, -		   cache_safe_filename(cgit_repo->url)); +	path = fmt("%s/%s", ctx.cfg.cache_root, +		   cache_safe_filename(ctx.repo->url));  	if (mkdir(path, S_IRWXU) && errno!=EEXIST)  		return 0; -	if (cgit_query_page) { -		path = fmt("%s/%s/%s", cgit_cache_root, -			   cache_safe_filename(cgit_repo->url), -			   cgit_query_page); +	if (ctx.qry.page) { +		path = fmt("%s/%s/%s", ctx.cfg.cache_root, +			   cache_safe_filename(ctx.repo->url), +			   ctx.qry.page);  		if (mkdir(path, S_IRWXU) && errno!=EEXIST)  			return 0;  	} @@ -74,7 +75,7 @@ int cache_refill_overdue(const char *lockfile)  	if (stat(lockfile, &st))  		return 0;  	else -		return (time(NULL) - st.st_mtime > cgit_cache_max_create_time); +		return (time(NULL) - st.st_mtime > ctx.cfg.cache_max_create_time);  }  int cache_lock(struct cacheitem *item) @@ -83,7 +84,7 @@ int cache_lock(struct cacheitem *item)  	char *lockfile = xstrdup(fmt("%s.lock", item->name));   top: -	if (++i > cgit_max_lock_attempts) +	if (++i > ctx.cfg.max_lock_attempts)  		die("cache_lock: unable to lock %s: %s",  		    item->name, strerror(errno)); @@ -0,0 +1,23 @@ +/* + * Since git has it's own cache.h which we include, + * lets test on CGIT_CACHE_H to avoid confusion + */ + +#ifndef CGIT_CACHE_H +#define CGIT_CACHE_H + +struct cacheitem { +	char *name; +	struct stat st; +	int ttl; +	int fd; +}; + +extern char *cache_safe_filename(const char *unsafe); +extern int cache_lock(struct cacheitem *item); +extern int cache_unlock(struct cacheitem *item); +extern int cache_cancel_lock(struct cacheitem *item); +extern int cache_exist(struct cacheitem *item); +extern int cache_expired(struct cacheitem *item); + +#endif /* CGIT_CACHE_H */ @@ -7,40 +7,199 @@   */  #include "cgit.h" +#include "cache.h" +#include "cmd.h" +#include "configfile.h" +#include "html.h" +#include "ui-shared.h" + +const char *cgit_version = CGIT_VERSION; + +void config_cb(const char *name, const char *value) +{ +	if (!strcmp(name, "root-title")) +		ctx.cfg.root_title = xstrdup(value); +	else if (!strcmp(name, "css")) +		ctx.cfg.css = xstrdup(value); +	else if (!strcmp(name, "logo")) +		ctx.cfg.logo = xstrdup(value); +	else if (!strcmp(name, "index-header")) +		ctx.cfg.index_header = xstrdup(value); +	else if (!strcmp(name, "index-info")) +		ctx.cfg.index_info = xstrdup(value); +	else if (!strcmp(name, "logo-link")) +		ctx.cfg.logo_link = xstrdup(value); +	else if (!strcmp(name, "module-link")) +		ctx.cfg.module_link = xstrdup(value); +	else if (!strcmp(name, "virtual-root")) { +		ctx.cfg.virtual_root = trim_end(value, '/'); +		if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) +			ctx.cfg.virtual_root = ""; +	} else if (!strcmp(name, "nocache")) +		ctx.cfg.nocache = atoi(value); +	else if (!strcmp(name, "snapshots")) +		ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); +	else if (!strcmp(name, "enable-index-links")) +		ctx.cfg.enable_index_links = atoi(value); +	else if (!strcmp(name, "enable-log-filecount")) +		ctx.cfg.enable_log_filecount = atoi(value); +	else if (!strcmp(name, "enable-log-linecount")) +		ctx.cfg.enable_log_linecount = atoi(value); +	else if (!strcmp(name, "cache-root")) +		ctx.cfg.cache_root = xstrdup(value); +	else if (!strcmp(name, "cache-root-ttl")) +		ctx.cfg.cache_root_ttl = atoi(value); +	else if (!strcmp(name, "cache-repo-ttl")) +		ctx.cfg.cache_repo_ttl = atoi(value); +	else if (!strcmp(name, "cache-static-ttl")) +		ctx.cfg.cache_static_ttl = atoi(value); +	else if (!strcmp(name, "cache-dynamic-ttl")) +		ctx.cfg.cache_dynamic_ttl = atoi(value); +	else if (!strcmp(name, "max-message-length")) +		ctx.cfg.max_msg_len = atoi(value); +	else if (!strcmp(name, "max-repodesc-length")) +		ctx.cfg.max_repodesc_len = atoi(value); +	else if (!strcmp(name, "max-commit-count")) +		ctx.cfg.max_commit_count = atoi(value); +	else if (!strcmp(name, "summary-log")) +		ctx.cfg.summary_log = atoi(value); +	else if (!strcmp(name, "summary-branches")) +		ctx.cfg.summary_branches = atoi(value); +	else if (!strcmp(name, "summary-tags")) +		ctx.cfg.summary_tags = atoi(value); +	else if (!strcmp(name, "agefile")) +		ctx.cfg.agefile = xstrdup(value); +	else if (!strcmp(name, "renamelimit")) +		ctx.cfg.renamelimit = atoi(value); +	else if (!strcmp(name, "robots")) +		ctx.cfg.robots = xstrdup(value); +	else if (!strcmp(name, "clone-prefix")) +		ctx.cfg.clone_prefix = xstrdup(value); +	else if (!strcmp(name, "repo.group")) +		ctx.cfg.repo_group = xstrdup(value); +	else if (!strcmp(name, "repo.url")) +		ctx.repo = cgit_add_repo(value); +	else if (!strcmp(name, "repo.name")) +		ctx.repo->name = xstrdup(value); +	else if (ctx.repo && !strcmp(name, "repo.path")) +		ctx.repo->path = trim_end(value, '/'); +	else if (ctx.repo && !strcmp(name, "repo.clone-url")) +		ctx.repo->clone_url = xstrdup(value); +	else if (ctx.repo && !strcmp(name, "repo.desc")) +		ctx.repo->desc = xstrdup(value); +	else if (ctx.repo && !strcmp(name, "repo.owner")) +		ctx.repo->owner = xstrdup(value); +	else if (ctx.repo && !strcmp(name, "repo.defbranch")) +		ctx.repo->defbranch = xstrdup(value); +	else if (ctx.repo && !strcmp(name, "repo.snapshots")) +		ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ +	else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) +		ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); +	else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) +		ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); +	else if (ctx.repo && !strcmp(name, "repo.module-link")) +		ctx.repo->module_link= xstrdup(value); +	else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { +		if (*value == '/') +			ctx.repo->readme = xstrdup(value); +		else +			ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); +	} else if (!strcmp(name, "include")) +		parse_configfile(value, config_cb); +} + +static void querystring_cb(const char *name, const char *value) +{ +	if (!strcmp(name,"r")) { +		ctx.qry.repo = xstrdup(value); +		ctx.repo = cgit_get_repoinfo(value); +	} else if (!strcmp(name, "p")) { +		ctx.qry.page = xstrdup(value); +	} else if (!strcmp(name, "url")) { +		cgit_parse_url(value); +	} else if (!strcmp(name, "qt")) { +		ctx.qry.grep = xstrdup(value); +	} else if (!strcmp(name, "q")) { +		ctx.qry.search = xstrdup(value); +	} else if (!strcmp(name, "h")) { +		ctx.qry.head = xstrdup(value); +		ctx.qry.has_symref = 1; +	} else if (!strcmp(name, "id")) { +		ctx.qry.sha1 = xstrdup(value); +		ctx.qry.has_sha1 = 1; +	} else if (!strcmp(name, "id2")) { +		ctx.qry.sha2 = xstrdup(value); +		ctx.qry.has_sha1 = 1; +	} else if (!strcmp(name, "ofs")) { +		ctx.qry.ofs = atoi(value); +	} else if (!strcmp(name, "path")) { +		ctx.qry.path = trim_end(value, '/'); +	} else if (!strcmp(name, "name")) { +		ctx.qry.name = xstrdup(value); +	} +} + +static void prepare_context(struct cgit_context *ctx) +{ +	memset(ctx, 0, sizeof(ctx)); +	ctx->cfg.agefile = "info/web/last-modified"; +	ctx->cfg.cache_dynamic_ttl = 5; +	ctx->cfg.cache_max_create_time = 5; +	ctx->cfg.cache_repo_ttl = 5; +	ctx->cfg.cache_root = CGIT_CACHE_ROOT; +	ctx->cfg.cache_root_ttl = 5; +	ctx->cfg.cache_static_ttl = -1; +	ctx->cfg.css = "/cgit.css"; +	ctx->cfg.logo = "/git-logo.png"; +	ctx->cfg.max_commit_count = 50; +	ctx->cfg.max_lock_attempts = 5; +	ctx->cfg.max_msg_len = 60; +	ctx->cfg.max_repodesc_len = 60; +	ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; +	ctx->cfg.renamelimit = -1; +	ctx->cfg.robots = "index, nofollow"; +	ctx->cfg.root_title = "Git repository browser"; +	ctx->cfg.script_name = CGIT_SCRIPT_NAME; +	ctx->page.mimetype = "text/html"; +	ctx->page.charset = PAGE_ENCODING; +	ctx->page.filename = NULL; +}  static int cgit_prepare_cache(struct cacheitem *item)  { -	if (!cgit_repo && cgit_query_repo) { -		char *title = fmt("%s - %s", cgit_root_title, "Bad request"); -		cgit_print_docstart(title, item); -		cgit_print_pageheader(title, 0); -		cgit_print_error(fmt("Unknown repo: %s", cgit_query_repo)); +	if (!ctx.repo && ctx.qry.repo) { +		ctx.page.title = fmt("%s - %s", ctx.cfg.root_title, +				      "Bad request"); +		cgit_print_http_headers(&ctx); +		cgit_print_docstart(&ctx); +		cgit_print_pageheader(&ctx); +		cgit_print_error(fmt("Unknown repo: %s", ctx.qry.repo));  		cgit_print_docend();  		return 0;  	} -	if (!cgit_repo) { -		item->name = xstrdup(fmt("%s/index.html", cgit_cache_root)); -		item->ttl = cgit_cache_root_ttl; +	if (!ctx.repo) { +		item->name = xstrdup(fmt("%s/index.html", ctx.cfg.cache_root)); +		item->ttl = ctx.cfg.cache_root_ttl;  		return 1;  	} -	if (!cgit_cmd) { -		item->name = xstrdup(fmt("%s/%s/index.%s.html", cgit_cache_root, -					 cache_safe_filename(cgit_repo->url), -					 cache_safe_filename(cgit_querystring))); -		item->ttl = cgit_cache_repo_ttl; +	if (!ctx.qry.page) { +		item->name = xstrdup(fmt("%s/%s/index.%s.html", ctx.cfg.cache_root, +					 cache_safe_filename(ctx.repo->url), +					 cache_safe_filename(ctx.qry.raw))); +		item->ttl = ctx.cfg.cache_repo_ttl;  	} else { -		item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, -					 cache_safe_filename(cgit_repo->url), -					 cgit_query_page, -					 cache_safe_filename(cgit_querystring))); -		if (cgit_query_has_symref) -			item->ttl = cgit_cache_dynamic_ttl; -		else if (cgit_query_has_sha1) -			item->ttl = cgit_cache_static_ttl; +		item->name = xstrdup(fmt("%s/%s/%s/%s.html", ctx.cfg.cache_root, +					 cache_safe_filename(ctx.repo->url), +					 ctx.qry.page, +					 cache_safe_filename(ctx.qry.raw))); +		if (ctx.qry.has_symref) +			item->ttl = ctx.cfg.cache_dynamic_ttl; +		else if (ctx.qry.has_sha1) +			item->ttl = ctx.cfg.cache_static_ttl;  		else -			item->ttl = cgit_cache_repo_ttl; +			item->ttl = ctx.cfg.cache_repo_ttl;  	}  	return 1;  } @@ -64,7 +223,7 @@ int find_current_ref(const char *refname, const unsigned char *sha1,  	return info->match;  } -char *find_default_branch(struct repoinfo *repo) +char *find_default_branch(struct cgit_repo *repo)  {  	struct refmatch info; @@ -78,113 +237,98 @@ char *find_default_branch(struct repoinfo *repo)  		return info.first_ref;  } -static void cgit_print_repo_page(struct cacheitem *item) +static int prepare_repo_cmd(struct cgit_context *ctx)  { -	char *title, *tmp; -	int show_search; +	char *tmp;  	unsigned char sha1[20]; +	int nongit = 0; -	if (chdir(cgit_repo->path)) { -		title = fmt("%s - %s", cgit_root_title, "Bad request"); -		cgit_print_docstart(title, item); -		cgit_print_pageheader(title, 0); -		cgit_print_error(fmt("Unable to scan repository: %s", -				     strerror(errno))); +	setenv("GIT_DIR", ctx->repo->path, 1); +	setup_git_directory_gently(&nongit); +	if (nongit) { +		ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, +				      "config error"); +		tmp = fmt("Not a git repository: '%s'", ctx->repo->path); +		ctx->repo = NULL; +		cgit_print_http_headers(ctx); +		cgit_print_docstart(ctx); +		cgit_print_pageheader(ctx); +		cgit_print_error(tmp);  		cgit_print_docend(); -		return; +		return 1;  	} +	ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); -	title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); -	show_search = 0; -	setenv("GIT_DIR", cgit_repo->path, 1); - -	if (!cgit_query_head) { -		cgit_query_head = xstrdup(find_default_branch(cgit_repo)); -		cgit_repo->defbranch = cgit_query_head; +	if (!ctx->qry.head) { +		ctx->qry.head = xstrdup(find_default_branch(ctx->repo)); +		ctx->repo->defbranch = ctx->qry.head;  	} -	if (!cgit_query_head) { -		cgit_print_docstart(title, item); -		cgit_print_pageheader(title, 0); +	if (!ctx->qry.head) { +		cgit_print_http_headers(ctx); +		cgit_print_docstart(ctx); +		cgit_print_pageheader(ctx);  		cgit_print_error("Repository seems to be empty");  		cgit_print_docend(); -		return; +		return 1;  	} -	if (get_sha1(cgit_query_head, sha1)) { -		tmp = xstrdup(cgit_query_head); -		cgit_query_head = cgit_repo->defbranch; -		cgit_print_docstart(title, item); -		cgit_print_pageheader(title, 0); +	if (get_sha1(ctx->qry.head, sha1)) { +		tmp = xstrdup(ctx->qry.head); +		ctx->qry.head = ctx->repo->defbranch; +		cgit_print_http_headers(ctx); +		cgit_print_docstart(ctx); +		cgit_print_pageheader(ctx);  		cgit_print_error(fmt("Invalid branch: %s", tmp));  		cgit_print_docend(); -		return; +		return 1;  	} +	return 0; +} -	if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) { -		cgit_print_snapshot(item, cgit_query_head, cgit_query_sha1, -				    cgit_repobasename(cgit_repo->url), -				    cgit_query_path, -				    cgit_repo->snapshots ); -		return; -	} +static void process_request(struct cgit_context *ctx) +{ +	struct cgit_cmd *cmd; -	if (cgit_cmd == CMD_PATCH) { -		cgit_print_patch(cgit_query_sha1, item); +	cmd = cgit_get_cmd(ctx); +	if (!cmd) { +		ctx->page.title = "cgit error"; +		ctx->repo = NULL; +		cgit_print_http_headers(ctx); +		cgit_print_docstart(ctx); +		cgit_print_pageheader(ctx); +		cgit_print_error("Invalid request"); +		cgit_print_docend();  		return;  	} -	if (cgit_cmd == CMD_BLOB) { -		cgit_print_blob(item, cgit_query_sha1, cgit_query_path); +	if (cmd->want_repo && prepare_repo_cmd(ctx))  		return; -	} -	show_search = (cgit_cmd == CMD_LOG); -	cgit_print_docstart(title, item); -	if (!cgit_cmd) { -		cgit_print_pageheader("summary", show_search); -		cgit_print_summary(); -		cgit_print_docend(); -		return; +	if (cmd->want_layout) { +		cgit_print_http_headers(ctx); +		cgit_print_docstart(ctx); +		cgit_print_pageheader(ctx);  	} -	cgit_print_pageheader(cgit_query_page, show_search); +	cmd->fn(ctx); -	switch(cgit_cmd) { -	case CMD_LOG: -		cgit_print_log(cgit_query_sha1, cgit_query_ofs, -			       cgit_max_commit_count, cgit_query_grep, cgit_query_search, -			       cgit_query_path, 1); -		break; -	case CMD_TREE: -		cgit_print_tree(cgit_query_sha1, cgit_query_path); -		break; -	case CMD_COMMIT: -		cgit_print_commit(cgit_query_sha1); -		break; -	case CMD_REFS: -		cgit_print_refs(); -		break; -	case CMD_TAG: -		cgit_print_tag(cgit_query_sha1); -		break; -	case CMD_DIFF: -		cgit_print_diff(cgit_query_sha1, cgit_query_sha2, cgit_query_path); -		break; -	default: -		cgit_print_error("Invalid request"); -	} -	cgit_print_docend(); +	if (cmd->want_layout) +		cgit_print_docend(); +} + +static long ttl_seconds(long ttl) +{ +	if (ttl<0) +		return 60 * 60 * 24 * 365; +	else +		return ttl * 60;  }  static void cgit_fill_cache(struct cacheitem *item, int use_cache)  { -	static char buf[PATH_MAX];  	int stdout2; -	getcwd(buf, sizeof(buf)); -	item->st.st_mtime = time(NULL); -  	if (use_cache) {  		stdout2 = chk_positive(dup(STDOUT_FILENO),  				       "Preserving STDOUT"); @@ -192,10 +336,9 @@ static void cgit_fill_cache(struct cacheitem *item, int use_cache)  		chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)");  	} -	if (cgit_repo) -		cgit_print_repo_page(item); -	else -		cgit_print_repolist(item); +	ctx.page.modified = time(NULL); +	ctx.page.expires = ctx.page.modified + ttl_seconds(item->ttl); +	process_request(&ctx);  	if (use_cache) {  		chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); @@ -203,8 +346,6 @@ static void cgit_fill_cache(struct cacheitem *item, int use_cache)  			     "Restoring original STDOUT");  		chk_zero(close(stdout2), "Closing temporary STDOUT");  	} - -	chdir(buf);  }  static void cgit_check_cache(struct cacheitem *item) @@ -212,7 +353,7 @@ static void cgit_check_cache(struct cacheitem *item)  	int i = 0;   top: -	if (++i > cgit_max_lock_attempts) { +	if (++i > ctx.cfg.max_lock_attempts) {  		die("cgit_refresh_cache: unable to lock %s: %s",  		    item->name, strerror(errno));  	} @@ -258,30 +399,30 @@ static void cgit_parse_args(int argc, const char **argv)  	for (i = 1; i < argc; i++) {  		if (!strncmp(argv[i], "--cache=", 8)) { -			cgit_cache_root = xstrdup(argv[i]+8); +			ctx.cfg.cache_root = xstrdup(argv[i]+8);  		}  		if (!strcmp(argv[i], "--nocache")) { -			cgit_nocache = 1; +			ctx.cfg.nocache = 1;  		}  		if (!strncmp(argv[i], "--query=", 8)) { -			cgit_querystring = xstrdup(argv[i]+8); +			ctx.qry.raw = xstrdup(argv[i]+8);  		}  		if (!strncmp(argv[i], "--repo=", 7)) { -			cgit_query_repo = xstrdup(argv[i]+7); +			ctx.qry.repo = xstrdup(argv[i]+7);  		}  		if (!strncmp(argv[i], "--page=", 7)) { -			cgit_query_page = xstrdup(argv[i]+7); +			ctx.qry.page = xstrdup(argv[i]+7);  		}  		if (!strncmp(argv[i], "--head=", 7)) { -			cgit_query_head = xstrdup(argv[i]+7); -			cgit_query_has_symref = 1; +			ctx.qry.head = xstrdup(argv[i]+7); +			ctx.qry.has_symref = 1;  		}  		if (!strncmp(argv[i], "--sha1=", 7)) { -			cgit_query_sha1 = xstrdup(argv[i]+7); -			cgit_query_has_sha1 = 1; +			ctx.qry.sha1 = xstrdup(argv[i]+7); +			ctx.qry.has_sha1 = 1;  		}  		if (!strncmp(argv[i], "--ofs=", 6)) { -			cgit_query_ofs = atoi(argv[i]+6); +			ctx.qry.ofs = atoi(argv[i]+6);  		}  	}  } @@ -291,24 +432,24 @@ int main(int argc, const char **argv)  	struct cacheitem item;  	const char *cgit_config_env = getenv("CGIT_CONFIG"); -	htmlfd = STDOUT_FILENO; +	prepare_context(&ctx);  	item.st.st_mtime = time(NULL);  	cgit_repolist.length = 0;  	cgit_repolist.count = 0;  	cgit_repolist.repos = NULL; -	cgit_read_config(cgit_config_env ? cgit_config_env : CGIT_CONFIG, -			 cgit_global_config_cb); -	cgit_repo = NULL; +	parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, +			 config_cb); +	ctx.repo = NULL;  	if (getenv("SCRIPT_NAME")) -		cgit_script_name = xstrdup(getenv("SCRIPT_NAME")); +		ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));  	if (getenv("QUERY_STRING")) -		cgit_querystring = xstrdup(getenv("QUERY_STRING")); +		ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));  	cgit_parse_args(argc, argv); -	cgit_parse_query(cgit_querystring, cgit_querystring_cb); +	http_parse_querystring(ctx.qry.raw, querystring_cb);  	if (!cgit_prepare_cache(&item))  		return 0; -	if (cgit_nocache) { +	if (ctx.cfg.nocache) {  		cgit_fill_cache(&item, 0);  	} else {  		cgit_check_cache(&item); @@ -20,19 +20,6 @@  /* - * The valid cgit repo-commands - */ -#define CMD_LOG      1 -#define CMD_COMMIT   2 -#define CMD_DIFF     3 -#define CMD_TREE     4 -#define CMD_BLOB     5 -#define CMD_SNAPSHOT 6 -#define CMD_TAG      7 -#define CMD_REFS     8 -#define CMD_PATCH    9 - -/*   * Dateformats used on misc. pages   */  #define FMT_LONGDATE "%Y-%m-%d %H:%M:%S" @@ -59,14 +46,7 @@ typedef void (*configfn)(const char *name, const char *value);  typedef void (*filepair_fn)(struct diff_filepair *pair);  typedef void (*linediff_fn)(char *line, int len); -struct cacheitem { -	char *name; -	struct stat st; -	int ttl; -	int fd; -}; - -struct repoinfo { +struct cgit_repo {  	char *url;  	char *name;  	char *path; @@ -82,10 +62,10 @@ struct repoinfo {  	int enable_log_linecount;  }; -struct repolist { +struct cgit_repolist {  	int length;  	int count; -	struct repoinfo *repos; +	struct cgit_repo *repos;  };  struct commitinfo { @@ -123,74 +103,94 @@ struct reflist {  	int count;  }; -extern const char *cgit_version; - -extern struct repolist cgit_repolist; -extern struct repoinfo *cgit_repo; -extern int cgit_cmd; +struct cgit_query { +	int has_symref; +	int has_sha1; +	char *raw; +	char *repo; +	char *page; +	char *search; +	char *grep; +	char *head; +	char *sha1; +	char *sha2; +	char *path; +	char *name; +	int   ofs; +}; -extern char *cgit_root_title; -extern char *cgit_css; -extern char *cgit_logo; -extern char *cgit_index_header; -extern char *cgit_index_info; -extern char *cgit_logo_link; -extern char *cgit_module_link; -extern char *cgit_agefile; -extern char *cgit_virtual_root; -extern char *cgit_script_name; -extern char *cgit_cache_root; -extern char *cgit_repo_group; -extern char *cgit_robots; -extern char *cgit_clone_prefix; +struct cgit_config { +	char *agefile; +	char *cache_root; +	char *clone_prefix; +	char *css; +	char *index_header; +	char *index_info; +	char *logo; +	char *logo_link; +	char *module_link; +	char *repo_group; +	char *robots; +	char *root_title; +	char *script_name; +	char *virtual_root; +	int cache_dynamic_ttl; +	int cache_max_create_time; +	int cache_repo_ttl; +	int cache_root_ttl; +	int cache_static_ttl; +	int enable_index_links; +	int enable_log_filecount; +	int enable_log_linecount; +	int max_commit_count; +	int max_lock_attempts; +	int max_msg_len; +	int max_repodesc_len; +	int nocache; +	int renamelimit; +	int snapshots; +	int summary_branches; +	int summary_log; +	int summary_tags; +}; -extern int cgit_nocache; -extern int cgit_snapshots; -extern int cgit_enable_index_links; -extern int cgit_enable_log_filecount; -extern int cgit_enable_log_linecount; -extern int cgit_max_lock_attempts; -extern int cgit_cache_root_ttl; -extern int cgit_cache_repo_ttl; -extern int cgit_cache_dynamic_ttl; -extern int cgit_cache_static_ttl; -extern int cgit_cache_max_create_time; -extern int cgit_summary_log; -extern int cgit_summary_tags; -extern int cgit_summary_branches; +struct cgit_page { +	time_t modified; +	time_t expires; +	char *mimetype; +	char *charset; +	char *filename; +	char *title; +}; -extern int cgit_max_msg_len; -extern int cgit_max_repodesc_len; -extern int cgit_max_commit_count; +struct cgit_context { +	struct cgit_query qry; +	struct cgit_config cfg; +	struct cgit_repo *repo; +	struct cgit_page page; +}; -extern int cgit_query_has_symref; -extern int cgit_query_has_sha1; +struct cgit_snapshot_format { +	const char *suffix; +	const char *mimetype; +	write_archive_fn_t write_func; +	int bit; +}; -extern char *cgit_querystring; -extern char *cgit_query_repo; -extern char *cgit_query_page; -extern char *cgit_query_search; -extern char *cgit_query_grep; -extern char *cgit_query_head; -extern char *cgit_query_sha1; -extern char *cgit_query_sha2; -extern char *cgit_query_path; -extern char *cgit_query_name; -extern int   cgit_query_ofs; +extern const char *cgit_version; -extern int htmlfd; +extern struct cgit_repolist cgit_repolist; +extern struct cgit_context ctx; +extern const struct cgit_snapshot_format cgit_snapshot_formats[]; -extern int cgit_get_cmd_index(const char *cmd); -extern struct repoinfo *cgit_get_repoinfo(const char *url); -extern void cgit_global_config_cb(const char *name, const char *value); +extern struct cgit_repo *cgit_add_repo(const char *url); +extern struct cgit_repo *cgit_get_repoinfo(const char *url);  extern void cgit_repo_config_cb(const char *name, const char *value); -extern void cgit_querystring_cb(const char *name, const char *value);  extern int chk_zero(int result, char *msg);  extern int chk_positive(int result, char *msg);  extern int chk_non_negative(int result, char *msg); -extern int hextoint(char c);  extern char *trim_end(const char *str, char c);  extern char *strlpart(char *txt, int maxlen);  extern char *strrpart(char *txt, int maxlen); @@ -213,83 +213,12 @@ extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);  extern char *fmt(const char *format,...); -extern void html(const char *txt); -extern void htmlf(const char *format,...); -extern void html_txt(char *txt); -extern void html_ntxt(int len, char *txt); -extern void html_attr(char *txt); -extern void html_hidden(char *name, char *value); -extern void html_option(char *value, char *text, char *selected_value); -extern void html_link_open(char *url, char *title, char *class); -extern void html_link_close(void); -extern void html_filemode(unsigned short mode); -extern int html_include(const char *filename); - -extern int cgit_read_config(const char *filename, configfn fn); -extern int cgit_parse_query(char *txt, configfn fn);  extern struct commitinfo *cgit_parse_commit(struct commit *commit);  extern struct taginfo *cgit_parse_tag(struct tag *tag);  extern void cgit_parse_url(const char *url); -extern char *cache_safe_filename(const char *unsafe); -extern int cache_lock(struct cacheitem *item); -extern int cache_unlock(struct cacheitem *item); -extern int cache_cancel_lock(struct cacheitem *item); -extern int cache_exist(struct cacheitem *item); -extern int cache_expired(struct cacheitem *item); - -extern char *cgit_repourl(const char *reponame); -extern char *cgit_fileurl(const char *reponame, const char *pagename, -			  const char *filename, const char *query); -extern char *cgit_pageurl(const char *reponame, const char *pagename, -			  const char *query); -  extern const char *cgit_repobasename(const char *reponame); -extern void cgit_tree_link(char *name, char *title, char *class, char *head, -			   char *rev, char *path); -extern void cgit_log_link(char *name, char *title, char *class, char *head, -			  char *rev, char *path, int ofs, char *grep, -			  char *pattern); -extern void cgit_commit_link(char *name, char *title, char *class, char *head, -			     char *rev); -extern void cgit_refs_link(char *name, char *title, char *class, char *head, -			   char *rev, char *path); -extern void cgit_snapshot_link(char *name, char *title, char *class, -			       char *head, char *rev, char *archivename); -extern void cgit_diff_link(char *name, char *title, char *class, char *head, -			   char *new_rev, char *old_rev, char *path); - -extern void cgit_object_link(struct object *obj); - -extern void cgit_print_error(char *msg); -extern void cgit_print_date(time_t secs, char *format); -extern void cgit_print_age(time_t t, time_t max_relative, char *format); -extern void cgit_print_docstart(char *title, struct cacheitem *item); -extern void cgit_print_docend(); -extern void cgit_print_pageheader(char *title, int show_search); -extern void cgit_print_snapshot_start(const char *mimetype, -				      const char *filename, -				      struct cacheitem *item); -extern void cgit_print_branches(int maxcount); -extern void cgit_print_tags(int maxcount); - -extern void cgit_print_repolist(struct cacheitem *item); -extern void cgit_print_summary(); -extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, -			   char *pattern, char *path, int pager); -extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); -extern void cgit_print_tree(const char *rev, char *path); -extern void cgit_print_commit(char *hex); -extern void cgit_print_refs(); -extern void cgit_print_tag(char *revname); -extern void cgit_print_diff(const char *new_hex, const char *old_hex, const char *prefix); -extern void cgit_print_patch(char *hex, struct cacheitem *item); -extern void cgit_print_snapshot(struct cacheitem *item, const char *head, -				const char *hex, const char *prefix, -				const char *filename, int snapshot); -extern void cgit_print_snapshot_links(const char *repo, const char *head, -				      const char *hex, int snapshots);  extern int cgit_parse_snapshots_mask(const char *str);  #endif /* CGIT_H */ @@ -0,0 +1,112 @@ +/* cmd.c: the cgit command dispatcher + * + * Copyright (C) 2008 Lars Hjemli + * + * Licensed under GNU General Public License v2 + *   (see COPYING for full license text) + */ + +#include "cgit.h" +#include "cmd.h" +#include "ui-blob.h" +#include "ui-commit.h" +#include "ui-diff.h" +#include "ui-log.h" +#include "ui-patch.h" +#include "ui-refs.h" +#include "ui-repolist.h" +#include "ui-snapshot.h" +#include "ui-summary.h" +#include "ui-tag.h" +#include "ui-tree.h" + +static void blob_fn(struct cgit_context *ctx) +{ +	cgit_print_blob(ctx->qry.sha1, ctx->qry.path); +} + +static void commit_fn(struct cgit_context *ctx) +{ +	cgit_print_commit(ctx->qry.sha1); +} + +static void diff_fn(struct cgit_context *ctx) +{ +	cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path); +} + +static void repolist_fn(struct cgit_context *ctx) +{ +	cgit_print_repolist(); +} + +static void log_fn(struct cgit_context *ctx) +{ +	cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count, +		       ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1); +} + +static void patch_fn(struct cgit_context *ctx) +{ +	cgit_print_patch(ctx->qry.sha1); +} + +static void refs_fn(struct cgit_context *ctx) +{ +	cgit_print_refs(); +} + +static void snapshot_fn(struct cgit_context *ctx) +{ +	cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, +			    cgit_repobasename(ctx->repo->url), ctx->qry.path, +			    ctx->repo->snapshots); +} + +static void summary_fn(struct cgit_context *ctx) +{ +	cgit_print_summary(); +} + +static void tag_fn(struct cgit_context *ctx) +{ +	cgit_print_tag(ctx->qry.sha1); +} + +static void tree_fn(struct cgit_context *ctx) +{ +	cgit_print_tree(ctx->qry.sha1, ctx->qry.path); +} + +#define def_cmd(name, want_repo, want_layout) \ +	{#name, name##_fn, want_repo, want_layout} + +struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) +{ +	static struct cgit_cmd cmds[] = { +		def_cmd(blob, 1, 0), +		def_cmd(commit, 1, 1), +		def_cmd(diff, 1, 1), +		def_cmd(log, 1, 1), +		def_cmd(patch, 1, 0), +		def_cmd(refs, 1, 1), +		def_cmd(repolist, 0, 0), +		def_cmd(snapshot, 1, 0), +		def_cmd(summary, 1, 1), +		def_cmd(tag, 1, 1), +		def_cmd(tree, 1, 1), +	}; +	int i; + +	if (ctx->qry.page == NULL) { +		if (ctx->repo) +			ctx->qry.page = "summary"; +		else +			ctx->qry.page = "repolist"; +	} + +	for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++) +		if (!strcmp(ctx->qry.page, cmds[i].name)) +			return &cmds[i]; +	return NULL; +} @@ -0,0 +1,15 @@ +#ifndef CMD_H +#define CMD_H + +typedef void (*cgit_cmd_fn)(struct cgit_context *ctx); + +struct cgit_cmd { +	const char *name; +	cgit_cmd_fn fn; +	unsigned int want_repo:1, +		want_layout:1; +}; + +extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx); + +#endif /* CMD_H */ diff --git a/configfile.c b/configfile.c new file mode 100644 index 0000000..4908058 --- /dev/null +++ b/configfile.c @@ -0,0 +1,87 @@ +/* configfile.c: parsing of config files + * + * Copyright (C) 2008 Lars Hjemli + * + * Licensed under GNU General Public License v2 + *   (see COPYING for full license text) + */ + +#include <ctype.h> +#include <stdio.h> +#include "configfile.h" + +int next_char(FILE *f) +{ +	int c = fgetc(f); +	if (c=='\r') { +		c = fgetc(f); +		if (c!='\n') { +			ungetc(c, f); +			c = '\r'; +		} +	} +	return c; +} + +void skip_line(FILE *f) +{ +	int c; + +	while((c=next_char(f)) && c!='\n' && c!=EOF) +		; +} + +int read_config_line(FILE *f, char *line, const char **value, int bufsize) +{ +	int i = 0, isname = 0; + +	*value = NULL; +	while(i<bufsize-1) { +		int c = next_char(f); +		if (!isname && (c=='#' || c==';')) { +			skip_line(f); +			continue; +		} +		if (!isname && isspace(c)) +			continue; + +		if (c=='=' && !*value) { +			line[i] = 0; +			*value = &line[i+1]; +		} else if (c=='\n' && !isname) { +			i = 0; +			continue; +		} else if (c=='\n' || c==EOF) { +			line[i] = 0; +			break; +		} else { +			line[i]=c; +		} +		isname = 1; +		i++; +	} +	line[i+1] = 0; +	return i; +} + +int parse_configfile(const char *filename, configfile_value_fn fn) +{ +	static int nesting; +	int len; +	char line[256]; +	const char *value; +	FILE *f; + +	/* cancel deeply nested include-commands */ +	if (nesting > 8) +		return -1; +	if (!(f = fopen(filename, "r"))) +		return -1; +	nesting++; +	while((len = read_config_line(f, line, &value, sizeof(line))) > 0) +		fn(line, value); +	nesting--; +	fclose(f); +	return 0; +} + diff --git a/configfile.h b/configfile.h new file mode 100644 index 0000000..04235e5 --- /dev/null +++ b/configfile.h @@ -0,0 +1,8 @@ +#ifndef CONFIGFILE_H +#define CONFIGFILE_H + +typedef void (*configfile_value_fn)(const char *name, const char *value); + +extern int parse_configfile(const char *filename, configfile_value_fn fn); + +#endif /* CONFIGFILE_H */ @@ -6,7 +6,13 @@   *   (see COPYING for full license text)   */ -#include "cgit.h" +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +int htmlfd = STDOUT_FILENO;  char *fmt(const char *format, ...)  { @@ -21,8 +27,10 @@ char *fmt(const char *format, ...)  	va_start(args, format);  	len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args);  	va_end(args); -	if (len>sizeof(buf[bufidx])) -		die("[html.c] string truncated: %s", format); +	if (len>sizeof(buf[bufidx])) { +		fprintf(stderr, "[html.c] string truncated: %s\n", format); +		exit(1); +	}  	return buf[bufidx];  } @@ -150,25 +158,10 @@ void html_link_close(void)  void html_fileperm(unsigned short mode)  { -	htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),  +	htmlf("%c%c%c", (mode & 4 ? 'r' : '-'),  	      (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-'));  } -void html_filemode(unsigned short mode) -{ -	if (S_ISDIR(mode)) -		html("d"); -	else if (S_ISLNK(mode)) -		html("l"); -	else if (S_ISGITLINK(mode)) -		html("m"); -	else -		html("-"); -	html_fileperm(mode >> 6); -	html_fileperm(mode >> 3); -	html_fileperm(mode); -} -  int html_include(const char *filename)  {  	FILE *f; @@ -182,3 +175,67 @@ int html_include(const char *filename)  	fclose(f);  	return 0;  } + +int hextoint(char c) +{ +	if (c >= 'a' && c <= 'f') +		return 10 + c - 'a'; +	else if (c >= 'A' && c <= 'F') +		return 10 + c - 'A'; +	else if (c >= '0' && c <= '9') +		return c - '0'; +	else +		return -1; +} + +char *convert_query_hexchar(char *txt) +{ +	int d1, d2; +	if (strlen(txt) < 3) { +		*txt = '\0'; +		return txt-1; +	} +	d1 = hextoint(*(txt+1)); +	d2 = hextoint(*(txt+2)); +	if (d1<0 || d2<0) { +		strcpy(txt, txt+3); +		return txt-1; +	} else { +		*txt = d1 * 16 + d2; +		strcpy(txt+1, txt+3); +		return txt; +	} +} + +int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value)) +{ +	char *t, *value = NULL, c; + +	if (!txt) +		return 0; + +	t = txt = strdup(txt); +	if (t == NULL) { +		printf("Out of memory\n"); +		exit(1); +	} +	while((c=*t) != '\0') { +		if (c=='=') { +			*t = '\0'; +			value = t+1; +		} else if (c=='+') { +			*t = ' '; +		} else if (c=='%') { +			t = convert_query_hexchar(t); +		} else if (c=='&') { +			*t = '\0'; +			(*fn)(txt, value); +			txt = t+1; +			value = NULL; +		} +		t++; +	} +	if (t!=txt) +		(*fn)(txt, value); +	return 0; +} @@ -0,0 +1,20 @@ +#ifndef HTML_H +#define HTML_H + +extern int htmlfd; + +extern void html(const char *txt); +extern void htmlf(const char *format,...); +extern void html_txt(char *txt); +extern void html_ntxt(int len, char *txt); +extern void html_attr(char *txt); +extern void html_hidden(char *name, char *value); +extern void html_option(char *value, char *text, char *selected_value); +extern void html_link_open(char *url, char *title, char *class); +extern void html_link_close(void); +extern void html_fileperm(unsigned short mode); +extern int html_include(const char *filename); + +extern int http_parse_querystring(char *txt, void (*fn)(const char *name, const char *value)); + +#endif /* HTML_H */ @@ -8,130 +8,6 @@  #include "cgit.h" -int next_char(FILE *f) -{ -	int c = fgetc(f); -	if (c=='\r') { -		c = fgetc(f); -		if (c!='\n') { -			ungetc(c, f); -			c = '\r'; -		} -	} -	return c; -} - -void skip_line(FILE *f) -{ -	int c; - -	while((c=next_char(f)) && c!='\n' && c!=EOF) -		; -} - -int read_config_line(FILE *f, char *line, const char **value, int bufsize) -{ -	int i = 0, isname = 0; - -	*value = NULL; -	while(i<bufsize-1) { -		int c = next_char(f); -		if (!isname && (c=='#' || c==';')) { -			skip_line(f); -			continue; -		} -		if (!isname && isspace(c)) -			continue; - -		if (c=='=' && !*value) { -			line[i] = 0; -			*value = &line[i+1]; -		} else if (c=='\n' && !isname) { -			i = 0; -			continue; -		} else if (c=='\n' || c==EOF) { -			line[i] = 0; -			break; -		} else { -			line[i]=c; -		} -		isname = 1; -		i++; -	} -	line[i+1] = 0; -	return i; -} - -int cgit_read_config(const char *filename, configfn fn) -{ -	static int nesting; -	int len; -	char line[256]; -	const char *value; -	FILE *f; - -	/* cancel deeply nested include-commands */ -	if (nesting > 8) -		return -1; -	if (!(f = fopen(filename, "r"))) -		return -1; -	nesting++; -	while((len = read_config_line(f, line, &value, sizeof(line))) > 0) -		(*fn)(line, value); -	nesting--; -	fclose(f); -	return 0; -} - -char *convert_query_hexchar(char *txt) -{ -	int d1, d2; -	if (strlen(txt) < 3) { -		*txt = '\0'; -		return txt-1; -	} -	d1 = hextoint(*(txt+1)); -	d2 = hextoint(*(txt+2)); -	if (d1<0 || d2<0) { -		strcpy(txt, txt+3); -		return txt-1; -	} else { -		*txt = d1 * 16 + d2; -		strcpy(txt+1, txt+3); -		return txt; -	} -} - -int cgit_parse_query(char *txt, configfn fn) -{ -	char *t, *value = NULL, c; - -	if (!txt) -		return 0; - -	t = txt = xstrdup(txt); - -	while((c=*t) != '\0') { -		if (c=='=') { -			*t = '\0'; -			value = t+1; -		} else if (c=='+') { -			*t = ' '; -		} else if (c=='%') { -			t = convert_query_hexchar(t); -		} else if (c=='&') { -			*t = '\0'; -			(*fn)(txt, value); -			txt = t+1; -			value = NULL; -		} -		t++; -	} -	if (t!=txt) -		(*fn)(txt, value); -	return 0; -} -  /*   * url syntax: [repo ['/' cmd [ '/' path]]]   *   repo: any valid repo url, may contain '/' @@ -143,35 +19,35 @@ void cgit_parse_url(const char *url)  {  	char *cmd, *p; -	cgit_repo = NULL; +	ctx.repo = NULL;  	if (!url || url[0] == '\0')  		return; -	cgit_repo = cgit_get_repoinfo(url); -	if (cgit_repo) { -		cgit_query_repo = cgit_repo->url; +	ctx.repo = cgit_get_repoinfo(url); +	if (ctx.repo) { +		ctx.qry.repo = ctx.repo->url;  		return;  	}  	cmd = strchr(url, '/'); -	while (!cgit_repo && cmd) { +	while (!ctx.repo && cmd) {  		cmd[0] = '\0'; -		cgit_repo = cgit_get_repoinfo(url); -		if (cgit_repo == NULL) { +		ctx.repo = cgit_get_repoinfo(url); +		if (ctx.repo == NULL) {  			cmd[0] = '/';  			cmd = strchr(cmd + 1, '/');  			continue;  		} -		cgit_query_repo = cgit_repo->url; +		ctx.qry.repo = ctx.repo->url;  		p = strchr(cmd + 1, '/');  		if (p) {  			p[0] = '\0';  			if (p[1]) -				cgit_query_path = trim_end(p + 1, '/'); +				ctx.qry.path = trim_end(p + 1, '/');  		} -		cgit_cmd = cgit_get_cmd_index(cmd + 1); -		cgit_query_page = xstrdup(cmd + 1); +		if (cmd[1]) +			ctx.qry.page = xstrdup(cmd + 1);  		return;  	}  } @@ -8,77 +8,10 @@  #include "cgit.h" -struct repolist cgit_repolist; -struct repoinfo *cgit_repo; +struct cgit_repolist cgit_repolist; +struct cgit_context ctx;  int cgit_cmd; -const char *cgit_version = CGIT_VERSION; - -char *cgit_root_title   = "Git repository browser"; -char *cgit_css          = "/cgit.css"; -char *cgit_logo         = "/git-logo.png"; -char *cgit_index_header = NULL; -char *cgit_index_info   = NULL; -char *cgit_logo_link    = "http://www.kernel.org/pub/software/scm/git/docs/"; -char *cgit_module_link  = "./?repo=%s&page=commit&id=%s"; -char *cgit_agefile      = "info/web/last-modified"; -char *cgit_virtual_root = NULL; -char *cgit_script_name  = CGIT_SCRIPT_NAME; -char *cgit_cache_root   = CGIT_CACHE_ROOT; -char *cgit_repo_group   = NULL; -char *cgit_robots       = "index, nofollow"; -char *cgit_clone_prefix = NULL; - -int cgit_nocache               =  0; -int cgit_snapshots             =  0; -int cgit_enable_index_links    =  0; -int cgit_enable_log_filecount  =  0; -int cgit_enable_log_linecount  =  0; -int cgit_max_lock_attempts     =  5; -int cgit_cache_root_ttl        =  5; -int cgit_cache_repo_ttl        =  5; -int cgit_cache_dynamic_ttl     =  5; -int cgit_cache_static_ttl      = -1; -int cgit_cache_max_create_time =  5; -int cgit_summary_log           =  0; -int cgit_summary_tags          =  0; -int cgit_summary_branches      =  0; -int cgit_renamelimit           = -1; - -int cgit_max_msg_len = 60; -int cgit_max_repodesc_len = 60; -int cgit_max_commit_count = 50; - -int cgit_query_has_symref = 0; -int cgit_query_has_sha1   = 0; - -char *cgit_querystring  = NULL; -char *cgit_query_repo   = NULL; -char *cgit_query_page   = NULL; -char *cgit_query_head   = NULL; -char *cgit_query_search = NULL; -char *cgit_query_grep   = NULL; -char *cgit_query_sha1   = NULL; -char *cgit_query_sha2   = NULL; -char *cgit_query_path   = NULL; -char *cgit_query_name   = NULL; -int   cgit_query_ofs    = 0; - -int htmlfd = 0; - - -int cgit_get_cmd_index(const char *cmd) -{ -	static char *cmds[] = {"log", "commit", "diff", "tree", "blob", -			       "snapshot", "tag", "refs", "patch", NULL}; -	int i; - -	for(i = 0; cmds[i]; i++) -		if (!strcmp(cmd, cmds[i])) -			return i + 1; -	return 0; -} -  int chk_zero(int result, char *msg)  {  	if (result != 0) @@ -100,9 +33,9 @@ int chk_non_negative(int result, char *msg)  	return result;  } -struct repoinfo *add_repo(const char *url) +struct cgit_repo *cgit_add_repo(const char *url)  { -	struct repoinfo *ret; +	struct cgit_repo *ret;  	if (++cgit_repolist.count > cgit_repolist.length) {  		if (cgit_repolist.length == 0) @@ -111,7 +44,7 @@ struct repoinfo *add_repo(const char *url)  			cgit_repolist.length *= 2;  		cgit_repolist.repos = xrealloc(cgit_repolist.repos,  					       cgit_repolist.length * -					       sizeof(struct repoinfo)); +					       sizeof(struct cgit_repo));  	}  	ret = &cgit_repolist.repos[cgit_repolist.count-1]; @@ -120,20 +53,20 @@ struct repoinfo *add_repo(const char *url)  	ret->path = NULL;  	ret->desc = "[no description]";  	ret->owner = NULL; -	ret->group = cgit_repo_group; +	ret->group = ctx.cfg.repo_group;  	ret->defbranch = "master"; -	ret->snapshots = cgit_snapshots; -	ret->enable_log_filecount = cgit_enable_log_filecount; -	ret->enable_log_linecount = cgit_enable_log_linecount; -	ret->module_link = cgit_module_link; +	ret->snapshots = ctx.cfg.snapshots; +	ret->enable_log_filecount = ctx.cfg.enable_log_filecount; +	ret->enable_log_linecount = ctx.cfg.enable_log_linecount; +	ret->module_link = ctx.cfg.module_link;  	ret->readme = NULL;  	return ret;  } -struct repoinfo *cgit_get_repoinfo(const char *url) +struct cgit_repo *cgit_get_repoinfo(const char *url)  {  	int i; -	struct repoinfo *repo; +	struct cgit_repo *repo;  	for (i=0; i<cgit_repolist.count; i++) {  		repo = &cgit_repolist.repos[i]; @@ -143,131 +76,6 @@ struct repoinfo *cgit_get_repoinfo(const char *url)  	return NULL;  } -void cgit_global_config_cb(const char *name, const char *value) -{ -	if (!strcmp(name, "root-title")) -		cgit_root_title = xstrdup(value); -	else if (!strcmp(name, "css")) -		cgit_css = xstrdup(value); -	else if (!strcmp(name, "logo")) -		cgit_logo = xstrdup(value); -	else if (!strcmp(name, "index-header")) -		cgit_index_header = xstrdup(value); -	else if (!strcmp(name, "index-info")) -		cgit_index_info = xstrdup(value); -	else if (!strcmp(name, "logo-link")) -		cgit_logo_link = xstrdup(value); -	else if (!strcmp(name, "module-link")) -		cgit_module_link = xstrdup(value); -	else if (!strcmp(name, "virtual-root")) { -		cgit_virtual_root = trim_end(value, '/'); -		if (!cgit_virtual_root && (!strcmp(value, "/"))) -			cgit_virtual_root = ""; -	} else if (!strcmp(name, "nocache")) -		cgit_nocache = atoi(value); -	else if (!strcmp(name, "snapshots")) -		cgit_snapshots = cgit_parse_snapshots_mask(value); -	else if (!strcmp(name, "enable-index-links")) -		cgit_enable_index_links = atoi(value); -	else if (!strcmp(name, "enable-log-filecount")) -		cgit_enable_log_filecount = atoi(value); -	else if (!strcmp(name, "enable-log-linecount")) -		cgit_enable_log_linecount = atoi(value); -	else if (!strcmp(name, "cache-root")) -		cgit_cache_root = xstrdup(value); -	else if (!strcmp(name, "cache-root-ttl")) -		cgit_cache_root_ttl = atoi(value); -	else if (!strcmp(name, "cache-repo-ttl")) -		cgit_cache_repo_ttl = atoi(value); -	else if (!strcmp(name, "cache-static-ttl")) -		cgit_cache_static_ttl = atoi(value); -	else if (!strcmp(name, "cache-dynamic-ttl")) -		cgit_cache_dynamic_ttl = atoi(value); -	else if (!strcmp(name, "max-message-length")) -		cgit_max_msg_len = atoi(value); -	else if (!strcmp(name, "max-repodesc-length")) -		cgit_max_repodesc_len = atoi(value); -	else if (!strcmp(name, "max-commit-count")) -		cgit_max_commit_count = atoi(value); -	else if (!strcmp(name, "summary-log")) -		cgit_summary_log = atoi(value); -	else if (!strcmp(name, "summary-branches")) -		cgit_summary_branches = atoi(value); -	else if (!strcmp(name, "summary-tags")) -		cgit_summary_tags = atoi(value); -	else if (!strcmp(name, "agefile")) -		cgit_agefile = xstrdup(value); -	else if (!strcmp(name, "renamelimit")) -		cgit_renamelimit = atoi(value); -	else if (!strcmp(name, "robots")) -		cgit_robots = xstrdup(value); -	else if (!strcmp(name, "clone-prefix")) -		cgit_clone_prefix = xstrdup(value); -	else if (!strcmp(name, "repo.group")) -		cgit_repo_group = xstrdup(value); -	else if (!strcmp(name, "repo.url")) -		cgit_repo = add_repo(value); -	else if (!strcmp(name, "repo.name")) -		cgit_repo->name = xstrdup(value); -	else if (cgit_repo && !strcmp(name, "repo.path")) -		cgit_repo->path = trim_end(value, '/'); -	else if (cgit_repo && !strcmp(name, "repo.clone-url")) -		cgit_repo->clone_url = xstrdup(value); -	else if (cgit_repo && !strcmp(name, "repo.desc")) -		cgit_repo->desc = xstrdup(value); -	else if (cgit_repo && !strcmp(name, "repo.owner")) -		cgit_repo->owner = xstrdup(value); -	else if (cgit_repo && !strcmp(name, "repo.defbranch")) -		cgit_repo->defbranch = xstrdup(value); -	else if (cgit_repo && !strcmp(name, "repo.snapshots")) -		cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ -	else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) -		cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); -	else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) -		cgit_repo->enable_log_linecount = cgit_enable_log_linecount * atoi(value); -	else if (cgit_repo && !strcmp(name, "repo.module-link")) -		cgit_repo->module_link= xstrdup(value); -	else if (cgit_repo && !strcmp(name, "repo.readme") && value != NULL) { -		if (*value == '/') -			cgit_repo->readme = xstrdup(value); -		else -			cgit_repo->readme = xstrdup(fmt("%s/%s", cgit_repo->path, value)); -	} else if (!strcmp(name, "include")) -		cgit_read_config(value, cgit_global_config_cb); -} - -void cgit_querystring_cb(const char *name, const char *value) -{ -	if (!strcmp(name,"r")) { -		cgit_query_repo = xstrdup(value); -		cgit_repo = cgit_get_repoinfo(value); -	} else if (!strcmp(name, "p")) { -		cgit_query_page = xstrdup(value); -		cgit_cmd = cgit_get_cmd_index(value); -	} else if (!strcmp(name, "url")) { -		cgit_parse_url(value); -	} else if (!strcmp(name, "qt")) { -		cgit_query_grep = xstrdup(value); -	} else if (!strcmp(name, "q")) { -		cgit_query_search = xstrdup(value); -	} else if (!strcmp(name, "h")) { -		cgit_query_head = xstrdup(value); -		cgit_query_has_symref = 1; -	} else if (!strcmp(name, "id")) { -		cgit_query_sha1 = xstrdup(value); -		cgit_query_has_sha1 = 1; -	} else if (!strcmp(name, "id2")) { -		cgit_query_sha2 = xstrdup(value); -		cgit_query_has_sha1 = 1; -	} else if (!strcmp(name, "ofs")) { -		cgit_query_ofs = atoi(value); -	} else if (!strcmp(name, "path")) { -		cgit_query_path = trim_end(value, '/'); -	} else if (!strcmp(name, "name")) { -		cgit_query_name = xstrdup(value); -	} -} -  void *cgit_free_commitinfo(struct commitinfo *info)  {  	free(info->author); @@ -281,18 +89,6 @@ void *cgit_free_commitinfo(struct commitinfo *info)  	return NULL;  } -int hextoint(char c) -{ -	if (c >= 'a' && c <= 'f') -		return 10 + c - 'a'; -	else if (c >= 'A' && c <= 'F') -		return 10 + c - 'A'; -	else if (c >= '0' && c <= '9') -		return c - '0'; -	else -		return -1; -} -  char *trim_end(const char *str, char c)  {  	int len; @@ -491,7 +287,7 @@ void cgit_diff_tree(const unsigned char *old_sha1,  	diff_setup(&opt);  	opt.output_format = DIFF_FORMAT_CALLBACK;  	opt.detect_rename = 1; -	opt.rename_limit = cgit_renamelimit; +	opt.rename_limit = ctx.cfg.renamelimit;  	DIFF_OPT_SET(&opt, RECURSIVE);  	opt.format_callback = cgit_diff_tree_cb;  	opt.format_callback_data = fn; @@ -519,3 +315,30 @@ void cgit_diff_commit(struct commit *commit, filepair_fn fn)  		old_sha1 = commit->parents->item->object.sha1;  	cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL);  } + +int cgit_parse_snapshots_mask(const char *str) +{ +	const struct cgit_snapshot_format *f; +	static const char *delim = " \t,:/|;"; +	int tl, sl, rv = 0; + +	/* favor legacy setting */ +	if(atoi(str)) +		return 1; +	for(;;) { +		str += strspn(str,delim); +		tl = strcspn(str,delim); +		if (!tl) +			break; +		for (f = cgit_snapshot_formats; f->suffix; f++) { +			sl = strlen(f->suffix); +			if((tl == sl && !strncmp(f->suffix, str, tl)) || +			   (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) { +				rv |= f->bit; +				break; +			} +		} +		str += tl; +	} +	return rv; +} @@ -1,6 +1,16 @@ +/* ui-blob.c: show blob content + * + * Copyright (C) 2008 Lars Hjemli + * + * Licensed under GNU General Public License v2 + *   (see COPYING for full license text) + */ +  #include "cgit.h" +#include "html.h" +#include "ui-shared.h" -void cgit_print_blob(struct cacheitem *item, const char *hex, char *path) +void cgit_print_blob(const char *hex, char *path)  {  	unsigned char sha1[20]; @@ -26,6 +36,8 @@ void cgit_print_blob(struct cacheitem *item, const char *hex, char *path)  	}  	buf[size] = '\0'; -	cgit_print_snapshot_start("text/plain", path, item); +	ctx.page.mimetype = "text/plain"; +	ctx.page.filename = path; +	cgit_print_http_headers(&ctx);  	write(htmlfd, buf, size);  } diff --git a/ui-blob.h b/ui-blob.h new file mode 100644 index 0000000..5a920a8 --- /dev/null +++ b/ui-blob.h @@ -0,0 +1,6 @@ +#ifndef UI_BLOB_H +#define UI_BLOB_H + +extern void cgit_print_blob(const char *hex, char *path); + +#endif /* UI_BLOB_H */ diff --git a/ui-commit.c b/ui-commit.c index bd55a33..8019e36 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -7,6 +7,8 @@   */  #include "cgit.h" +#include "html.h" +#include "ui-shared.h"  static int files, slots;  static int total_adds, total_rems, max_changes; @@ -62,20 +64,20 @@ void print_fileinfo(struct fileinfo *info)  	html("<tr>");  	htmlf("<td class='mode'>");  	if (is_null_sha1(info->new_sha1)) { -		html_filemode(info->old_mode); +		cgit_print_filemode(info->old_mode);  	} else { -		html_filemode(info->new_mode); +		cgit_print_filemode(info->new_mode);  	}  	if (info->old_mode != info->new_mode &&  	    !is_null_sha1(info->old_sha1) &&  	    !is_null_sha1(info->new_sha1)) {  		html("<span class='modechange'>["); -		html_filemode(info->old_mode); +		cgit_print_filemode(info->old_mode);  		html("]</span>");  	}  	htmlf("</td><td class='%s'>", class); -	cgit_diff_link(info->new_path, NULL, NULL, cgit_query_head, curr_rev, +	cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, curr_rev,  		       NULL, info->new_path);  	if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)  		htmlf(" (%s from %s)", @@ -143,7 +145,7 @@ void cgit_print_commit(char *hex)  	int i;  	if (!hex) -		hex = cgit_query_head; +		hex = ctx.qry.head;  	curr_rev = hex;  	if (get_sha1(hex, sha1)) { @@ -175,7 +177,7 @@ void cgit_print_commit(char *hex)  	html("<tr><th>tree</th><td colspan='2' class='sha1'>");  	tmp = xstrdup(hex);  	cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, -		       cgit_query_head, tmp, NULL); +		       ctx.qry.head, tmp, NULL);  	html("</td></tr>\n");        	for (p = commit->parents; p ; p = p->next) {  		parent = lookup_commit_reference(p->item->object.sha1); @@ -188,16 +190,16 @@ void cgit_print_commit(char *hex)  		html("<tr><th>parent</th>"  		     "<td colspan='2' class='sha1'>");  		cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, -				 cgit_query_head, sha1_to_hex(p->item->object.sha1)); +				 ctx.qry.head, sha1_to_hex(p->item->object.sha1));  		html(" ("); -		cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex, +		cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,  			       sha1_to_hex(p->item->object.sha1), NULL);  		html(")</td></tr>");  	} -	if (cgit_repo->snapshots) { +	if (ctx.repo->snapshots) {  		html("<tr><th>download</th><td colspan='2' class='sha1'>"); -		cgit_print_snapshot_links(cgit_query_repo, cgit_query_head, -					  hex, cgit_repo->snapshots); +		cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, +					  hex, ctx.repo->snapshots);  		html("</td></tr>");  	}  	html("</table>\n"); @@ -218,7 +220,7 @@ void cgit_print_commit(char *hex)  		html("<div class='diffstat-summary'>");  		htmlf("%d files changed, %d insertions, %d deletions (",  		      files, total_adds, total_rems); -		cgit_diff_link("show diff", NULL, NULL, cgit_query_head, hex, +		cgit_diff_link("show diff", NULL, NULL, ctx.qry.head, hex,  			       NULL, NULL);  		html(")</div>");  	} diff --git a/ui-commit.h b/ui-commit.h new file mode 100644 index 0000000..40bcb31 --- /dev/null +++ b/ui-commit.h @@ -0,0 +1,6 @@ +#ifndef UI_COMMIT_H +#define UI_COMMIT_H + +extern void cgit_print_commit(char *hex); + +#endif /* UI_COMMIT_H */ @@ -7,7 +7,8 @@   */  #include "cgit.h" - +#include "html.h" +#include "ui-shared.h"  unsigned char old_rev_sha1[20];  unsigned char new_rev_sha1[20]; @@ -71,13 +72,13 @@ static void header(unsigned char *sha1, char *path1, int mode1,  		}  		html("<br/>--- a/");  		if (mode1 != 0) -			cgit_tree_link(path1, NULL, NULL, cgit_query_head, +			cgit_tree_link(path1, NULL, NULL, ctx.qry.head,  				       sha1_to_hex(old_rev_sha1), path1);  		else  			html_txt(path1);  		html("<br/>+++ b/");  		if (mode2 != 0) -			cgit_tree_link(path2, NULL, NULL, cgit_query_head, +			cgit_tree_link(path2, NULL, NULL, ctx.qry.head,  				       sha1_to_hex(new_rev_sha1), path2);  		else  			html_txt(path2); @@ -107,7 +108,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi  	struct commit *commit, *commit2;  	if (!new_rev) -		new_rev = cgit_query_head; +		new_rev = ctx.qry.head;  	get_sha1(new_rev, new_rev_sha1);  	type = sha1_object_info(new_rev_sha1, &size);  	if (type == OBJ_BAD) { diff --git a/ui-diff.h b/ui-diff.h new file mode 100644 index 0000000..2307322 --- /dev/null +++ b/ui-diff.h @@ -0,0 +1,7 @@ +#ifndef UI_DIFF_H +#define UI_DIFF_H + +extern void cgit_print_diff(const char *new_hex, const char *old_hex, +			    const char *prefix); + +#endif /* UI_DIFF_H */ @@ -7,6 +7,8 @@   */  #include "cgit.h" +#include "html.h" +#include "ui-shared.h"  int files, add_lines, rem_lines; @@ -25,7 +27,7 @@ void count_lines(char *line, int size)  void inspect_files(struct diff_filepair *pair)  {  	files++; -	if (cgit_repo->enable_log_linecount) +	if (ctx.repo->enable_log_linecount)  		cgit_diff_files(pair->one->sha1, pair->two->sha1, count_lines);  } @@ -37,16 +39,16 @@ void print_commit(struct commit *commit)  	html("<tr><td>");  	cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);  	html("</td><td>"); -	cgit_commit_link(info->subject, NULL, NULL, cgit_query_head, +	cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,  			 sha1_to_hex(commit->object.sha1)); -	if (cgit_repo->enable_log_filecount) { +	if (ctx.repo->enable_log_filecount) {  		files = 0;  		add_lines = 0;  		rem_lines = 0;  		cgit_diff_commit(commit, inspect_files);  		html("</td><td class='right'>");  		htmlf("%d", files); -		if (cgit_repo->enable_log_linecount) { +		if (ctx.repo->enable_log_linecount) {  			html("</td><td class='right'>");  			htmlf("-%d/+%d", rem_lines, add_lines);  		} @@ -67,7 +69,7 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern  	int i;  	if (!tip) -		argv[1] = cgit_query_head; +		argv[1] = ctx.qry.head;  	if (grep && pattern && (!strcmp(grep, "grep") ||  				!strcmp(grep, "author") || @@ -94,9 +96,9 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern  	html("<tr class='nohover'><th class='left'>Age</th>"  	     "<th class='left'>Message</th>"); -	if (cgit_repo->enable_log_filecount) { +	if (ctx.repo->enable_log_filecount) {  		html("<th class='right'>Files</th>"); -		if (cgit_repo->enable_log_linecount) +		if (ctx.repo->enable_log_linecount)  			html("<th class='right'>Lines</th>");  	}  	html("<th class='left'>Author</th></tr>\n"); @@ -123,17 +125,17 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern  	if (pager) {  		html("<div class='pager'>");  		if (ofs > 0) { -			cgit_log_link("[prev]", NULL, NULL, cgit_query_head, -				      cgit_query_sha1, cgit_query_path, -				      ofs - cnt, cgit_query_grep, -				      cgit_query_search); +			cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, +				      ctx.qry.sha1, ctx.qry.path, +				      ofs - cnt, ctx.qry.grep, +				      ctx.qry.search);  			html(" ");  		}  		if ((commit = get_revision(&rev)) != NULL) { -			cgit_log_link("[next]", NULL, NULL, cgit_query_head, -				      cgit_query_sha1, cgit_query_path, -				      ofs + cnt, cgit_query_grep, -				      cgit_query_search); +			cgit_log_link("[next]", NULL, NULL, ctx.qry.head, +				      ctx.qry.sha1, ctx.qry.path, +				      ofs + cnt, ctx.qry.grep, +				      ctx.qry.search);  		}  		html("</div>");  	} diff --git a/ui-log.h b/ui-log.h new file mode 100644 index 0000000..877e40e --- /dev/null +++ b/ui-log.h @@ -0,0 +1,7 @@ +#ifndef UI_LOG_H +#define UI_LOG_H + +extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, +			   char *pattern, char *path, int pager); + +#endif /* UI_LOG_H */ @@ -7,6 +7,8 @@   */  #include "cgit.h" +#include "html.h" +#include "ui-shared.h"  static void print_line(char *line, int len)  { @@ -68,7 +70,7 @@ static void filepair_cb(struct diff_filepair *pair)  		html("Error running diff");  } -void cgit_print_patch(char *hex, struct cacheitem *item) +void cgit_print_patch(char *hex)  {  	struct commit *commit;  	struct commitinfo *info; @@ -76,7 +78,7 @@ void cgit_print_patch(char *hex, struct cacheitem *item)  	char *patchname;  	if (!hex) -		hex = cgit_query_head; +		hex = ctx.qry.head;  	if (get_sha1(hex, sha1)) {  		cgit_print_error(fmt("Bad object id: %s", hex)); @@ -95,7 +97,9 @@ void cgit_print_patch(char *hex, struct cacheitem *item)  		hashclr(old_sha1);  	patchname = fmt("%s.patch", sha1_to_hex(sha1)); -	cgit_print_snapshot_start("text/plain", patchname, item); +	ctx.page.mimetype = "text/plain"; +	ctx.page.filename = patchname; +	cgit_print_http_headers(&ctx);  	htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1));  	htmlf("From: %s%s\n", info->author, info->author_email);  	html("Date: "); diff --git a/ui-patch.h b/ui-patch.h new file mode 100644 index 0000000..9f68212 --- /dev/null +++ b/ui-patch.h @@ -0,0 +1,6 @@ +#ifndef UI_PATCH_H +#define UI_PATCH_H + +extern void cgit_print_patch(char *hex); + +#endif /* UI_PATCH_H */ @@ -7,18 +7,189 @@   */  #include "cgit.h" +#include "html.h" +#include "ui-shared.h" +static int header; +static int cmp_age(int age1, int age2) +{ +	if (age1 != 0 && age2 != 0) +		return age2 - age1; + +	if (age1 == 0 && age2 == 0) +		return 0; + +	if (age1 == 0) +		return +1; + +	return -1; +} + +static int cmp_ref_name(const void *a, const void *b) +{ +	struct refinfo *r1 = *(struct refinfo **)a; +	struct refinfo *r2 = *(struct refinfo **)b; + +	return strcmp(r1->refname, r2->refname); +} + +static int cmp_branch_age(const void *a, const void *b) +{ +	struct refinfo *r1 = *(struct refinfo **)a; +	struct refinfo *r2 = *(struct refinfo **)b; + +	return cmp_age(r1->commit->committer_date, r2->commit->committer_date); +} + +static int cmp_tag_age(const void *a, const void *b) +{ +	struct refinfo *r1 = *(struct refinfo **)a; +	struct refinfo *r2 = *(struct refinfo **)b; + +	return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); +} + +static int print_branch(struct refinfo *ref) +{ +	struct commitinfo *info = ref->commit; +	char *name = (char *)ref->refname; + +	if (!info) +		return 1; +	html("<tr><td>"); +	cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL); +	html("</td><td>"); + +	if (ref->object->type == OBJ_COMMIT) { +		cgit_print_age(info->commit->date, -1, NULL); +		html("</td><td>"); +		html_txt(info->author); +		html("</td><td>"); +		cgit_commit_link(info->subject, NULL, NULL, name, NULL); +	} else { +		html("</td><td></td><td>"); +		cgit_object_link(ref->object); +	} +	html("</td></tr>\n"); +	return 0; +} + +static void print_tag_header() +{ +	html("<tr class='nohover'><th class='left'>Tag</th>" +	     "<th class='left'>Age</th>" +	     "<th class='left'>Author</th>" +	     "<th class='left'>Reference</th></tr>\n"); +	header = 1; +} + +static int print_tag(struct refinfo *ref) +{ +	struct tag *tag; +	struct taginfo *info; +	char *url, *name = (char *)ref->refname; + +	if (ref->object->type == OBJ_TAG) { +		tag = (struct tag *)ref->object; +		info = ref->tag; +		if (!tag || !info) +			return 1; +		html("<tr><td>"); +		url = cgit_pageurl(ctx.qry.repo, "tag", +				   fmt("id=%s", name)); +		html_link_open(url, NULL, NULL); +		html_txt(name); +		html_link_close(); +		html("</td><td>"); +		if (info->tagger_date > 0) +			cgit_print_age(info->tagger_date, -1, NULL); +		html("</td><td>"); +		if (info->tagger) +			html(info->tagger); +		html("</td><td>"); +		cgit_object_link(tag->tagged); +		html("</td></tr>\n"); +	} else { +		if (!header) +			print_tag_header(); +		html("<tr><td>"); +		html_txt(name); +		html("</td><td colspan='2'/><td>"); +		cgit_object_link(ref->object); +		html("</td></tr>\n"); +	} +	return 0; +} + +static void print_refs_link(char *path) +{ +	html("<tr class='nohover'><td colspan='4'>"); +	cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path); +	html("</td></tr>"); +} + +void cgit_print_branches(int maxcount) +{ +	struct reflist list; +	int i; +	html("<tr class='nohover'><th class='left'>Branch</th>" +	     "<th class='left'>Idle</th>" +	     "<th class='left'>Author</th>" +	     "<th class='left'>Head commit</th></tr>\n"); + +	list.refs = NULL; +	list.alloc = list.count = 0; +	for_each_branch_ref(cgit_refs_cb, &list); + +	if (maxcount == 0 || maxcount > list.count) +		maxcount = list.count; + +	if (maxcount < list.count) { +		qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); +		qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); +	} + +	for(i=0; i<maxcount; i++) +		print_branch(list.refs[i]); + +	if (maxcount < list.count) +		print_refs_link("heads"); +} + +void cgit_print_tags(int maxcount) +{ +	struct reflist list; +	int i; + +	header = 0; +	list.refs = NULL; +	list.alloc = list.count = 0; +	for_each_tag_ref(cgit_refs_cb, &list); +	if (list.count == 0) +		return; +	qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); +	if (!maxcount) +		maxcount = list.count; +	else if (maxcount > list.count) +		maxcount = list.count; +	print_tag_header(); +	for(i=0; i<maxcount; i++) +		print_tag(list.refs[i]); + +	if (maxcount < list.count) +		print_refs_link("tags"); +}  void cgit_print_refs()  {  	html("<table class='list nowrap'>"); -	if (cgit_query_path && !strncmp(cgit_query_path, "heads", 5)) +	if (ctx.qry.path && !strncmp(ctx.qry.path, "heads", 5))  		cgit_print_branches(0); -	else if (cgit_query_path && !strncmp(cgit_query_path, "tags", 4)) +	else if (ctx.qry.path && !strncmp(ctx.qry.path, "tags", 4))  		cgit_print_tags(0);  	else {  		cgit_print_branches(0); diff --git a/ui-refs.h b/ui-refs.h new file mode 100644 index 0000000..b35c04a --- /dev/null +++ b/ui-refs.h @@ -0,0 +1,8 @@ +#ifndef UI_REFS_H +#define UI_REFS_H + +extern void cgit_print_branches(int maxcount); +extern void cgit_print_tags(int maxcount); +extern void cgit_print_refs(); + +#endif /* UI_REFS_H */ diff --git a/ui-repolist.c b/ui-repolist.c index 3e97ca9..eeeaf3d 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -6,9 +6,11 @@   *   (see COPYING for full license text)   */ -#include "cgit.h"  #include <time.h> +#include "cgit.h" +#include "html.h" +#include "ui-shared.h"  time_t read_agefile(char *path)  { @@ -25,12 +27,12 @@ time_t read_agefile(char *path)  		return 0;  } -static void print_modtime(struct repoinfo *repo) +static void print_modtime(struct cgit_repo *repo)  {  	char *path;  	struct stat s; -	path = fmt("%s/%s", repo->path, cgit_agefile); +	path = fmt("%s/%s", repo->path, ctx.cfg.agefile);  	if (stat(path, &s) == 0) {  		cgit_print_age(read_agefile(path), -1, NULL);  		return; @@ -42,22 +44,24 @@ static void print_modtime(struct repoinfo *repo)  	cgit_print_age(s.st_mtime, -1, NULL);  } -void cgit_print_repolist(struct cacheitem *item) +void cgit_print_repolist()  {  	int i, columns = 4;  	char *last_group = NULL; -	if (cgit_enable_index_links) +	if (ctx.cfg.enable_index_links)  		columns++; -	cgit_print_docstart(cgit_root_title, item); -	cgit_print_pageheader(cgit_root_title, 0); +	ctx.page.title = ctx.cfg.root_title; +	cgit_print_http_headers(&ctx); +	cgit_print_docstart(&ctx); +	cgit_print_pageheader(&ctx);  	html("<table summary='repository list' class='list nowrap'>"); -	if (cgit_index_header) { +	if (ctx.cfg.index_header) {  		htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>",  		      columns); -		html_include(cgit_index_header); +		html_include(ctx.cfg.index_header);  		html("</td></tr>");  	}  	html("<tr class='nohover'>" @@ -65,37 +69,37 @@ void cgit_print_repolist(struct cacheitem *item)  	     "<th class='left'>Description</th>"  	     "<th class='left'>Owner</th>"  	     "<th class='left'>Idle</th>"); -	if (cgit_enable_index_links) +	if (ctx.cfg.enable_index_links)  		html("<th>Links</th>");  	html("</tr>\n");  	for (i=0; i<cgit_repolist.count; i++) { -		cgit_repo = &cgit_repolist.repos[i]; -		if ((last_group == NULL && cgit_repo->group != NULL) || -		    (last_group != NULL && cgit_repo->group == NULL) || -		    (last_group != NULL && cgit_repo->group != NULL && -		     strcmp(cgit_repo->group, last_group))) { +		ctx.repo = &cgit_repolist.repos[i]; +		if ((last_group == NULL && ctx.repo->group != NULL) || +		    (last_group != NULL && ctx.repo->group == NULL) || +		    (last_group != NULL && ctx.repo->group != NULL && +		     strcmp(ctx.repo->group, last_group))) {  			htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>",  			      columns); -			html_txt(cgit_repo->group); +			html_txt(ctx.repo->group);  			html("</td></tr>"); -			last_group = cgit_repo->group; +			last_group = ctx.repo->group;  		}  		htmlf("<tr><td class='%s'>", -		      cgit_repo->group ? "sublevel-repo" : "toplevel-repo"); -		html_link_open(cgit_repourl(cgit_repo->url), NULL, NULL); -		html_txt(cgit_repo->name); +		      ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); +		html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); +		html_txt(ctx.repo->name);  		html_link_close();  		html("</td><td>"); -		html_ntxt(cgit_max_repodesc_len, cgit_repo->desc); +		html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc);  		html("</td><td>"); -		html_txt(cgit_repo->owner); +		html_txt(ctx.repo->owner);  		html("</td><td>"); -		print_modtime(cgit_repo); +		print_modtime(ctx.repo);  		html("</td>"); -		if (cgit_enable_index_links) { +		if (ctx.cfg.enable_index_links) {  			html("<td>"); -			html_link_open(cgit_repourl(cgit_repo->url), +			html_link_open(cgit_repourl(ctx.repo->url),  				       NULL, "button");  			html("summary</a>");  			cgit_log_link("log", NULL, "button", NULL, NULL, NULL, diff --git a/ui-repolist.h b/ui-repolist.h new file mode 100644 index 0000000..c23e5d2 --- /dev/null +++ b/ui-repolist.h @@ -0,0 +1,6 @@ +#ifndef UI_REPOLIST_H +#define UI_REPOLIST_H + +extern void cgit_print_repolist(); + +#endif /* UI_REPOLIST_H */ diff --git a/ui-shared.c b/ui-shared.c index 60aa2e3..aa65988 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -7,6 +7,7 @@   */  #include "cgit.h" +#include "html.h"  const char cgit_doctype[] =  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" @@ -25,14 +26,6 @@ static char *http_date(time_t t)  		   tm->tm_hour, tm->tm_min, tm->tm_sec);  } -static long ttl_seconds(long ttl) -{ -	if (ttl<0) -		return 60 * 60 * 24 * 365; -	else -		return ttl * 60; -} -  void cgit_print_error(char *msg)  {  	html("<div class='error'>"); @@ -42,16 +35,16 @@ void cgit_print_error(char *msg)  char *cgit_rooturl()  { -	if (cgit_virtual_root) -		return fmt("%s/", cgit_virtual_root); +	if (ctx.cfg.virtual_root) +		return fmt("%s/", ctx.cfg.virtual_root);  	else -		return cgit_script_name; +		return ctx.cfg.script_name;  }  char *cgit_repourl(const char *reponame)  { -	if (cgit_virtual_root) { -		return fmt("%s/%s/", cgit_virtual_root, reponame); +	if (ctx.cfg.virtual_root) { +		return fmt("%s/%s/", ctx.cfg.virtual_root, reponame);  	} else {  		return fmt("?r=%s", reponame);  	} @@ -63,8 +56,8 @@ char *cgit_fileurl(const char *reponame, const char *pagename,  	char *tmp;  	char *delim; -	if (cgit_virtual_root) { -		tmp = fmt("%s/%s/%s/%s", cgit_virtual_root, reponame, +	if (ctx.cfg.virtual_root) { +		tmp = fmt("%s/%s/%s/%s", ctx.cfg.virtual_root, reponame,  			  pagename, (filename ? filename:""));  		delim = "?";  	} else { @@ -110,14 +103,14 @@ const char *cgit_repobasename(const char *reponame)  char *cgit_currurl()  { -	if (!cgit_virtual_root) -		return cgit_script_name; -	else if (cgit_query_page) -		return fmt("%s/%s/%s/", cgit_virtual_root, cgit_query_repo, cgit_query_page); -	else if (cgit_query_repo) -		return fmt("%s/%s/", cgit_virtual_root, cgit_query_repo); +	if (!ctx.cfg.virtual_root) +		return ctx.cfg.script_name; +	else if (ctx.qry.page) +		return fmt("%s/%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo, ctx.qry.page); +	else if (ctx.qry.repo) +		return fmt("%s/%s/", ctx.cfg.virtual_root, ctx.qry.repo);  	else -		return fmt("%s/", cgit_virtual_root); +		return fmt("%s/", ctx.cfg.virtual_root);  }  static char *repolink(char *title, char *class, char *page, char *head, @@ -137,12 +130,12 @@ static char *repolink(char *title, char *class, char *page, char *head,  		html("'");  	}  	html(" href='"); -	if (cgit_virtual_root) { -		html_attr(cgit_virtual_root); -		if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/') +	if (ctx.cfg.virtual_root) { +		html_attr(ctx.cfg.virtual_root); +		if (ctx.cfg.virtual_root[strlen(ctx.cfg.virtual_root) - 1] != '/')  			html("/"); -		html_attr(cgit_repo->url); -		if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') +		html_attr(ctx.repo->url); +		if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')  			html("/");  		if (page) {  			html(page); @@ -151,10 +144,10 @@ static char *repolink(char *title, char *class, char *page, char *head,  				html_attr(path);  		}  	} else { -		html(cgit_script_name); +		html(ctx.cfg.script_name);  		html("?url="); -		html_attr(cgit_repo->url); -		if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') +		html_attr(ctx.repo->url); +		if (ctx.repo->url[strlen(ctx.repo->url) - 1] != '/')  			html("/");  		if (page) {  			html(page); @@ -164,7 +157,7 @@ static char *repolink(char *title, char *class, char *page, char *head,  		}  		delim = "&";  	} -	if (head && strcmp(head, cgit_repo->defbranch)) { +	if (head && strcmp(head, ctx.repo->defbranch)) {  		html(delim);  		html("h=");  		html_attr(head); @@ -179,7 +172,7 @@ static void reporevlink(char *page, char *name, char *title, char *class,  	char *delim;  	delim = repolink(title, class, page, head, path); -	if (rev && strcmp(rev, cgit_query_head)) { +	if (rev && strcmp(rev, ctx.qry.head)) {  		html(delim);  		html("id=");  		html_attr(rev); @@ -201,7 +194,7 @@ void cgit_log_link(char *name, char *title, char *class, char *head,  	char *delim;  	delim = repolink(title, class, "log", head, path); -	if (rev && strcmp(rev, cgit_query_head)) { +	if (rev && strcmp(rev, ctx.qry.head)) {  		html(delim);  		html("id=");  		html_attr(rev); @@ -229,11 +222,11 @@ void cgit_log_link(char *name, char *title, char *class, char *head,  void cgit_commit_link(char *name, char *title, char *class, char *head,  		      char *rev)  { -	if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) { -		name[cgit_max_msg_len] = '\0'; -		name[cgit_max_msg_len - 1] = '.'; -		name[cgit_max_msg_len - 2] = '.'; -		name[cgit_max_msg_len - 3] = '.'; +	if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { +		name[ctx.cfg.max_msg_len] = '\0'; +		name[ctx.cfg.max_msg_len - 1] = '.'; +		name[ctx.cfg.max_msg_len - 2] = '.'; +		name[ctx.cfg.max_msg_len - 3] = '.';  	}  	reporevlink("commit", name, title, class, head, rev, NULL);  } @@ -256,7 +249,7 @@ void cgit_diff_link(char *name, char *title, char *class, char *head,  	char *delim;  	delim = repolink(title, class, "diff", head, path); -	if (new_rev && strcmp(new_rev, cgit_query_head)) { +	if (new_rev && strcmp(new_rev, ctx.qry.head)) {  		html(delim);  		html("id=");  		html_attr(new_rev); @@ -284,7 +277,7 @@ void cgit_object_link(struct object *obj)  	if (obj->type == OBJ_COMMIT) {                  cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, -				 cgit_query_head, sha1_to_hex(obj->sha1)); +				 ctx.qry.head, sha1_to_hex(obj->sha1));  		return;  	} else if (obj->type == OBJ_TREE) {  		page = "tree"; @@ -297,7 +290,7 @@ void cgit_object_link(struct object *obj)  		arg = "id";  	} -	url = cgit_pageurl(cgit_query_repo, page, +	url = cgit_pageurl(ctx.qry.repo, page,  			   fmt("%s=%s", arg, sha1_to_hex(obj->sha1)));  	html_link_open(url, NULL, NULL);  	htmlf("%s %s", typename(obj->type), @@ -360,24 +353,34 @@ void cgit_print_age(time_t t, time_t max_relative, char *format)  	      secs * 1.0 / TM_YEAR);  } -void cgit_print_docstart(char *title, struct cacheitem *item) +void cgit_print_http_headers(struct cgit_context *ctx)  { -	html("Content-Type: text/html; charset=" PAGE_ENCODING "\n"); -	htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); -	htmlf("Expires: %s\n", http_date(item->st.st_mtime + -					 ttl_seconds(item->ttl))); +	if (ctx->page.mimetype && ctx->page.charset) +		htmlf("Content-Type: %s; charset=%s\n", ctx->page.mimetype, +		      ctx->page.charset); +	else if (ctx->page.mimetype) +		htmlf("Content-Type: %s\n", ctx->page.mimetype); +	if (ctx->page.filename) +		htmlf("Content-Disposition: inline; filename=\"%s\"\n", +		      ctx->page.filename); +	htmlf("Last-Modified: %s\n", http_date(ctx->page.modified)); +	htmlf("Expires: %s\n", http_date(ctx->page.expires));  	html("\n"); +} + +void cgit_print_docstart(struct cgit_context *ctx) +{  	html(cgit_doctype);  	html("<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n");  	html("<head>\n");  	html("<title>"); -	html_txt(title); +	html_txt(ctx->page.title);  	html("</title>\n");  	htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); -	if (cgit_robots && *cgit_robots) -		htmlf("<meta name='robots' content='%s'/>\n", cgit_robots); +	if (ctx->cfg.robots && *ctx->cfg.robots) +		htmlf("<meta name='robots' content='%s'/>\n", ctx->cfg.robots);  	html("<link rel='stylesheet' type='text/css' href='"); -	html_attr(cgit_css); +	html_attr(ctx->cfg.css);  	html("'/>\n");  	html("</head>\n");  	html("<body>\n"); @@ -392,7 +395,7 @@ int print_branch_option(const char *refname, const unsigned char *sha1,  			int flags, void *cb_data)  {  	char *name = (char *)refname; -	html_option(name, name, cgit_query_head); +	html_option(name, name, ctx.qry.head);  	return 0;  } @@ -426,7 +429,7 @@ int print_archive_ref(const char *refname, const unsigned char *sha1,  		html("<h1>download</h1>\n");  		*header = 1;  	} -	url = cgit_pageurl(cgit_query_repo, "blob", +	url = cgit_pageurl(ctx.qry.repo, "blob",  			   fmt("id=%s&path=%s", sha1_to_hex(fileid),  			       buf));  	html_link_open(url, NULL, "menu"); @@ -439,30 +442,30 @@ void add_hidden_formfields(int incl_head, int incl_search, char *page)  {  	char *url; -	if (!cgit_virtual_root) { -		url = fmt("%s/%s", cgit_query_repo, page); -		if (cgit_query_path) -			url = fmt("%s/%s", url, cgit_query_path); +	if (!ctx.cfg.virtual_root) { +		url = fmt("%s/%s", ctx.qry.repo, page); +		if (ctx.qry.path) +			url = fmt("%s/%s", url, ctx.qry.path);  		html_hidden("url", url);  	} -	if (incl_head && strcmp(cgit_query_head, cgit_repo->defbranch)) -		html_hidden("h", cgit_query_head); +	if (incl_head && strcmp(ctx.qry.head, ctx.repo->defbranch)) +		html_hidden("h", ctx.qry.head); -	if (cgit_query_sha1) -		html_hidden("id", cgit_query_sha1); -	if (cgit_query_sha2) -		html_hidden("id2", cgit_query_sha2); +	if (ctx.qry.sha1) +		html_hidden("id", ctx.qry.sha1); +	if (ctx.qry.sha2) +		html_hidden("id2", ctx.qry.sha2);  	if (incl_search) { -		if (cgit_query_grep) -			html_hidden("qt", cgit_query_grep); -		if (cgit_query_search) -			html_hidden("q", cgit_query_search); +		if (ctx.qry.grep) +			html_hidden("qt", ctx.qry.grep); +		if (ctx.qry.search) +			html_hidden("q", ctx.qry.search);  	}  } -void cgit_print_pageheader(char *title, int show_search) +void cgit_print_pageheader(struct cgit_context *ctx)  {  	static const char *default_info = "This is cgit, a fast webinterface for git repositories";  	int header = 0; @@ -474,40 +477,40 @@ void cgit_print_pageheader(char *title, int show_search)  	html("<tr><td class='sidebar'>\n<a href='");  	html_attr(cgit_rooturl());  	htmlf("'><img src='%s' alt='cgit'/></a>\n", -	      cgit_logo); +	      ctx->cfg.logo);  	html("</td></tr>\n<tr><td class='sidebar'>\n"); -	if (cgit_query_repo) { +	if (ctx->repo) {  		html("<h1 class='first'>"); -		html_txt(strrpart(cgit_repo->name, 20)); +		html_txt(strrpart(ctx->repo->name, 20));  		html("</h1>\n"); -		html_txt(cgit_repo->desc); -		if (cgit_repo->owner) { +		html_txt(ctx->repo->desc); +		if (ctx->repo->owner) {  			html("<h1>owner</h1>\n"); -			html_txt(cgit_repo->owner); +			html_txt(ctx->repo->owner);  		}  		html("<h1>navigate</h1>\n"); -		reporevlink(NULL, "summary", NULL, "menu", cgit_query_head, +		reporevlink(NULL, "summary", NULL, "menu", ctx->qry.head,  			    NULL, NULL); -		cgit_log_link("log", NULL, "menu", cgit_query_head, NULL, NULL, +		cgit_log_link("log", NULL, "menu", ctx->qry.head, NULL, NULL,  			      0, NULL, NULL); -		cgit_tree_link("tree", NULL, "menu", cgit_query_head, -			       cgit_query_sha1, NULL); -		cgit_commit_link("commit", NULL, "menu", cgit_query_head, -			      cgit_query_sha1); -		cgit_diff_link("diff", NULL, "menu", cgit_query_head, -			       cgit_query_sha1, cgit_query_sha2, NULL); -		cgit_patch_link("patch", NULL, "menu", cgit_query_head, -				cgit_query_sha1); +		cgit_tree_link("tree", NULL, "menu", ctx->qry.head, +			       ctx->qry.sha1, NULL); +		cgit_commit_link("commit", NULL, "menu", ctx->qry.head, +			      ctx->qry.sha1); +		cgit_diff_link("diff", NULL, "menu", ctx->qry.head, +			       ctx->qry.sha1, ctx->qry.sha2, NULL); +		cgit_patch_link("patch", NULL, "menu", ctx->qry.head, +				ctx->qry.sha1);  		for_each_ref(print_archive_ref, &header); -		if (cgit_repo->clone_url || cgit_clone_prefix) { +		if (ctx->repo->clone_url || ctx->cfg.clone_prefix) {  			html("<h1>clone</h1>\n"); -			if (cgit_repo->clone_url) -				url = cgit_repo->clone_url; +			if (ctx->repo->clone_url) +				url = ctx->repo->clone_url;  			else -				url = fmt("%s%s", cgit_clone_prefix, -					  cgit_repo->url); +				url = fmt("%s%s", ctx->cfg.clone_prefix, +					  ctx->repo->url);  			html("<a class='menu' href='");  			html_attr(url);  			html("' title='"); @@ -519,10 +522,10 @@ void cgit_print_pageheader(char *title, int show_search)  		html("<h1>branch</h1>\n");  		html("<form method='get' action=''>\n"); -		add_hidden_formfields(0, 1, cgit_query_page); +		add_hidden_formfields(0, 1, ctx->qry.page);  //		html("<table summary='branch selector' class='grid'><tr><td id='branch-dropdown-cell'>");  		html("<select name='h' onchange='this.form.submit();'>\n"); -		for_each_branch_ref(print_branch_option, cgit_query_head); +		for_each_branch_ref(print_branch_option, ctx->qry.head);  		html("</select>\n");  //		html("</td><td>");  		html("<noscript><input type='submit' id='switch-btn' value='switch'/></noscript>\n"); @@ -531,22 +534,22 @@ void cgit_print_pageheader(char *title, int show_search)  		html("<h1>search</h1>\n");  		html("<form method='get' action='"); -		if (cgit_virtual_root) -			html_attr(cgit_fileurl(cgit_query_repo, "log", -					       cgit_query_path, NULL)); +		if (ctx->cfg.virtual_root) +			html_attr(cgit_fileurl(ctx->qry.repo, "log", +					       ctx->qry.path, NULL));  		html("'>\n");  		add_hidden_formfields(1, 0, "log");  		html("<select name='qt'>\n"); -		html_option("grep", "log msg", cgit_query_grep); -		html_option("author", "author", cgit_query_grep); -		html_option("committer", "committer", cgit_query_grep); +		html_option("grep", "log msg", ctx->qry.grep); +		html_option("author", "author", ctx->qry.grep); +		html_option("committer", "committer", ctx->qry.grep);  		html("</select>\n");  		html("<input class='txt' type='text' name='q' value='"); -		html_attr(cgit_query_search); +		html_attr(ctx->qry.search);  		html("'/>\n");  		html("</form>\n");  	} else { -		if (!cgit_index_info || html_include(cgit_index_info)) +		if (!ctx->cfg.index_info || html_include(ctx->cfg.index_info))  			html(default_info);  	} @@ -555,16 +558,34 @@ void cgit_print_pageheader(char *title, int show_search)  	html("<td id='content'>\n");  } - -void cgit_print_snapshot_start(const char *mimetype, const char *filename, -			       struct cacheitem *item) +void cgit_print_filemode(unsigned short mode)  { -	htmlf("Content-Type: %s\n", mimetype); -	htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); -	htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); -	htmlf("Expires: %s\n", http_date(item->st.st_mtime + -					 ttl_seconds(item->ttl))); -	html("\n"); +	if (S_ISDIR(mode)) +		html("d"); +	else if (S_ISLNK(mode)) +		html("l"); +	else if (S_ISGITLINK(mode)) +		html("m"); +	else +		html("-"); +	html_fileperm(mode >> 6); +	html_fileperm(mode >> 3); +	html_fileperm(mode);  } -/* vim:set sw=8: */ +void cgit_print_snapshot_links(const char *repo, const char *head, +			       const char *hex, int snapshots) +{ +	const struct cgit_snapshot_format* f; +    	char *filename; + +	for (f = cgit_snapshot_formats; f->suffix; f++) { +		if (!(snapshots & f->bit)) +			continue; +		filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, +			       f->suffix); +		cgit_snapshot_link(filename, NULL, NULL, (char *)head, +				   (char *)hex, filename); +		html("<br/>"); +	} +} diff --git a/ui-shared.h b/ui-shared.h new file mode 100644 index 0000000..94de884 --- /dev/null +++ b/ui-shared.h @@ -0,0 +1,36 @@ +#ifndef UI_SHARED_H +#define UI_SHARED_H + +extern char *cgit_repourl(const char *reponame); +extern char *cgit_fileurl(const char *reponame, const char *pagename, +			  const char *filename, const char *query); +extern char *cgit_pageurl(const char *reponame, const char *pagename, +			  const char *query); + +extern void cgit_tree_link(char *name, char *title, char *class, char *head, +			   char *rev, char *path); +extern void cgit_log_link(char *name, char *title, char *class, char *head, +			  char *rev, char *path, int ofs, char *grep, +			  char *pattern); +extern void cgit_commit_link(char *name, char *title, char *class, char *head, +			     char *rev); +extern void cgit_refs_link(char *name, char *title, char *class, char *head, +			   char *rev, char *path); +extern void cgit_snapshot_link(char *name, char *title, char *class, +			       char *head, char *rev, char *archivename); +extern void cgit_diff_link(char *name, char *title, char *class, char *head, +			   char *new_rev, char *old_rev, char *path); +extern void cgit_object_link(struct object *obj); + +extern void cgit_print_error(char *msg); +extern void cgit_print_date(time_t secs, char *format); +extern void cgit_print_age(time_t t, time_t max_relative, char *format); +extern void cgit_print_http_headers(struct cgit_context *ctx); +extern void cgit_print_docstart(struct cgit_context *ctx); +extern void cgit_print_docend(); +extern void cgit_print_pageheader(struct cgit_context *ctx); +extern void cgit_print_filemode(unsigned short mode); +extern void cgit_print_snapshot_links(const char *repo, const char *head, +				      const char *hex, int snapshots); + +#endif /* UI_SHARED_H */ diff --git a/ui-snapshot.c b/ui-snapshot.c index dfedd8f..966a140 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c @@ -7,6 +7,8 @@   */  #include "cgit.h" +#include "html.h" +#include "ui-shared.h"  static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)  { @@ -54,104 +56,59 @@ static int write_tar_bzip2_archive(struct archiver_args *args)  	return write_compressed_tar_archive(args,"bzip2");  } -static const struct snapshot_archive_t { -    	const char *suffix; -	const char *mimetype; -	write_archive_fn_t write_func; -	int bit; -}	snapshot_archives[] = { +const struct cgit_snapshot_format cgit_snapshot_formats[] = {  	{ ".zip", "application/x-zip", write_zip_archive, 0x1 },  	{ ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },  	{ ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 }, -	{ ".tar", "application/x-tar", write_tar_archive, 0x8 } +	{ ".tar", "application/x-tar", write_tar_archive, 0x8 }, +	{}  }; -#define snapshot_archives_len (sizeof(snapshot_archives) / sizeof(*snapshot_archives)) - -void cgit_print_snapshot(struct cacheitem *item, const char *head, +static int make_snapshot(const struct cgit_snapshot_format *format,  			 const char *hex, const char *prefix, -			 const char *filename, int snapshots) +			 const char *filename)  { -	const struct snapshot_archive_t* sat;  	struct archiver_args args;  	struct commit *commit;  	unsigned char sha1[20]; -	int f, sl, fnl = strlen(filename); -	for(f=0; f<snapshot_archives_len; f++) { -		sat = &snapshot_archives[f]; -		if(!(snapshots & sat->bit)) -			continue; -		sl = strlen(sat->suffix); -		if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix)) -			continue; -		if (!hex) -			hex = head; -		if(get_sha1(hex, sha1)) { -			cgit_print_error(fmt("Bad object id: %s", hex)); -			return; -		} -		commit = lookup_commit_reference(sha1); -		if(!commit) { -			cgit_print_error(fmt("Not a commit reference: %s", hex)); -			return;; -		} -		memset(&args,0,sizeof(args)); -		args.base = fmt("%s/", prefix); -		args.tree = commit->tree; -		args.time = commit->date; -		cgit_print_snapshot_start(sat->mimetype, filename, item); -		(*sat->write_func)(&args); -		return; +	if(get_sha1(hex, sha1)) { +		cgit_print_error(fmt("Bad object id: %s", hex)); +		return 1;  	} -	cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); -} - -void cgit_print_snapshot_links(const char *repo, const char *head, -			       const char *hex, int snapshots) -{ -	const struct snapshot_archive_t* sat; -    	char *filename; -	int f; - -	for(f=0; f<snapshot_archives_len; f++) { -		sat = &snapshot_archives[f]; -		if(!(snapshots & sat->bit)) -			continue; -		filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, -			       sat->suffix); -		cgit_snapshot_link(filename, NULL, NULL, (char *)head, -				   (char *)hex, filename); -		html("<br/>"); +	commit = lookup_commit_reference(sha1); +	if(!commit) { +		cgit_print_error(fmt("Not a commit reference: %s", hex)); +		return 1;  	} +	memset(&args, 0, sizeof(args)); +	args.base = fmt("%s/", prefix); +	args.tree = commit->tree; +	args.time = commit->date; +	ctx.page.mimetype = xstrdup(format->mimetype); +	ctx.page.filename = xstrdup(filename); +	cgit_print_http_headers(&ctx); +	format->write_func(&args); +	return 0;  } -int cgit_parse_snapshots_mask(const char *str) +void cgit_print_snapshot(const char *head, const char *hex, const char *prefix, +			 const char *filename, int snapshots)  { -	const struct snapshot_archive_t* sat; -	static const char *delim = " \t,:/|;"; -	int f, tl, sl, rv = 0; +	const struct cgit_snapshot_format* f; +	int sl, fnl; -	/* favor legacy setting */ -	if(atoi(str)) -		return 1; -	for(;;) { -		str += strspn(str,delim); -		tl = strcspn(str,delim); -		if(!tl) -			break; -		for(f=0; f<snapshot_archives_len; f++) { -			sat = &snapshot_archives[f]; -			sl = strlen(sat->suffix); -			if((tl == sl && !strncmp(sat->suffix, str, tl)) || -			   (tl == sl-1 && !strncmp(sat->suffix+1, str, tl-1))) { -				rv |= sat->bit; -				break; -			} -		} -		str += tl; +	fnl = strlen(filename); +	if (!hex) +		hex = head; +	for (f = cgit_snapshot_formats; f->suffix; f++) { +		if (!(snapshots & f->bit)) +			continue; +		sl = strlen(f->suffix); +		if(fnl < sl || strcmp(&filename[fnl-sl], f->suffix)) +			continue; +		make_snapshot(f, hex, prefix, filename); +		return;  	} -	return rv; +	cgit_print_error(fmt("Unsupported snapshot format: %s", filename));  } - -/* vim:set sw=8: */ diff --git a/ui-snapshot.h b/ui-snapshot.h new file mode 100644 index 0000000..6e03761 --- /dev/null +++ b/ui-snapshot.h @@ -0,0 +1,8 @@ +#ifndef UI_SNAPSHOT_H +#define UI_SNAPSHOT_H + +extern void cgit_print_snapshot(const char *head, const char *hex, +				const char *prefix, const char *filename, +				int snapshot); + +#endif /* UI_SNAPSHOT_H */ diff --git a/ui-summary.c b/ui-summary.c index b96414e..0b66b52 100644 --- a/ui-summary.c +++ b/ui-summary.c @@ -7,194 +7,25 @@   */  #include "cgit.h" - -static int header; - -static int cmp_age(int age1, int age2) -{ -	if (age1 != 0 && age2 != 0) -		return age2 - age1; - -	if (age1 == 0 && age2 == 0) -		return 0; - -	if (age1 == 0) -		return +1; - -	return -1; -} - -static int cmp_ref_name(const void *a, const void *b) -{ -	struct refinfo *r1 = *(struct refinfo **)a; -	struct refinfo *r2 = *(struct refinfo **)b; - -	return strcmp(r1->refname, r2->refname); -} - -static int cmp_branch_age(const void *a, const void *b) -{ -	struct refinfo *r1 = *(struct refinfo **)a; -	struct refinfo *r2 = *(struct refinfo **)b; - -	return cmp_age(r1->commit->committer_date, r2->commit->committer_date); -} - -static int cmp_tag_age(const void *a, const void *b) -{ -	struct refinfo *r1 = *(struct refinfo **)a; -	struct refinfo *r2 = *(struct refinfo **)b; - -	return cmp_age(r1->tag->tagger_date, r2->tag->tagger_date); -} - -static int print_branch(struct refinfo *ref) -{ -	struct commitinfo *info = ref->commit; -	char *name = (char *)ref->refname; - -	if (!info) -		return 1; -	html("<tr><td>"); -	cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL); -	html("</td><td>"); - -	if (ref->object->type == OBJ_COMMIT) { -		cgit_print_age(info->commit->date, -1, NULL); -		html("</td><td>"); -		html_txt(info->author); -		html("</td><td>"); -		cgit_commit_link(info->subject, NULL, NULL, name, NULL); -	} else { -		html("</td><td></td><td>"); -		cgit_object_link(ref->object); -	} -	html("</td></tr>\n"); -	return 0; -} - -static void print_tag_header() -{ -	html("<tr class='nohover'><th class='left'>Tag</th>" -	     "<th class='left'>Age</th>" -	     "<th class='left'>Author</th>" -	     "<th class='left'>Reference</th></tr>\n"); -	header = 1; -} - -static int print_tag(struct refinfo *ref) -{ -	struct tag *tag; -	struct taginfo *info; -	char *url, *name = (char *)ref->refname; - -	if (ref->object->type == OBJ_TAG) { -		tag = (struct tag *)ref->object; -		info = ref->tag; -		if (!tag || !info) -			return 1; -		html("<tr><td>"); -		url = cgit_pageurl(cgit_query_repo, "tag", -				   fmt("id=%s", name)); -		html_link_open(url, NULL, NULL); -		html_txt(name); -		html_link_close(); -		html("</td><td>"); -		if (info->tagger_date > 0) -			cgit_print_age(info->tagger_date, -1, NULL); -		html("</td><td>"); -		if (info->tagger) -			html(info->tagger); -		html("</td><td>"); -		cgit_object_link(tag->tagged); -		html("</td></tr>\n"); -	} else { -		if (!header) -			print_tag_header(); -		html("<tr><td>"); -		html_txt(name); -		html("</td><td colspan='2'/><td>"); -		cgit_object_link(ref->object); -		html("</td></tr>\n"); -	} -	return 0; -} - -static void print_refs_link(char *path) -{ -	html("<tr class='nohover'><td colspan='4'>"); -	cgit_refs_link("[...]", NULL, NULL, cgit_query_head, NULL, path); -	html("</td></tr>"); -} - -void cgit_print_branches(int maxcount) -{ -	struct reflist list; -	int i; - -	html("<tr class='nohover'><th class='left'>Branch</th>" -	     "<th class='left'>Idle</th>" -	     "<th class='left'>Author</th>" -	     "<th class='left'>Head commit</th></tr>\n"); - -	list.refs = NULL; -	list.alloc = list.count = 0; -	for_each_branch_ref(cgit_refs_cb, &list); - -	if (maxcount == 0 || maxcount > list.count) -		maxcount = list.count; - -	if (maxcount < list.count) { -		qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); -		qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); -	} - -	for(i=0; i<maxcount; i++) -		print_branch(list.refs[i]); - -	if (maxcount < list.count) -		print_refs_link("heads"); -} - -void cgit_print_tags(int maxcount) -{ -	struct reflist list; -	int i; - -	header = 0; -	list.refs = NULL; -	list.alloc = list.count = 0; -	for_each_tag_ref(cgit_refs_cb, &list); -	if (list.count == 0) -		return; -	qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); -	if (!maxcount) -		maxcount = list.count; -	else if (maxcount > list.count) -		maxcount = list.count; -	print_tag_header(); -	for(i=0; i<maxcount; i++) -		print_tag(list.refs[i]); - -	if (maxcount < list.count) -		print_refs_link("tags"); -} +#include "html.h" +#include "ui-log.h" +#include "ui-refs.h"  void cgit_print_summary()  { -	if (cgit_repo->readme) { +	if (ctx.repo->readme) {  		html("<div id='summary'>"); -		html_include(cgit_repo->readme); +		html_include(ctx.repo->readme);  		html("</div>");  	} -	if (cgit_summary_log > 0) -		cgit_print_log(cgit_query_head, 0, cgit_summary_log, NULL, +	if (ctx.cfg.summary_log > 0) +		cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL,  			       NULL, NULL, 0);  	html("<table summary='repository info' class='list nowrap'>"); -	if (cgit_summary_log > 0) +	if (ctx.cfg.summary_log > 0)  		html("<tr class='nohover'><td colspan='4'> </td></tr>"); -	cgit_print_branches(cgit_summary_branches); +	cgit_print_branches(ctx.cfg.summary_branches);  	html("<tr class='nohover'><td colspan='4'> </td></tr>"); -	cgit_print_tags(cgit_summary_tags); +	cgit_print_tags(ctx.cfg.summary_tags);  	html("</table>");  } diff --git a/ui-summary.h b/ui-summary.h new file mode 100644 index 0000000..37aedd2 --- /dev/null +++ b/ui-summary.h @@ -0,0 +1,6 @@ +#ifndef UI_SUMMARY_H +#define UI_SUMMARY_H + +extern void cgit_print_summary(); + +#endif /* UI_SUMMARY_H */ @@ -7,7 +7,8 @@   */  #include "cgit.h" - +#include "html.h" +#include "ui-shared.h"  static void print_tag_content(char *buf)  { diff --git a/ui-tag.h b/ui-tag.h new file mode 100644 index 0000000..d295cdc --- /dev/null +++ b/ui-tag.h @@ -0,0 +1,6 @@ +#ifndef UI_TAG_H +#define UI_TAG_H + +extern void cgit_print_tag(char *revname); + +#endif /* UI_TAG_H */ @@ -7,6 +7,8 @@   */  #include "cgit.h" +#include "html.h" +#include "ui-shared.h"  char *curr_rev;  char *match_path; @@ -34,7 +36,7 @@ static void print_object(const unsigned char *sha1, char *path)  	}  	html(" blob: <a href='"); -	html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1)))); +	html_attr(cgit_pageurl(ctx.qry.repo, "blob", fmt("id=%s", sha1_to_hex(sha1))));  	htmlf("'>%s</a>",sha1_to_hex(sha1));  	html("<table summary='blob content' class='blob'>\n"); @@ -67,8 +69,8 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,  	unsigned long size = 0;  	name = xstrdup(pathname); -	fullpath = fmt("%s%s%s", cgit_query_path ? cgit_query_path : "", -		       cgit_query_path ? "/" : "", name); +	fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", +		       ctx.qry.path ? "/" : "", name);  	type = sha1_object_info(sha1, &size);  	if (type == OBJ_BAD && !S_ISGITLINK(mode)) { @@ -79,27 +81,27 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen,  	}  	html("<tr><td class='ls-mode'>"); -	html_filemode(mode); +	cgit_print_filemode(mode);  	html("</td><td>");  	if (S_ISGITLINK(mode)) {  		htmlf("<a class='ls-mod' href='"); -		html_attr(fmt(cgit_repo->module_link, +		html_attr(fmt(ctx.repo->module_link,  			      name,  			      sha1_to_hex(sha1)));  		html("'>");  		html_txt(name);  		html("</a>");  	} else if (S_ISDIR(mode)) { -		cgit_tree_link(name, NULL, "ls-dir", cgit_query_head, +		cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head,  			       curr_rev, fullpath);  	} else { -		cgit_tree_link(name, NULL, "ls-blob", cgit_query_head, +		cgit_tree_link(name, NULL, "ls-blob", ctx.qry.head,  			       curr_rev, fullpath);  	}  	htmlf("</td><td class='ls-size'>%li</td>", size);  	html("<td>"); -	cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev, +	cgit_log_link("log", NULL, "button", ctx.qry.head, curr_rev,  		      fullpath, 0, NULL, NULL);  	html("</td></tr>\n");  	free(name); @@ -153,10 +155,10 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,  	if (state == 0) {  		memcpy(buffer, base, baselen);  		strcpy(buffer+baselen, pathname); -		url = cgit_pageurl(cgit_query_repo, "tree", +		url = cgit_pageurl(ctx.qry.repo, "tree",  				   fmt("h=%s&path=%s", curr_rev, buffer));  		html("/"); -		cgit_tree_link(xstrdup(pathname), NULL, NULL, cgit_query_head, +		cgit_tree_link(xstrdup(pathname), NULL, NULL, ctx.qry.head,  			       curr_rev, buffer);  		if (strcmp(match_path, buffer)) @@ -188,7 +190,7 @@ void cgit_print_tree(const char *rev, char *path)  	const char *paths[] = {path, NULL};  	if (!rev) -		rev = cgit_query_head; +		rev = ctx.qry.head;  	curr_rev = xstrdup(rev);  	if (get_sha1(rev, sha1)) { @@ -202,7 +204,7 @@ void cgit_print_tree(const char *rev, char *path)  	}  	html("path: <a href='"); -	html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev))); +	html_attr(cgit_pageurl(ctx.qry.repo, "tree", fmt("h=%s", rev)));  	html("'>root</a>");  	if (path == NULL) { diff --git a/ui-tree.h b/ui-tree.h new file mode 100644 index 0000000..bbd34e3 --- /dev/null +++ b/ui-tree.h @@ -0,0 +1,6 @@ +#ifndef UI_TREE_H +#define UI_TREE_H + +extern void cgit_print_tree(const char *rev, char *path); + +#endif /* UI_TREE_H */ | 
