+sub git_tags_body {
+ # uses global variable $project
+ my ($taglist, $from, $to, $extra) = @_;
+ $from = 0 unless defined $from;
+ $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
+
+ print "<table class=\"tags\" cellspacing=\"0\">\n";
+ my $alternate = 0;
+ for (my $i = $from; $i <= $to; $i++) {
+ my $entry = $taglist->[$i];
+ my %tag = %$entry;
+ my $comment_lines = $tag{'comment'};
+ my $comment = shift @$comment_lines;
+ my $comment_short;
+ if (defined $comment) {
+ $comment_short = chop_str($comment, 30, 5);
+ }
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+ print "<td><i>$tag{'age'}</i></td>\n" .
+ "<td>" .
+ $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}"),
+ -class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
+ "</td>\n" .
+ "<td>";
+ if (defined $comment) {
+ if (length($comment_short) < length($comment)) {
+ print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}"),
+ -class => "list", -title => $comment}, $comment_short);
+ } else {
+ print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}"),
+ -class => "list"}, $comment);
+ }
+ }
+ print "</td>\n" .
+ "<td class=\"selflink\">";
+ if ($tag{'type'} eq "tag") {
+ print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tag;h=$tag{'id'}")}, "tag");
+ } else {
+ print " ";
+ }
+ print "</td>\n" .
+ "<td class=\"link\">" . " | " .
+ $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=$tag{'reftype'};h=$tag{'refid'}")}, $tag{'reftype'});
+ if ($tag{'reftype'} eq "commit") {
+ print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") .
+ " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'refid'}")}, "log");
+ } elsif ($tag{'reftype'} eq "blob") {
+ print " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$tag{'refid'}")}, "raw");
+ }
+ print "</td>\n" .
+ "</tr>";
+ }
+ if (defined $extra) {
+ print "<tr>\n" .
+ "<td colspan=\"5\">$extra</td>\n" .
+ "</tr>\n";
+ }
+ print "</table>\n";
+}
+
+sub git_heads_body {
+ # uses global variable $project
+ my ($taglist, $head, $from, $to, $extra) = @_;
+ $from = 0 unless defined $from;
+ $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
+
+ print "<table class=\"heads\" cellspacing=\"0\">\n";
+ my $alternate = 0;
+ for (my $i = $from; $i <= $to; $i++) {
+ my $entry = $taglist->[$i];
+ my %tag = %$entry;
+ my $curr = $tag{'id'} eq $head;
+ if ($alternate) {
+ print "<tr class=\"dark\">\n";
+ } else {
+ print "<tr class=\"light\">\n";
+ }
+ $alternate ^= 1;
+ print "<td><i>$tag{'age'}</i></td>\n" .
+ ($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
+ $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}"),
+ -class => "list"}, "<b>" . esc_html($tag{'name'}) . "</b>") .
+ "</td>\n" .
+ "<td class=\"link\">" .
+ $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog;h=$tag{'name'}")}, "shortlog") . " | " .
+ $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log;h=$tag{'name'}")}, "log") .
+ "</td>\n" .
+ "</tr>";
+ }
+ if (defined $extra) {
+ print "<tr>\n" .
+ "<td colspan=\"3\">$extra</td>\n" .
+ "</tr>\n";
+ }
+ print "</table>\n";
+}
+
+## ----------------------------------------------------------------------
+## functions printing large fragments, format as one of arguments
+
+sub git_diff_print {
+ my $from = shift;
+ my $from_name = shift;
+ my $to = shift;
+ my $to_name = shift;
+ my $format = shift || "html";
+
+ my $from_tmp = "/dev/null";
+ my $to_tmp = "/dev/null";
+ my $pid = $$;
+
+ # create tmp from-file
+ if (defined $from) {
+ $from_tmp = "$git_temp/gitweb_" . $$ . "_from";
+ open my $fd2, "> $from_tmp";
+ open my $fd, "-|", $GIT, "cat-file", "blob", $from;
+ my @file = <$fd>;
+ print $fd2 @file;
+ close $fd2;
+ close $fd;
+ }
+
+ # create tmp to-file
+ if (defined $to) {
+ $to_tmp = "$git_temp/gitweb_" . $$ . "_to";
+ open my $fd2, "> $to_tmp";
+ open my $fd, "-|", $GIT, "cat-file", "blob", $to;
+ my @file = <$fd>;
+ print $fd2 @file;
+ close $fd2;
+ close $fd;
+ }
+
+ open my $fd, "-|", "/usr/bin/diff -u -p -L \'$from_name\' -L \'$to_name\' $from_tmp $to_tmp";
+ if ($format eq "plain") {
+ undef $/;
+ print <$fd>;
+ $/ = "\n";
+ } else {
+ while (my $line = <$fd>) {
+ chomp $line;
+ my $char = substr($line, 0, 1);
+ my $diff_class = "";
+ if ($char eq '+') {
+ $diff_class = " add";
+ } elsif ($char eq "-") {
+ $diff_class = " rem";
+ } elsif ($char eq "@") {
+ $diff_class = " chunk_header";
+ } elsif ($char eq "\\") {
+ # skip errors
+ next;
+ }
+ while ((my $pos = index($line, "\t")) != -1) {
+ if (my $count = (8 - (($pos-1) % 8))) {
+ my $spaces = ' ' x $count;
+ $line =~ s/\t/$spaces/;
+ }
+ }
+ print "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
+ }
+ }
+ close $fd;
+
+ if (defined $from) {
+ unlink($from_tmp);
+ }
+ if (defined $to) {
+ unlink($to_tmp);
+ }
+}
+
+
+## ======================================================================
+## ======================================================================
+## actions
+
+# git-logo (cached in browser for one day)
+sub git_logo {
+ binmode STDOUT, ':raw';
+ print $cgi->header(-type => 'image/png', -expires => '+1d');
+ # cat git-logo.png | hexdump -e '16/1 " %02x" "\n"' | sed 's/ /\\x/g'
+ print "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" .
+ "\x00\x00\x00\x48\x00\x00\x00\x1b\x04\x03\x00\x00\x00\x2d\xd9\xd4" .
+ "\x2d\x00\x00\x00\x18\x50\x4c\x54\x45\xff\xff\xff\x60\x60\x5d\xb0" .
+ "\xaf\xaa\x00\x80\x00\xce\xcd\xc7\xc0\x00\x00\xe8\xe8\xe6\xf7\xf7" .
+ "\xf6\x95\x0c\xa7\x47\x00\x00\x00\x73\x49\x44\x41\x54\x28\xcf\x63" .
+ "\x48\x67\x20\x04\x4a\x5c\x18\x0a\x08\x2a\x62\x53\x61\x20\x02\x08" .
+ "\x0d\x69\x45\xac\xa1\xa1\x01\x30\x0c\x93\x60\x36\x26\x52\x91\xb1" .
+ "\x01\x11\xd6\xe1\x55\x64\x6c\x6c\xcc\x6c\x6c\x0c\xa2\x0c\x70\x2a" .
+ "\x62\x06\x2a\xc1\x62\x1d\xb3\x01\x02\x53\xa4\x08\xe8\x00\x03\x18" .
+ "\x26\x56\x11\xd4\xe1\x20\x97\x1b\xe0\xb4\x0e\x35\x24\x71\x29\x82" .
+ "\x99\x30\xb8\x93\x0a\x11\xb9\x45\x88\xc1\x8d\xa0\xa2\x44\x21\x06" .
+ "\x27\x41\x82\x40\x85\xc1\x45\x89\x20\x70\x01\x00\xa4\x3d\x21\xc5" .
+ "\x12\x1c\x9a\xfe\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82";
+}