summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c6
-rw-r--r--cgit.h1
-rw-r--r--cmd.c42
-rw-r--r--cmd.h3
4 files changed, 30 insertions, 22 deletions
diff --git a/cgit.c b/cgit.c
index 9305d0a..2c3ad73 100644
--- a/cgit.c
+++ b/cgit.c
@@ -235,384 +235,390 @@ static void querystring_cb(const char *name, const char *value)
235 ctx.qry.sha2 = xstrdup(value); 235 ctx.qry.sha2 = xstrdup(value);
236 ctx.qry.has_sha1 = 1; 236 ctx.qry.has_sha1 = 1;
237 } else if (!strcmp(name, "ofs")) { 237 } else if (!strcmp(name, "ofs")) {
238 ctx.qry.ofs = atoi(value); 238 ctx.qry.ofs = atoi(value);
239 } else if (!strcmp(name, "path")) { 239 } else if (!strcmp(name, "path")) {
240 ctx.qry.path = trim_end(value, '/'); 240 ctx.qry.path = trim_end(value, '/');
241 } else if (!strcmp(name, "name")) { 241 } else if (!strcmp(name, "name")) {
242 ctx.qry.name = xstrdup(value); 242 ctx.qry.name = xstrdup(value);
243 } else if (!strcmp(name, "mimetype")) { 243 } else if (!strcmp(name, "mimetype")) {
244 ctx.qry.mimetype = xstrdup(value); 244 ctx.qry.mimetype = xstrdup(value);
245 } else if (!strcmp(name, "s")){ 245 } else if (!strcmp(name, "s")){
246 ctx.qry.sort = xstrdup(value); 246 ctx.qry.sort = xstrdup(value);
247 } else if (!strcmp(name, "showmsg")) { 247 } else if (!strcmp(name, "showmsg")) {
248 ctx.qry.showmsg = atoi(value); 248 ctx.qry.showmsg = atoi(value);
249 } else if (!strcmp(name, "period")) { 249 } else if (!strcmp(name, "period")) {
250 ctx.qry.period = xstrdup(value); 250 ctx.qry.period = xstrdup(value);
251 } else if (!strcmp(name, "ss")) { 251 } else if (!strcmp(name, "ss")) {
252 ctx.qry.ssdiff = atoi(value); 252 ctx.qry.ssdiff = atoi(value);
253 } 253 }
254} 254}
255 255
256char *xstrdupn(const char *str) 256char *xstrdupn(const char *str)
257{ 257{
258 return (str ? xstrdup(str) : NULL); 258 return (str ? xstrdup(str) : NULL);
259} 259}
260 260
261static void prepare_context(struct cgit_context *ctx) 261static void prepare_context(struct cgit_context *ctx)
262{ 262{
263 memset(ctx, 0, sizeof(*ctx)); 263 memset(ctx, 0, sizeof(*ctx));
264 ctx->cfg.agefile = "info/web/last-modified"; 264 ctx->cfg.agefile = "info/web/last-modified";
265 ctx->cfg.nocache = 0; 265 ctx->cfg.nocache = 0;
266 ctx->cfg.cache_size = 0; 266 ctx->cfg.cache_size = 0;
267 ctx->cfg.cache_dynamic_ttl = 5; 267 ctx->cfg.cache_dynamic_ttl = 5;
268 ctx->cfg.cache_max_create_time = 5; 268 ctx->cfg.cache_max_create_time = 5;
269 ctx->cfg.cache_repo_ttl = 5; 269 ctx->cfg.cache_repo_ttl = 5;
270 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 270 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
271 ctx->cfg.cache_root_ttl = 5; 271 ctx->cfg.cache_root_ttl = 5;
272 ctx->cfg.cache_scanrc_ttl = 15; 272 ctx->cfg.cache_scanrc_ttl = 15;
273 ctx->cfg.cache_static_ttl = -1; 273 ctx->cfg.cache_static_ttl = -1;
274 ctx->cfg.css = "/cgit.css"; 274 ctx->cfg.css = "/cgit.css";
275 ctx->cfg.logo = "/cgit.png"; 275 ctx->cfg.logo = "/cgit.png";
276 ctx->cfg.local_time = 0; 276 ctx->cfg.local_time = 0;
277 ctx->cfg.enable_tree_linenumbers = 1; 277 ctx->cfg.enable_tree_linenumbers = 1;
278 ctx->cfg.max_repo_count = 50; 278 ctx->cfg.max_repo_count = 50;
279 ctx->cfg.max_commit_count = 50; 279 ctx->cfg.max_commit_count = 50;
280 ctx->cfg.max_lock_attempts = 5; 280 ctx->cfg.max_lock_attempts = 5;
281 ctx->cfg.max_msg_len = 80; 281 ctx->cfg.max_msg_len = 80;
282 ctx->cfg.max_repodesc_len = 80; 282 ctx->cfg.max_repodesc_len = 80;
283 ctx->cfg.max_blob_size = 0; 283 ctx->cfg.max_blob_size = 0;
284 ctx->cfg.max_stats = 0; 284 ctx->cfg.max_stats = 0;
285 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 285 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
286 ctx->cfg.renamelimit = -1; 286 ctx->cfg.renamelimit = -1;
287 ctx->cfg.robots = "index, nofollow"; 287 ctx->cfg.robots = "index, nofollow";
288 ctx->cfg.root_title = "Git repository browser"; 288 ctx->cfg.root_title = "Git repository browser";
289 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 289 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
290 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 290 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
291 ctx->cfg.section = ""; 291 ctx->cfg.section = "";
292 ctx->cfg.summary_branches = 10; 292 ctx->cfg.summary_branches = 10;
293 ctx->cfg.summary_log = 10; 293 ctx->cfg.summary_log = 10;
294 ctx->cfg.summary_tags = 10; 294 ctx->cfg.summary_tags = 10;
295 ctx->cfg.ssdiff = 0; 295 ctx->cfg.ssdiff = 0;
296 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 296 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
297 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 297 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
298 ctx->env.https = xstrdupn(getenv("HTTPS")); 298 ctx->env.https = xstrdupn(getenv("HTTPS"));
299 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 299 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
300 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 300 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
301 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 301 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
302 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 302 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
303 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 303 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
304 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); 304 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
305 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); 305 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
306 ctx->page.mimetype = "text/html"; 306 ctx->page.mimetype = "text/html";
307 ctx->page.charset = PAGE_ENCODING; 307 ctx->page.charset = PAGE_ENCODING;
308 ctx->page.filename = NULL; 308 ctx->page.filename = NULL;
309 ctx->page.size = 0; 309 ctx->page.size = 0;
310 ctx->page.modified = time(NULL); 310 ctx->page.modified = time(NULL);
311 ctx->page.expires = ctx->page.modified; 311 ctx->page.expires = ctx->page.modified;
312 ctx->page.etag = NULL; 312 ctx->page.etag = NULL;
313 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); 313 memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list));
314 if (ctx->env.script_name) 314 if (ctx->env.script_name)
315 ctx->cfg.script_name = ctx->env.script_name; 315 ctx->cfg.script_name = ctx->env.script_name;
316 if (ctx->env.query_string) 316 if (ctx->env.query_string)
317 ctx->qry.raw = ctx->env.query_string; 317 ctx->qry.raw = ctx->env.query_string;
318 if (!ctx->env.cgit_config) 318 if (!ctx->env.cgit_config)
319 ctx->env.cgit_config = CGIT_CONFIG; 319 ctx->env.cgit_config = CGIT_CONFIG;
320} 320}
321 321
322struct refmatch { 322struct refmatch {
323 char *req_ref; 323 char *req_ref;
324 char *first_ref; 324 char *first_ref;
325 int match; 325 int match;
326}; 326};
327 327
328int find_current_ref(const char *refname, const unsigned char *sha1, 328int find_current_ref(const char *refname, const unsigned char *sha1,
329 int flags, void *cb_data) 329 int flags, void *cb_data)
330{ 330{
331 struct refmatch *info; 331 struct refmatch *info;
332 332
333 info = (struct refmatch *)cb_data; 333 info = (struct refmatch *)cb_data;
334 if (!strcmp(refname, info->req_ref)) 334 if (!strcmp(refname, info->req_ref))
335 info->match = 1; 335 info->match = 1;
336 if (!info->first_ref) 336 if (!info->first_ref)
337 info->first_ref = xstrdup(refname); 337 info->first_ref = xstrdup(refname);
338 return info->match; 338 return info->match;
339} 339}
340 340
341char *find_default_branch(struct cgit_repo *repo) 341char *find_default_branch(struct cgit_repo *repo)
342{ 342{
343 struct refmatch info; 343 struct refmatch info;
344 char *ref; 344 char *ref;
345 345
346 info.req_ref = repo->defbranch; 346 info.req_ref = repo->defbranch;
347 info.first_ref = NULL; 347 info.first_ref = NULL;
348 info.match = 0; 348 info.match = 0;
349 for_each_branch_ref(find_current_ref, &info); 349 for_each_branch_ref(find_current_ref, &info);
350 if (info.match) 350 if (info.match)
351 ref = info.req_ref; 351 ref = info.req_ref;
352 else 352 else
353 ref = info.first_ref; 353 ref = info.first_ref;
354 if (ref) 354 if (ref)
355 ref = xstrdup(ref); 355 ref = xstrdup(ref);
356 return ref; 356 return ref;
357} 357}
358 358
359static int prepare_repo_cmd(struct cgit_context *ctx) 359static int prepare_repo_cmd(struct cgit_context *ctx)
360{ 360{
361 char *tmp; 361 char *tmp;
362 unsigned char sha1[20]; 362 unsigned char sha1[20];
363 int nongit = 0; 363 int nongit = 0;
364 364
365 setenv("GIT_DIR", ctx->repo->path, 1); 365 setenv("GIT_DIR", ctx->repo->path, 1);
366 setup_git_directory_gently(&nongit); 366 setup_git_directory_gently(&nongit);
367 if (nongit) { 367 if (nongit) {
368 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 368 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
369 "config error"); 369 "config error");
370 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 370 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
371 ctx->repo = NULL; 371 ctx->repo = NULL;
372 cgit_print_http_headers(ctx); 372 cgit_print_http_headers(ctx);
373 cgit_print_docstart(ctx); 373 cgit_print_docstart(ctx);
374 cgit_print_pageheader(ctx); 374 cgit_print_pageheader(ctx);
375 cgit_print_error(tmp); 375 cgit_print_error(tmp);
376 cgit_print_docend(); 376 cgit_print_docend();
377 return 1; 377 return 1;
378 } 378 }
379 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 379 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
380 380
381 if (!ctx->qry.head) { 381 if (!ctx->qry.head) {
382 ctx->qry.nohead = 1; 382 ctx->qry.nohead = 1;
383 ctx->qry.head = find_default_branch(ctx->repo); 383 ctx->qry.head = find_default_branch(ctx->repo);
384 ctx->repo->defbranch = ctx->qry.head; 384 ctx->repo->defbranch = ctx->qry.head;
385 } 385 }
386 386
387 if (!ctx->qry.head) { 387 if (!ctx->qry.head) {
388 cgit_print_http_headers(ctx); 388 cgit_print_http_headers(ctx);
389 cgit_print_docstart(ctx); 389 cgit_print_docstart(ctx);
390 cgit_print_pageheader(ctx); 390 cgit_print_pageheader(ctx);
391 cgit_print_error("Repository seems to be empty"); 391 cgit_print_error("Repository seems to be empty");
392 cgit_print_docend(); 392 cgit_print_docend();
393 return 1; 393 return 1;
394 } 394 }
395 395
396 if (get_sha1(ctx->qry.head, sha1)) { 396 if (get_sha1(ctx->qry.head, sha1)) {
397 tmp = xstrdup(ctx->qry.head); 397 tmp = xstrdup(ctx->qry.head);
398 ctx->qry.head = ctx->repo->defbranch; 398 ctx->qry.head = ctx->repo->defbranch;
399 ctx->page.status = 404; 399 ctx->page.status = 404;
400 ctx->page.statusmsg = "not found"; 400 ctx->page.statusmsg = "not found";
401 cgit_print_http_headers(ctx); 401 cgit_print_http_headers(ctx);
402 cgit_print_docstart(ctx); 402 cgit_print_docstart(ctx);
403 cgit_print_pageheader(ctx); 403 cgit_print_pageheader(ctx);
404 cgit_print_error(fmt("Invalid branch: %s", tmp)); 404 cgit_print_error(fmt("Invalid branch: %s", tmp));
405 cgit_print_docend(); 405 cgit_print_docend();
406 return 1; 406 return 1;
407 } 407 }
408 return 0; 408 return 0;
409} 409}
410 410
411static void process_request(void *cbdata) 411static void process_request(void *cbdata)
412{ 412{
413 struct cgit_context *ctx = cbdata; 413 struct cgit_context *ctx = cbdata;
414 struct cgit_cmd *cmd; 414 struct cgit_cmd *cmd;
415 415
416 cmd = cgit_get_cmd(ctx); 416 cmd = cgit_get_cmd(ctx);
417 if (!cmd) { 417 if (!cmd) {
418 ctx->page.title = "cgit error"; 418 ctx->page.title = "cgit error";
419 cgit_print_http_headers(ctx); 419 cgit_print_http_headers(ctx);
420 cgit_print_docstart(ctx); 420 cgit_print_docstart(ctx);
421 cgit_print_pageheader(ctx); 421 cgit_print_pageheader(ctx);
422 cgit_print_error("Invalid request"); 422 cgit_print_error("Invalid request");
423 cgit_print_docend(); 423 cgit_print_docend();
424 return; 424 return;
425 } 425 }
426 426
427 /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual"
428 * in-project path limit to be made available at ctx->qry.vpath.
429 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL).
430 */
431 ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL;
432
427 if (cmd->want_repo && !ctx->repo) { 433 if (cmd->want_repo && !ctx->repo) {
428 cgit_print_http_headers(ctx); 434 cgit_print_http_headers(ctx);
429 cgit_print_docstart(ctx); 435 cgit_print_docstart(ctx);
430 cgit_print_pageheader(ctx); 436 cgit_print_pageheader(ctx);
431 cgit_print_error(fmt("No repository selected")); 437 cgit_print_error(fmt("No repository selected"));
432 cgit_print_docend(); 438 cgit_print_docend();
433 return; 439 return;
434 } 440 }
435 441
436 if (ctx->repo && prepare_repo_cmd(ctx)) 442 if (ctx->repo && prepare_repo_cmd(ctx))
437 return; 443 return;
438 444
439 if (cmd->want_layout) { 445 if (cmd->want_layout) {
440 cgit_print_http_headers(ctx); 446 cgit_print_http_headers(ctx);
441 cgit_print_docstart(ctx); 447 cgit_print_docstart(ctx);
442 cgit_print_pageheader(ctx); 448 cgit_print_pageheader(ctx);
443 } 449 }
444 450
445 cmd->fn(ctx); 451 cmd->fn(ctx);
446 452
447 if (cmd->want_layout) 453 if (cmd->want_layout)
448 cgit_print_docend(); 454 cgit_print_docend();
449} 455}
450 456
451int cmp_repos(const void *a, const void *b) 457int cmp_repos(const void *a, const void *b)
452{ 458{
453 const struct cgit_repo *ra = a, *rb = b; 459 const struct cgit_repo *ra = a, *rb = b;
454 return strcmp(ra->url, rb->url); 460 return strcmp(ra->url, rb->url);
455} 461}
456 462
457char *build_snapshot_setting(int bitmap) 463char *build_snapshot_setting(int bitmap)
458{ 464{
459 const struct cgit_snapshot_format *f; 465 const struct cgit_snapshot_format *f;
460 char *result = xstrdup(""); 466 char *result = xstrdup("");
461 char *tmp; 467 char *tmp;
462 int len; 468 int len;
463 469
464 for (f = cgit_snapshot_formats; f->suffix; f++) { 470 for (f = cgit_snapshot_formats; f->suffix; f++) {
465 if (f->bit & bitmap) { 471 if (f->bit & bitmap) {
466 tmp = result; 472 tmp = result;
467 result = xstrdup(fmt("%s%s ", tmp, f->suffix)); 473 result = xstrdup(fmt("%s%s ", tmp, f->suffix));
468 free(tmp); 474 free(tmp);
469 } 475 }
470 } 476 }
471 len = strlen(result); 477 len = strlen(result);
472 if (len) 478 if (len)
473 result[len - 1] = '\0'; 479 result[len - 1] = '\0';
474 return result; 480 return result;
475} 481}
476 482
477char *get_first_line(char *txt) 483char *get_first_line(char *txt)
478{ 484{
479 char *t = xstrdup(txt); 485 char *t = xstrdup(txt);
480 char *p = strchr(t, '\n'); 486 char *p = strchr(t, '\n');
481 if (p) 487 if (p)
482 *p = '\0'; 488 *p = '\0';
483 return t; 489 return t;
484} 490}
485 491
486void print_repo(FILE *f, struct cgit_repo *repo) 492void print_repo(FILE *f, struct cgit_repo *repo)
487{ 493{
488 fprintf(f, "repo.url=%s\n", repo->url); 494 fprintf(f, "repo.url=%s\n", repo->url);
489 fprintf(f, "repo.name=%s\n", repo->name); 495 fprintf(f, "repo.name=%s\n", repo->name);
490 fprintf(f, "repo.path=%s\n", repo->path); 496 fprintf(f, "repo.path=%s\n", repo->path);
491 if (repo->owner) 497 if (repo->owner)
492 fprintf(f, "repo.owner=%s\n", repo->owner); 498 fprintf(f, "repo.owner=%s\n", repo->owner);
493 if (repo->desc) { 499 if (repo->desc) {
494 char *tmp = get_first_line(repo->desc); 500 char *tmp = get_first_line(repo->desc);
495 fprintf(f, "repo.desc=%s\n", tmp); 501 fprintf(f, "repo.desc=%s\n", tmp);
496 free(tmp); 502 free(tmp);
497 } 503 }
498 if (repo->readme) 504 if (repo->readme)
499 fprintf(f, "repo.readme=%s\n", repo->readme); 505 fprintf(f, "repo.readme=%s\n", repo->readme);
500 if (repo->defbranch) 506 if (repo->defbranch)
501 fprintf(f, "repo.defbranch=%s\n", repo->defbranch); 507 fprintf(f, "repo.defbranch=%s\n", repo->defbranch);
502 if (repo->module_link) 508 if (repo->module_link)
503 fprintf(f, "repo.module-link=%s\n", repo->module_link); 509 fprintf(f, "repo.module-link=%s\n", repo->module_link);
504 if (repo->section) 510 if (repo->section)
505 fprintf(f, "repo.section=%s\n", repo->section); 511 fprintf(f, "repo.section=%s\n", repo->section);
506 if (repo->clone_url) 512 if (repo->clone_url)
507 fprintf(f, "repo.clone-url=%s\n", repo->clone_url); 513 fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
508 fprintf(f, "repo.enable-log-filecount=%d\n", 514 fprintf(f, "repo.enable-log-filecount=%d\n",
509 repo->enable_log_filecount); 515 repo->enable_log_filecount);
510 fprintf(f, "repo.enable-log-linecount=%d\n", 516 fprintf(f, "repo.enable-log-linecount=%d\n",
511 repo->enable_log_linecount); 517 repo->enable_log_linecount);
512 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) 518 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter)
513 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); 519 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd);
514 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) 520 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter)
515 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); 521 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd);
516 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) 522 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter)
517 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); 523 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd);
518 if (repo->snapshots != ctx.cfg.snapshots) { 524 if (repo->snapshots != ctx.cfg.snapshots) {
519 char *tmp = build_snapshot_setting(repo->snapshots); 525 char *tmp = build_snapshot_setting(repo->snapshots);
520 fprintf(f, "repo.snapshots=%s\n", tmp); 526 fprintf(f, "repo.snapshots=%s\n", tmp);
521 free(tmp); 527 free(tmp);
522 } 528 }
523 if (repo->max_stats != ctx.cfg.max_stats) 529 if (repo->max_stats != ctx.cfg.max_stats)
524 fprintf(f, "repo.max-stats=%s\n", 530 fprintf(f, "repo.max-stats=%s\n",
525 cgit_find_stats_periodname(repo->max_stats)); 531 cgit_find_stats_periodname(repo->max_stats));
526 fprintf(f, "\n"); 532 fprintf(f, "\n");
527} 533}
528 534
529void print_repolist(FILE *f, struct cgit_repolist *list, int start) 535void print_repolist(FILE *f, struct cgit_repolist *list, int start)
530{ 536{
531 int i; 537 int i;
532 538
533 for(i = start; i < list->count; i++) 539 for(i = start; i < list->count; i++)
534 print_repo(f, &list->repos[i]); 540 print_repo(f, &list->repos[i]);
535} 541}
536 542
537/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 543/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
538 * and return 0 on success. 544 * and return 0 on success.
539 */ 545 */
540static int generate_cached_repolist(const char *path, const char *cached_rc) 546static int generate_cached_repolist(const char *path, const char *cached_rc)
541{ 547{
542 char *locked_rc; 548 char *locked_rc;
543 int idx; 549 int idx;
544 FILE *f; 550 FILE *f;
545 551
546 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 552 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
547 f = fopen(locked_rc, "wx"); 553 f = fopen(locked_rc, "wx");
548 if (!f) { 554 if (!f) {
549 /* Inform about the error unless the lockfile already existed, 555 /* Inform about the error unless the lockfile already existed,
550 * since that only means we've got concurrent requests. 556 * since that only means we've got concurrent requests.
551 */ 557 */
552 if (errno != EEXIST) 558 if (errno != EEXIST)
553 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 559 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
554 locked_rc, strerror(errno), errno); 560 locked_rc, strerror(errno), errno);
555 return errno; 561 return errno;
556 } 562 }
557 idx = cgit_repolist.count; 563 idx = cgit_repolist.count;
558 scan_tree(path, repo_config); 564 scan_tree(path, repo_config);
559 print_repolist(f, &cgit_repolist, idx); 565 print_repolist(f, &cgit_repolist, idx);
560 if (rename(locked_rc, cached_rc)) 566 if (rename(locked_rc, cached_rc))
561 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 567 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
562 locked_rc, cached_rc, strerror(errno), errno); 568 locked_rc, cached_rc, strerror(errno), errno);
563 fclose(f); 569 fclose(f);
564 return 0; 570 return 0;
565} 571}
566 572
567static void process_cached_repolist(const char *path) 573static void process_cached_repolist(const char *path)
568{ 574{
569 struct stat st; 575 struct stat st;
570 char *cached_rc; 576 char *cached_rc;
571 time_t age; 577 time_t age;
572 578
573 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 579 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
574 hash_str(path))); 580 hash_str(path)));
575 581
576 if (stat(cached_rc, &st)) { 582 if (stat(cached_rc, &st)) {
577 /* Nothing is cached, we need to scan without forking. And 583 /* Nothing is cached, we need to scan without forking. And
578 * if we fail to generate a cached repolist, we need to 584 * if we fail to generate a cached repolist, we need to
579 * invoke scan_tree manually. 585 * invoke scan_tree manually.
580 */ 586 */
581 if (generate_cached_repolist(path, cached_rc)) 587 if (generate_cached_repolist(path, cached_rc))
582 scan_tree(path, repo_config); 588 scan_tree(path, repo_config);
583 return; 589 return;
584 } 590 }
585 591
586 parse_configfile(cached_rc, config_cb); 592 parse_configfile(cached_rc, config_cb);
587 593
588 /* If the cached configfile hasn't expired, lets exit now */ 594 /* If the cached configfile hasn't expired, lets exit now */
589 age = time(NULL) - st.st_mtime; 595 age = time(NULL) - st.st_mtime;
590 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 596 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
591 return; 597 return;
592 598
593 /* The cached repolist has been parsed, but it was old. So lets 599 /* The cached repolist has been parsed, but it was old. So lets
594 * rescan the specified path and generate a new cached repolist 600 * rescan the specified path and generate a new cached repolist
595 * in a child-process to avoid latency for the current request. 601 * in a child-process to avoid latency for the current request.
596 */ 602 */
597 if (fork()) 603 if (fork())
598 return; 604 return;
599 605
600 exit(generate_cached_repolist(path, cached_rc)); 606 exit(generate_cached_repolist(path, cached_rc));
601} 607}
602 608
603static void cgit_parse_args(int argc, const char **argv) 609static void cgit_parse_args(int argc, const char **argv)
604{ 610{
605 int i; 611 int i;
606 int scan = 0; 612 int scan = 0;
607 613
608 for (i = 1; i < argc; i++) { 614 for (i = 1; i < argc; i++) {
609 if (!strncmp(argv[i], "--cache=", 8)) { 615 if (!strncmp(argv[i], "--cache=", 8)) {
610 ctx.cfg.cache_root = xstrdup(argv[i]+8); 616 ctx.cfg.cache_root = xstrdup(argv[i]+8);
611 } 617 }
612 if (!strcmp(argv[i], "--nocache")) { 618 if (!strcmp(argv[i], "--nocache")) {
613 ctx.cfg.nocache = 1; 619 ctx.cfg.nocache = 1;
614 } 620 }
615 if (!strcmp(argv[i], "--nohttp")) { 621 if (!strcmp(argv[i], "--nohttp")) {
616 ctx.env.no_http = "1"; 622 ctx.env.no_http = "1";
617 } 623 }
618 if (!strncmp(argv[i], "--query=", 8)) { 624 if (!strncmp(argv[i], "--query=", 8)) {
diff --git a/cgit.h b/cgit.h
index cd4af72..f990b15 100644
--- a/cgit.h
+++ b/cgit.h
@@ -1,299 +1,300 @@
1#ifndef CGIT_H 1#ifndef CGIT_H
2#define CGIT_H 2#define CGIT_H
3 3
4 4
5#include <git-compat-util.h> 5#include <git-compat-util.h>
6#include <cache.h> 6#include <cache.h>
7#include <grep.h> 7#include <grep.h>
8#include <object.h> 8#include <object.h>
9#include <tree.h> 9#include <tree.h>
10#include <commit.h> 10#include <commit.h>
11#include <tag.h> 11#include <tag.h>
12#include <diff.h> 12#include <diff.h>
13#include <diffcore.h> 13#include <diffcore.h>
14#include <refs.h> 14#include <refs.h>
15#include <revision.h> 15#include <revision.h>
16#include <log-tree.h> 16#include <log-tree.h>
17#include <archive.h> 17#include <archive.h>
18#include <string-list.h> 18#include <string-list.h>
19#include <xdiff-interface.h> 19#include <xdiff-interface.h>
20#include <xdiff/xdiff.h> 20#include <xdiff/xdiff.h>
21#include <utf8.h> 21#include <utf8.h>
22 22
23 23
24/* 24/*
25 * Dateformats used on misc. pages 25 * Dateformats used on misc. pages
26 */ 26 */
27#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)" 27#define FMT_LONGDATE "%Y-%m-%d %H:%M:%S (%Z)"
28#define FMT_SHORTDATE "%Y-%m-%d" 28#define FMT_SHORTDATE "%Y-%m-%d"
29#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ" 29#define FMT_ATOMDATE "%Y-%m-%dT%H:%M:%SZ"
30 30
31 31
32/* 32/*
33 * Limits used for relative dates 33 * Limits used for relative dates
34 */ 34 */
35#define TM_MIN 60 35#define TM_MIN 60
36#define TM_HOUR (TM_MIN * 60) 36#define TM_HOUR (TM_MIN * 60)
37#define TM_DAY (TM_HOUR * 24) 37#define TM_DAY (TM_HOUR * 24)
38#define TM_WEEK (TM_DAY * 7) 38#define TM_WEEK (TM_DAY * 7)
39#define TM_YEAR (TM_DAY * 365) 39#define TM_YEAR (TM_DAY * 365)
40#define TM_MONTH (TM_YEAR / 12.0) 40#define TM_MONTH (TM_YEAR / 12.0)
41 41
42 42
43/* 43/*
44 * Default encoding 44 * Default encoding
45 */ 45 */
46#define PAGE_ENCODING "UTF-8" 46#define PAGE_ENCODING "UTF-8"
47 47
48typedef void (*configfn)(const char *name, const char *value); 48typedef void (*configfn)(const char *name, const char *value);
49typedef void (*filepair_fn)(struct diff_filepair *pair); 49typedef void (*filepair_fn)(struct diff_filepair *pair);
50typedef void (*linediff_fn)(char *line, int len); 50typedef void (*linediff_fn)(char *line, int len);
51 51
52struct cgit_filter { 52struct cgit_filter {
53 char *cmd; 53 char *cmd;
54 char **argv; 54 char **argv;
55 int old_stdout; 55 int old_stdout;
56 int pipe_fh[2]; 56 int pipe_fh[2];
57 int pid; 57 int pid;
58 int exitstatus; 58 int exitstatus;
59}; 59};
60 60
61struct cgit_repo { 61struct cgit_repo {
62 char *url; 62 char *url;
63 char *name; 63 char *name;
64 char *path; 64 char *path;
65 char *desc; 65 char *desc;
66 char *owner; 66 char *owner;
67 char *defbranch; 67 char *defbranch;
68 char *module_link; 68 char *module_link;
69 char *readme; 69 char *readme;
70 char *section; 70 char *section;
71 char *clone_url; 71 char *clone_url;
72 int snapshots; 72 int snapshots;
73 int enable_log_filecount; 73 int enable_log_filecount;
74 int enable_log_linecount; 74 int enable_log_linecount;
75 int enable_remote_branches; 75 int enable_remote_branches;
76 int max_stats; 76 int max_stats;
77 time_t mtime; 77 time_t mtime;
78 struct cgit_filter *about_filter; 78 struct cgit_filter *about_filter;
79 struct cgit_filter *commit_filter; 79 struct cgit_filter *commit_filter;
80 struct cgit_filter *source_filter; 80 struct cgit_filter *source_filter;
81}; 81};
82 82
83typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, 83typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name,
84 const char *value); 84 const char *value);
85 85
86struct cgit_repolist { 86struct cgit_repolist {
87 int length; 87 int length;
88 int count; 88 int count;
89 struct cgit_repo *repos; 89 struct cgit_repo *repos;
90}; 90};
91 91
92struct commitinfo { 92struct commitinfo {
93 struct commit *commit; 93 struct commit *commit;
94 char *author; 94 char *author;
95 char *author_email; 95 char *author_email;
96 unsigned long author_date; 96 unsigned long author_date;
97 char *committer; 97 char *committer;
98 char *committer_email; 98 char *committer_email;
99 unsigned long committer_date; 99 unsigned long committer_date;
100 char *subject; 100 char *subject;
101 char *msg; 101 char *msg;
102 char *msg_encoding; 102 char *msg_encoding;
103}; 103};
104 104
105struct taginfo { 105struct taginfo {
106 char *tagger; 106 char *tagger;
107 char *tagger_email; 107 char *tagger_email;
108 unsigned long tagger_date; 108 unsigned long tagger_date;
109 char *msg; 109 char *msg;
110}; 110};
111 111
112struct refinfo { 112struct refinfo {
113 const char *refname; 113 const char *refname;
114 struct object *object; 114 struct object *object;
115 union { 115 union {
116 struct taginfo *tag; 116 struct taginfo *tag;
117 struct commitinfo *commit; 117 struct commitinfo *commit;
118 }; 118 };
119}; 119};
120 120
121struct reflist { 121struct reflist {
122 struct refinfo **refs; 122 struct refinfo **refs;
123 int alloc; 123 int alloc;
124 int count; 124 int count;
125}; 125};
126 126
127struct cgit_query { 127struct cgit_query {
128 int has_symref; 128 int has_symref;
129 int has_sha1; 129 int has_sha1;
130 char *raw; 130 char *raw;
131 char *repo; 131 char *repo;
132 char *page; 132 char *page;
133 char *search; 133 char *search;
134 char *grep; 134 char *grep;
135 char *head; 135 char *head;
136 char *sha1; 136 char *sha1;
137 char *sha2; 137 char *sha2;
138 char *path; 138 char *path;
139 char *name; 139 char *name;
140 char *mimetype; 140 char *mimetype;
141 char *url; 141 char *url;
142 char *period; 142 char *period;
143 int ofs; 143 int ofs;
144 int nohead; 144 int nohead;
145 char *sort; 145 char *sort;
146 int showmsg; 146 int showmsg;
147 int ssdiff; 147 int ssdiff;
148 char *vpath;
148}; 149};
149 150
150struct cgit_config { 151struct cgit_config {
151 char *agefile; 152 char *agefile;
152 char *cache_root; 153 char *cache_root;
153 char *clone_prefix; 154 char *clone_prefix;
154 char *css; 155 char *css;
155 char *favicon; 156 char *favicon;
156 char *footer; 157 char *footer;
157 char *head_include; 158 char *head_include;
158 char *header; 159 char *header;
159 char *index_header; 160 char *index_header;
160 char *index_info; 161 char *index_info;
161 char *logo; 162 char *logo;
162 char *logo_link; 163 char *logo_link;
163 char *module_link; 164 char *module_link;
164 char *robots; 165 char *robots;
165 char *root_title; 166 char *root_title;
166 char *root_desc; 167 char *root_desc;
167 char *root_readme; 168 char *root_readme;
168 char *script_name; 169 char *script_name;
169 char *section; 170 char *section;
170 char *virtual_root; 171 char *virtual_root;
171 int cache_size; 172 int cache_size;
172 int cache_dynamic_ttl; 173 int cache_dynamic_ttl;
173 int cache_max_create_time; 174 int cache_max_create_time;
174 int cache_repo_ttl; 175 int cache_repo_ttl;
175 int cache_root_ttl; 176 int cache_root_ttl;
176 int cache_scanrc_ttl; 177 int cache_scanrc_ttl;
177 int cache_static_ttl; 178 int cache_static_ttl;
178 int embedded; 179 int embedded;
179 int enable_filter_overrides; 180 int enable_filter_overrides;
180 int enable_index_links; 181 int enable_index_links;
181 int enable_log_filecount; 182 int enable_log_filecount;
182 int enable_log_linecount; 183 int enable_log_linecount;
183 int enable_remote_branches; 184 int enable_remote_branches;
184 int enable_tree_linenumbers; 185 int enable_tree_linenumbers;
185 int local_time; 186 int local_time;
186 int max_repo_count; 187 int max_repo_count;
187 int max_commit_count; 188 int max_commit_count;
188 int max_lock_attempts; 189 int max_lock_attempts;
189 int max_msg_len; 190 int max_msg_len;
190 int max_repodesc_len; 191 int max_repodesc_len;
191 int max_blob_size; 192 int max_blob_size;
192 int max_stats; 193 int max_stats;
193 int nocache; 194 int nocache;
194 int noplainemail; 195 int noplainemail;
195 int noheader; 196 int noheader;
196 int renamelimit; 197 int renamelimit;
197 int snapshots; 198 int snapshots;
198 int summary_branches; 199 int summary_branches;
199 int summary_log; 200 int summary_log;
200 int summary_tags; 201 int summary_tags;
201 int ssdiff; 202 int ssdiff;
202 struct string_list mimetypes; 203 struct string_list mimetypes;
203 struct cgit_filter *about_filter; 204 struct cgit_filter *about_filter;
204 struct cgit_filter *commit_filter; 205 struct cgit_filter *commit_filter;
205 struct cgit_filter *source_filter; 206 struct cgit_filter *source_filter;
206}; 207};
207 208
208struct cgit_page { 209struct cgit_page {
209 time_t modified; 210 time_t modified;
210 time_t expires; 211 time_t expires;
211 size_t size; 212 size_t size;
212 char *mimetype; 213 char *mimetype;
213 char *charset; 214 char *charset;
214 char *filename; 215 char *filename;
215 char *etag; 216 char *etag;
216 char *title; 217 char *title;
217 int status; 218 int status;
218 char *statusmsg; 219 char *statusmsg;
219}; 220};
220 221
221struct cgit_environment { 222struct cgit_environment {
222 char *cgit_config; 223 char *cgit_config;
223 char *http_host; 224 char *http_host;
224 char *https; 225 char *https;
225 char *no_http; 226 char *no_http;
226 char *path_info; 227 char *path_info;
227 char *query_string; 228 char *query_string;
228 char *request_method; 229 char *request_method;
229 char *script_name; 230 char *script_name;
230 char *server_name; 231 char *server_name;
231 char *server_port; 232 char *server_port;
232}; 233};
233 234
234struct cgit_context { 235struct cgit_context {
235 struct cgit_environment env; 236 struct cgit_environment env;
236 struct cgit_query qry; 237 struct cgit_query qry;
237 struct cgit_config cfg; 238 struct cgit_config cfg;
238 struct cgit_repo *repo; 239 struct cgit_repo *repo;
239 struct cgit_page page; 240 struct cgit_page page;
240}; 241};
241 242
242struct cgit_snapshot_format { 243struct cgit_snapshot_format {
243 const char *suffix; 244 const char *suffix;
244 const char *mimetype; 245 const char *mimetype;
245 write_archive_fn_t write_func; 246 write_archive_fn_t write_func;
246 int bit; 247 int bit;
247}; 248};
248 249
249extern const char *cgit_version; 250extern const char *cgit_version;
250 251
251extern struct cgit_repolist cgit_repolist; 252extern struct cgit_repolist cgit_repolist;
252extern struct cgit_context ctx; 253extern struct cgit_context ctx;
253extern const struct cgit_snapshot_format cgit_snapshot_formats[]; 254extern const struct cgit_snapshot_format cgit_snapshot_formats[];
254 255
255extern struct cgit_repo *cgit_add_repo(const char *url); 256extern struct cgit_repo *cgit_add_repo(const char *url);
256extern struct cgit_repo *cgit_get_repoinfo(const char *url); 257extern struct cgit_repo *cgit_get_repoinfo(const char *url);
257extern void cgit_repo_config_cb(const char *name, const char *value); 258extern void cgit_repo_config_cb(const char *name, const char *value);
258 259
259extern int chk_zero(int result, char *msg); 260extern int chk_zero(int result, char *msg);
260extern int chk_positive(int result, char *msg); 261extern int chk_positive(int result, char *msg);
261extern int chk_non_negative(int result, char *msg); 262extern int chk_non_negative(int result, char *msg);
262 263
263extern char *trim_end(const char *str, char c); 264extern char *trim_end(const char *str, char c);
264extern char *strlpart(char *txt, int maxlen); 265extern char *strlpart(char *txt, int maxlen);
265extern char *strrpart(char *txt, int maxlen); 266extern char *strrpart(char *txt, int maxlen);
266 267
267extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); 268extern void cgit_add_ref(struct reflist *list, struct refinfo *ref);
268extern int cgit_refs_cb(const char *refname, const unsigned char *sha1, 269extern int cgit_refs_cb(const char *refname, const unsigned char *sha1,
269 int flags, void *cb_data); 270 int flags, void *cb_data);
270 271
271extern void *cgit_free_commitinfo(struct commitinfo *info); 272extern void *cgit_free_commitinfo(struct commitinfo *info);
272 273
273extern int cgit_diff_files(const unsigned char *old_sha1, 274extern int cgit_diff_files(const unsigned char *old_sha1,
274 const unsigned char *new_sha1, 275 const unsigned char *new_sha1,
275 unsigned long *old_size, unsigned long *new_size, 276 unsigned long *old_size, unsigned long *new_size,
276 int *binary, linediff_fn fn); 277 int *binary, linediff_fn fn);
277 278
278extern void cgit_diff_tree(const unsigned char *old_sha1, 279extern void cgit_diff_tree(const unsigned char *old_sha1,
279 const unsigned char *new_sha1, 280 const unsigned char *new_sha1,
280 filepair_fn fn, const char *prefix); 281 filepair_fn fn, const char *prefix);
281 282
282extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 283extern void cgit_diff_commit(struct commit *commit, filepair_fn fn);
283 284
284extern char *fmt(const char *format,...); 285extern char *fmt(const char *format,...);
285 286
286extern struct commitinfo *cgit_parse_commit(struct commit *commit); 287extern struct commitinfo *cgit_parse_commit(struct commit *commit);
287extern struct taginfo *cgit_parse_tag(struct tag *tag); 288extern struct taginfo *cgit_parse_tag(struct tag *tag);
288extern void cgit_parse_url(const char *url); 289extern void cgit_parse_url(const char *url);
289 290
290extern const char *cgit_repobasename(const char *reponame); 291extern const char *cgit_repobasename(const char *reponame);
291 292
292extern int cgit_parse_snapshots_mask(const char *str); 293extern int cgit_parse_snapshots_mask(const char *str);
293 294
294extern int cgit_open_filter(struct cgit_filter *filter); 295extern int cgit_open_filter(struct cgit_filter *filter);
295extern int cgit_close_filter(struct cgit_filter *filter); 296extern int cgit_close_filter(struct cgit_filter *filter);
296 297
297extern int readfile(const char *path, char **buf, size_t *size); 298extern int readfile(const char *path, char **buf, size_t *size);
298 299
299#endif /* CGIT_H */ 300#endif /* CGIT_H */
diff --git a/cmd.c b/cmd.c
index 766f903..a9e426a 100644
--- a/cmd.c
+++ b/cmd.c
@@ -1,171 +1,171 @@
1/* cmd.c: the cgit command dispatcher 1/* cmd.c: the cgit command dispatcher
2 * 2 *
3 * Copyright (C) 2008 Lars Hjemli 3 * Copyright (C) 2008 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "cmd.h" 10#include "cmd.h"
11#include "cache.h" 11#include "cache.h"
12#include "ui-shared.h" 12#include "ui-shared.h"
13#include "ui-atom.h" 13#include "ui-atom.h"
14#include "ui-blob.h" 14#include "ui-blob.h"
15#include "ui-clone.h" 15#include "ui-clone.h"
16#include "ui-commit.h" 16#include "ui-commit.h"
17#include "ui-diff.h" 17#include "ui-diff.h"
18#include "ui-log.h" 18#include "ui-log.h"
19#include "ui-patch.h" 19#include "ui-patch.h"
20#include "ui-plain.h" 20#include "ui-plain.h"
21#include "ui-refs.h" 21#include "ui-refs.h"
22#include "ui-repolist.h" 22#include "ui-repolist.h"
23#include "ui-snapshot.h" 23#include "ui-snapshot.h"
24#include "ui-stats.h" 24#include "ui-stats.h"
25#include "ui-summary.h" 25#include "ui-summary.h"
26#include "ui-tag.h" 26#include "ui-tag.h"
27#include "ui-tree.h" 27#include "ui-tree.h"
28 28
29static void HEAD_fn(struct cgit_context *ctx) 29static void HEAD_fn(struct cgit_context *ctx)
30{ 30{
31 cgit_clone_head(ctx); 31 cgit_clone_head(ctx);
32} 32}
33 33
34static void atom_fn(struct cgit_context *ctx) 34static void atom_fn(struct cgit_context *ctx)
35{ 35{
36 cgit_print_atom(ctx->qry.head, ctx->qry.path, 10); 36 cgit_print_atom(ctx->qry.head, ctx->qry.path, 10);
37} 37}
38 38
39static void about_fn(struct cgit_context *ctx) 39static void about_fn(struct cgit_context *ctx)
40{ 40{
41 if (ctx->repo) 41 if (ctx->repo)
42 cgit_print_repo_readme(ctx->qry.path); 42 cgit_print_repo_readme(ctx->qry.path);
43 else 43 else
44 cgit_print_site_readme(); 44 cgit_print_site_readme();
45} 45}
46 46
47static void blob_fn(struct cgit_context *ctx) 47static void blob_fn(struct cgit_context *ctx)
48{ 48{
49 cgit_print_blob(ctx->qry.sha1, ctx->qry.path, ctx->qry.head); 49 cgit_print_blob(ctx->qry.sha1, ctx->qry.path, ctx->qry.head);
50} 50}
51 51
52static void commit_fn(struct cgit_context *ctx) 52static void commit_fn(struct cgit_context *ctx)
53{ 53{
54 cgit_print_commit(ctx->qry.sha1); 54 cgit_print_commit(ctx->qry.sha1);
55} 55}
56 56
57static void diff_fn(struct cgit_context *ctx) 57static void diff_fn(struct cgit_context *ctx)
58{ 58{
59 cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path); 59 cgit_print_diff(ctx->qry.sha1, ctx->qry.sha2, ctx->qry.path);
60} 60}
61 61
62static void info_fn(struct cgit_context *ctx) 62static void info_fn(struct cgit_context *ctx)
63{ 63{
64 cgit_clone_info(ctx); 64 cgit_clone_info(ctx);
65} 65}
66 66
67static void log_fn(struct cgit_context *ctx) 67static void log_fn(struct cgit_context *ctx)
68{ 68{
69 cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count, 69 cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count,
70 ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1); 70 ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1);
71} 71}
72 72
73static void ls_cache_fn(struct cgit_context *ctx) 73static void ls_cache_fn(struct cgit_context *ctx)
74{ 74{
75 ctx->page.mimetype = "text/plain"; 75 ctx->page.mimetype = "text/plain";
76 ctx->page.filename = "ls-cache.txt"; 76 ctx->page.filename = "ls-cache.txt";
77 cgit_print_http_headers(ctx); 77 cgit_print_http_headers(ctx);
78 cache_ls(ctx->cfg.cache_root); 78 cache_ls(ctx->cfg.cache_root);
79} 79}
80 80
81static void objects_fn(struct cgit_context *ctx) 81static void objects_fn(struct cgit_context *ctx)
82{ 82{
83 cgit_clone_objects(ctx); 83 cgit_clone_objects(ctx);
84} 84}
85 85
86static void repolist_fn(struct cgit_context *ctx) 86static void repolist_fn(struct cgit_context *ctx)
87{ 87{
88 cgit_print_repolist(); 88 cgit_print_repolist();
89} 89}
90 90
91static void patch_fn(struct cgit_context *ctx) 91static void patch_fn(struct cgit_context *ctx)
92{ 92{
93 cgit_print_patch(ctx->qry.sha1); 93 cgit_print_patch(ctx->qry.sha1);
94} 94}
95 95
96static void plain_fn(struct cgit_context *ctx) 96static void plain_fn(struct cgit_context *ctx)
97{ 97{
98 cgit_print_plain(ctx); 98 cgit_print_plain(ctx);
99} 99}
100 100
101static void refs_fn(struct cgit_context *ctx) 101static void refs_fn(struct cgit_context *ctx)
102{ 102{
103 cgit_print_refs(); 103 cgit_print_refs();
104} 104}
105 105
106static void snapshot_fn(struct cgit_context *ctx) 106static void snapshot_fn(struct cgit_context *ctx)
107{ 107{
108 cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, ctx->qry.path, 108 cgit_print_snapshot(ctx->qry.head, ctx->qry.sha1, ctx->qry.path,
109 ctx->repo->snapshots, ctx->qry.nohead); 109 ctx->repo->snapshots, ctx->qry.nohead);
110} 110}
111 111
112static void stats_fn(struct cgit_context *ctx) 112static void stats_fn(struct cgit_context *ctx)
113{ 113{
114 cgit_show_stats(ctx); 114 cgit_show_stats(ctx);
115} 115}
116 116
117static void summary_fn(struct cgit_context *ctx) 117static void summary_fn(struct cgit_context *ctx)
118{ 118{
119 cgit_print_summary(); 119 cgit_print_summary();
120} 120}
121 121
122static void tag_fn(struct cgit_context *ctx) 122static void tag_fn(struct cgit_context *ctx)
123{ 123{
124 cgit_print_tag(ctx->qry.sha1); 124 cgit_print_tag(ctx->qry.sha1);
125} 125}
126 126
127static void tree_fn(struct cgit_context *ctx) 127static void tree_fn(struct cgit_context *ctx)
128{ 128{
129 cgit_print_tree(ctx->qry.sha1, ctx->qry.path); 129 cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
130} 130}
131 131
132#define def_cmd(name, want_repo, want_layout) \ 132#define def_cmd(name, want_repo, want_layout, want_vpath) \
133 {#name, name##_fn, want_repo, want_layout} 133 {#name, name##_fn, want_repo, want_layout, want_vpath}
134 134
135struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) 135struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
136{ 136{
137 static struct cgit_cmd cmds[] = { 137 static struct cgit_cmd cmds[] = {
138 def_cmd(HEAD, 1, 0), 138 def_cmd(HEAD, 1, 0, 0),
139 def_cmd(atom, 1, 0), 139 def_cmd(atom, 1, 0, 0),
140 def_cmd(about, 0, 1), 140 def_cmd(about, 0, 1, 0),
141 def_cmd(blob, 1, 0), 141 def_cmd(blob, 1, 0, 0),
142 def_cmd(commit, 1, 1), 142 def_cmd(commit, 1, 1, 1),
143 def_cmd(diff, 1, 1), 143 def_cmd(diff, 1, 1, 1),
144 def_cmd(info, 1, 0), 144 def_cmd(info, 1, 0, 0),
145 def_cmd(log, 1, 1), 145 def_cmd(log, 1, 1, 1),
146 def_cmd(ls_cache, 0, 0), 146 def_cmd(ls_cache, 0, 0, 0),
147 def_cmd(objects, 1, 0), 147 def_cmd(objects, 1, 0, 0),
148 def_cmd(patch, 1, 0), 148 def_cmd(patch, 1, 0, 1),
149 def_cmd(plain, 1, 0), 149 def_cmd(plain, 1, 0, 0),
150 def_cmd(refs, 1, 1), 150 def_cmd(refs, 1, 1, 0),
151 def_cmd(repolist, 0, 0), 151 def_cmd(repolist, 0, 0, 0),
152 def_cmd(snapshot, 1, 0), 152 def_cmd(snapshot, 1, 0, 0),
153 def_cmd(stats, 1, 1), 153 def_cmd(stats, 1, 1, 1),
154 def_cmd(summary, 1, 1), 154 def_cmd(summary, 1, 1, 0),
155 def_cmd(tag, 1, 1), 155 def_cmd(tag, 1, 1, 0),
156 def_cmd(tree, 1, 1), 156 def_cmd(tree, 1, 1, 1),
157 }; 157 };
158 int i; 158 int i;
159 159
160 if (ctx->qry.page == NULL) { 160 if (ctx->qry.page == NULL) {
161 if (ctx->repo) 161 if (ctx->repo)
162 ctx->qry.page = "summary"; 162 ctx->qry.page = "summary";
163 else 163 else
164 ctx->qry.page = "repolist"; 164 ctx->qry.page = "repolist";
165 } 165 }
166 166
167 for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++) 167 for(i = 0; i < sizeof(cmds)/sizeof(*cmds); i++)
168 if (!strcmp(ctx->qry.page, cmds[i].name)) 168 if (!strcmp(ctx->qry.page, cmds[i].name))
169 return &cmds[i]; 169 return &cmds[i];
170 return NULL; 170 return NULL;
171} 171}
diff --git a/cmd.h b/cmd.h
index ec9e691..8dc01bd 100644
--- a/cmd.h
+++ b/cmd.h
@@ -1,15 +1,16 @@
1#ifndef CMD_H 1#ifndef CMD_H
2#define CMD_H 2#define CMD_H
3 3
4typedef void (*cgit_cmd_fn)(struct cgit_context *ctx); 4typedef void (*cgit_cmd_fn)(struct cgit_context *ctx);
5 5
6struct cgit_cmd { 6struct cgit_cmd {
7 const char *name; 7 const char *name;
8 cgit_cmd_fn fn; 8 cgit_cmd_fn fn;
9 unsigned int want_repo:1, 9 unsigned int want_repo:1,
10 want_layout:1; 10 want_layout:1,
11 want_vpath:1;
11}; 12};
12 13
13extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx); 14extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx);
14 15
15#endif /* CMD_H */ 16#endif /* CMD_H */