X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/72424a946d4d49d67bf0ac3da402ae68593ae869f73ba33b1060676a6e094e61..66597c4f8d1d454bbd9c5fd754b7d481064543176c7bef3aaf078ed531ce8922:/gitweb.perl diff --git a/gitweb.perl b/gitweb.perl index 39de505..00e35dc 100755 --- a/gitweb.perl +++ b/gitweb.perl @@ -473,13 +473,15 @@ if (defined $searchtype) { } } +our $search_use_regexp = $cgi->param('sr'); + our $searchtext = $cgi->param('s'); our $search_regexp; if (defined $searchtext) { if (length($searchtext) < 2) { die_error(undef, "At least two characters are required for search parameter"); } - $search_regexp = quotemeta $searchtext; + $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; } # now read PATH_INFO and use it as alternative to parameters @@ -609,9 +611,12 @@ sub href(%) { searchtype => "st", snapshot_format => "sf", extra_options => "opt", + search_use_regexp => "sr", ); my %mapping = @mapping; + $params{'project'} = $project unless exists $params{'project'}; + if ($params{-replay}) { while (my ($name, $symbol) = each %mapping) { if (!exists $params{$name}) { @@ -621,8 +626,6 @@ sub href(%) { } } - $params{'project'} = $project unless exists $params{'project'}; - my ($use_pathinfo) = gitweb_check_feature('pathinfo'); if ($use_pathinfo) { # use PATH_INFO for project name @@ -696,10 +699,9 @@ sub validate_refname { # in utf-8 thanks to "binmode STDOUT, ':utf8'" at beginning sub to_utf8 { my $str = shift; - my $res; - eval { $res = decode_utf8($str, Encode::FB_CROAK); }; - if (defined $res) { - return $res; + if (utf8::valid($str)) { + utf8::decode($str); + return $str; } else { return decode($fallback_encoding, $str, Encode::FB_DEFAULT); } @@ -755,29 +757,40 @@ sub esc_path { # Make control characters "printable", using character escape codes (CEC) sub quot_cec { my $cntrl = shift; + my %opts = @_; my %es = ( # character escape codes, aka escape sequences - "\t" => '\t', # tab (HT) - "\n" => '\n', # line feed (LF) - "\r" => '\r', # carrige return (CR) - "\f" => '\f', # form feed (FF) - "\b" => '\b', # backspace (BS) - "\a" => '\a', # alarm (bell) (BEL) - "\e" => '\e', # escape (ESC) - "\013" => '\v', # vertical tab (VT) - "\000" => '\0', # nul character (NUL) - ); + "\t" => '\t', # tab (HT) + "\n" => '\n', # line feed (LF) + "\r" => '\r', # carrige return (CR) + "\f" => '\f', # form feed (FF) + "\b" => '\b', # backspace (BS) + "\a" => '\a', # alarm (bell) (BEL) + "\e" => '\e', # escape (ESC) + "\013" => '\v', # vertical tab (VT) + "\000" => '\0', # nul character (NUL) + ); my $chr = ( (exists $es{$cntrl}) ? $es{$cntrl} : sprintf('\%03o', ord($cntrl)) ); - return "$chr"; + if ($opts{-nohtml}) { + return $chr; + } else { + return "$chr"; + } } # Alternatively use unicode control pictures codepoints, # Unicode "printable representation" (PR) sub quot_upr { my $cntrl = shift; + my %opts = @_; + my $chr = sprintf('&#%04d;', 0x2400+ord($cntrl)); - return "$chr"; + if ($opts{-nohtml}) { + return $chr; + } else { + return "$chr"; + } } # git may return quoted and escaped filenames @@ -802,7 +815,7 @@ sub unquote { return chr(oct($seq)); } elsif (exists $es{$seq}) { # C escape sequence, aka character escape code - return $es{$seq} + return $es{$seq}; } # quoted ordinary character return $seq; @@ -839,37 +852,78 @@ sub project_in_list { ## ---------------------------------------------------------------------- ## HTML aware string manipulation +# Try to chop given string on a word boundary between position +# $len and $len+$add_len. If there is no word boundary there, +# chop at $len+$add_len. Do not chop if chopped part plus ellipsis +# (marking chopped part) would be longer than given string. sub chop_str { my $str = shift; my $len = shift; my $add_len = shift || 10; + my $where = shift || 'right'; # 'left' | 'center' | 'right' # allow only $len chars, but don't cut a word if it would fit in $add_len # if it doesn't fit, cut it if it's still longer than the dots we would add - $str =~ m/^(.{0,$len}[^ \/\-_:\.@]{0,$add_len})(.*)/; - my $body = $1; - my $tail = $2; - if (length($tail) > 4) { - $tail = " ..."; - $body =~ s/&[^;]*$//; # remove chopped character entities + # remove chopped character entities entirely + + # when chopping in the middle, distribute $len into left and right part + # return early if chopping wouldn't make string shorter + if ($where eq 'center') { + return $str if ($len + 5 >= length($str)); # filler is length 5 + $len = int($len/2); + } else { + return $str if ($len + 4 >= length($str)); # filler is length 4 + } + + # regexps: ending and beginning with word part up to $add_len + my $endre = qr/.{$len}\w{0,$add_len}/; + my $begre = qr/\w{0,$add_len}.{$len}/; + + if ($where eq 'left') { + $str =~ m/^(.*?)($begre)$/; + my ($lead, $body) = ($1, $2); + if (length($lead) > 4) { + $body =~ s/^[^;]*;// if ($lead =~ m/&[^;]*$/); + $lead = " ..."; + } + return "$lead$body"; + + } elsif ($where eq 'center') { + $str =~ m/^($endre)(.*)$/; + my ($left, $str) = ($1, $2); + $str =~ m/^(.*?)($begre)$/; + my ($mid, $right) = ($1, $2); + if (length($mid) > 5) { + $left =~ s/&[^;]*$//; + $right =~ s/^[^;]*;// if ($mid =~ m/&[^;]*$/); + $mid = " ... "; + } + return "$left$mid$right"; + + } else { + $str =~ m/^($endre)(.*)$/; + my $body = $1; + my $tail = $2; + if (length($tail) > 4) { + $body =~ s/&[^;]*$//; + $tail = "... "; + } + return "$body$tail"; } - return "$body$tail"; } # takes the same arguments as chop_str, but also wraps a around the # result with a title attribute if it does get chopped. Additionally, the # string is HTML-escaped. sub chop_and_escape_str { - my $str = shift; - my $len = shift; - my $add_len = shift || 10; + my ($str) = @_; - my $chopped = chop_str($str, $len, $add_len); + my $chopped = chop_str(@_); if ($chopped eq $str) { return esc_html($chopped); } else { - return qq{} . - esc_html($chopped) . qq{}; + $str =~ s/([[:cntrl:]])/?/g; + return $cgi->span({-title=>$str}, esc_html($chopped)); } } @@ -1513,7 +1567,7 @@ sub config_to_int { sub config_to_multi { my $val = shift; - return ref($val) ? $val : [ $val ]; + return ref($val) ? $val : (defined($val) ? [ $val ] : []); } sub git_get_project_config { @@ -1608,7 +1662,7 @@ sub git_get_project_description { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$projectroot/$path/description" + open my $fd, "$git_dir/description" or return git_get_project_config('description'); my $descr = <$fd>; close $fd; @@ -1622,7 +1676,7 @@ sub git_get_project_url_list { my $path = shift; $git_dir = "$projectroot/$path"; - open my $fd, "$projectroot/$path/cloneurl" + open my $fd, "$git_dir/cloneurl" or return wantarray ? @{ config_to_multi(git_get_project_config('url')) } : config_to_multi(git_get_project_config('url')); @@ -1761,6 +1815,7 @@ sub git_get_project_owner { my $owner; return undef unless $project; + $git_dir = "$projectroot/$project"; if (!defined $gitweb_project_owner) { git_get_project_list_from_file(); @@ -1769,8 +1824,11 @@ sub git_get_project_owner { if (exists $gitweb_project_owner->{$project}) { $owner = $gitweb_project_owner->{$project}; } + if (!defined $owner){ + $owner = git_get_project_config('owner'); + } if (!defined $owner) { - $owner = get_file_owner("$projectroot/$project"); + $owner = get_file_owner("$git_dir"); } return $owner; @@ -1857,7 +1915,7 @@ sub parse_date { $date{'mday-time'} = sprintf "%d %s %02d:%02d", $mday, $months[$mon], $hour ,$min; $date{'iso-8601'} = sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ", - 1900+$year, $mon, $mday, $hour ,$min, $sec; + 1900+$year, 1+$mon, $mday, $hour ,$min, $sec; $tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/; my $local = $epoch + ((int $1 + ($2/60)) * 3600); @@ -2025,7 +2083,7 @@ sub parse_commit { } sub parse_commits { - my ($commit_id, $maxcount, $skip, $arg, $filename) = @_; + my ($commit_id, $maxcount, $skip, $filename, @args) = @_; my @cos; $maxcount ||= 1; @@ -2035,7 +2093,7 @@ sub parse_commits { open my $fd, "-|", git_cmd(), "rev-list", "--header", - ($arg ? ($arg) : ()), + @args, ("--max-count=" . $maxcount), ("--skip=" . $skip), @extra_options, @@ -2235,6 +2293,7 @@ sub git_get_heads_list { my ($hash, $name, $title) = split(' ', $refinfo, 3); my ($committer, $epoch, $tz) = ($committerinfo =~ /^(.*) ([0-9]+) (.*)$/); + $ref_item{'fullname'} = $name; $name =~ s!^refs/heads/!!; $ref_item{'name'} = $name; @@ -2272,6 +2331,7 @@ sub git_get_tags_list { my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6); my ($creator, $epoch, $tz) = ($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/); + $ref_item{'fullname'} = $name; $name =~ s!^refs/tags/!!; $ref_item{'type'} = $type; @@ -2528,6 +2588,10 @@ EOF $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . " search:\n", $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + "" . + $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', + -checked => $search_use_regexp) . + "" . "" . $cgi->end_form() . "\n"; } @@ -3545,7 +3609,7 @@ sub git_shortlog_body { $from = 0 unless defined $from; $to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to); - print "\n"; + print "
\n"; my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my %co = %{$commitlist->[$i]}; @@ -3591,7 +3655,7 @@ sub git_history_body { $from = 0 unless defined $from; $to = $#{$commitlist} unless (defined $to && $to <= $#{$commitlist}); - print "
\n"; + print "
\n"; my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my %co = %{$commitlist->[$i]}; @@ -3651,7 +3715,7 @@ sub git_tags_body { $from = 0 unless defined $from; $to = $#{$taglist} if (!defined $to || $#{$taglist} < $to); - print "
\n"; + print "
\n"; my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $taglist->[$i]; @@ -3692,8 +3756,8 @@ sub git_tags_body { "
" . " | " . $cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'}); if ($tag{'reftype'} eq "commit") { - print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . - " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log"); + print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'fullname'})}, "shortlog") . + " | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'fullname'})}, "log"); } elsif ($tag{'reftype'} eq "blob") { print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw"); } @@ -3714,7 +3778,7 @@ sub git_heads_body { $from = 0 unless defined $from; $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to); - print "\n"; + print "
\n"; my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my $entry = $headlist->[$i]; @@ -3728,13 +3792,13 @@ sub git_heads_body { $alternate ^= 1; print "\n" . ($curr ? "\n" . "\n" . ""; } @@ -3751,7 +3815,7 @@ sub git_search_grep_body { $from = 0 unless defined $from; $to = $#{$commitlist} if (!defined $to || $#{$commitlist} < $to); - print "
$ref{'age'}" : "") . - $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}), + $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'}), -class => "list name"},esc_html($ref{'name'})) . "" . - $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " . - $cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " . - $cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") . + $cgi->a({-href => href(action=>"shortlog", hash=>$ref{'fullname'})}, "shortlog") . " | " . + $cgi->a({-href => href(action=>"log", hash=>$ref{'fullname'})}, "log") . " | " . + $cgi->a({-href => href(action=>"tree", hash=>$ref{'fullname'}, hash_base=>$ref{'name'})}, "tree") . "
\n"; + print "
\n"; my $alternate = 1; for (my $i = $from; $i <= $to; $i++) { my %co = %{$commitlist->[$i]}; @@ -3769,24 +3833,32 @@ sub git_search_grep_body { print "\n" . "\n" . "\n" . "\n" . "\n"; @@ -3892,7 +3964,7 @@ sub git_summary { git_print_page_nav('summary','', $head); print "
 
\n"; - print "
$co{'age_string_date'}" . $author . "" . - $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), -class => "list subject"}, - chop_and_escape_str($co{'title'}, 50) . "
"); + $cgi->a({-href => href(action=>"commit", hash=>$co{'id'}), + -class => "list subject"}, + chop_and_escape_str($co{'title'}, 50) . "
"); my $comment = $co{'comment'}; foreach my $line (@$comment) { - if ($line =~ m/^(.*)($search_regexp)(.*)$/i) { - my $lead = esc_html($1) || ""; - $lead = chop_str($lead, 30, 10); - my $match = esc_html($2) || ""; - my $trail = esc_html($3) || ""; - $trail = chop_str($trail, 30, 10); - my $text = "$lead$match$trail"; - print chop_str($text, 80, 5) . "
\n"; + if ($line =~ m/^(.*?)($search_regexp)(.*)$/i) { + my ($lead, $match, $trail) = ($1, $2, $3); + $match = chop_str($match, 70, 5, 'center'); + my $contextlen = int((80 - length($match))/2); + $contextlen = 30 if ($contextlen > 30); + $lead = chop_str($lead, $contextlen, 10, 'left'); + $trail = chop_str($trail, $contextlen, 10, 'right'); + + $lead = esc_html($lead); + $match = esc_html($match); + $trail = esc_html($trail); + + print "$lead$match$trail
"; } } print "
" . $cgi->a({-href => href(action=>"commit", hash=>$co{'id'})}, "commit") . " | " . + $cgi->a({-href => href(action=>"commitdiff", hash=>$co{'id'})}, "commitdiff") . + " | " . $cgi->a({-href => href(action=>"tree", hash=>$co{'tree'}, hash_base=>$co{'id'})}, "tree"); print "
\n" . + print "
\n" . "\n" . "\n"; if (defined $cd{'rfc2822'}) { @@ -3913,8 +3985,10 @@ sub git_summary { if (-s "$projectroot/$project/README.html") { if (open my $fd, "$projectroot/$project/README.html") { - print "
readme
\n"; + print "
readme
\n" . + "
\n"; print $_ while (<$fd>); + print "\n
\n"; # class="readme" close $fd; } } @@ -3966,7 +4040,7 @@ sub git_tag { git_print_header_div('commit', esc_html($tag{'name'}), $hash); print "
\n" . - "
description" . esc_html($descr) . "
owner" . esc_html($owner) . "
\n" . + "
\n" . "\n" . "\n" . "
object" . $cgi->a({-class => "list", -href => href(action=>$tag{'type'}, hash=>$tag{'object'})}, @@ -4286,7 +4360,7 @@ sub git_blob { open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or die_error(undef, "Couldn't cat $file_name, $hash"); my $mimetype = blob_mimetype($fd, $file_name); - if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)!) { + if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) { close $fd; return git_blob_plain($mimetype); } @@ -4327,16 +4401,7 @@ sub git_blob { } git_print_page_path($file_name, "blob", $hash_base); print "
\n"; - if ($mimetype =~ m!^text/!) { - my $nr; - while (my $line = <$fd>) { - chomp $line; - $nr++; - $line = untabify($line); - printf "
%4i %s
\n", - $nr, $nr, $nr, esc_html($line, -nbsp=>1); - } - } elsif ($mimetype =~ m!^image/!) { + if ($mimetype =~ m!^image/!) { print qq!$file_name"blob_plain", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name) . qq!" />\n!; + } else { + my $nr; + while (my $line = <$fd>) { + chomp $line; + $nr++; + $line = untabify($line); + printf "
%4i %s
\n", + $nr, $nr, $nr, esc_html($line, -nbsp=>1); + } } close $fd or print "Reading blob failed.\n"; @@ -4406,7 +4480,7 @@ sub git_tree { } git_print_page_path($file_name, 'tree', $hash_base); print "
\n"; - print "\n"; + print "
\n"; my $alternate = 1; # '..' (top directory) link if possible if (defined $hash_base && @@ -4628,7 +4702,7 @@ sub git_commit { git_print_header_div('tree', esc_html($co{'title'}) . $ref, $co{'tree'}, $hash); } print "
\n" . - "
\n"; + "
\n"; print "\n". "" . "
author" . esc_html($co{'author'}) . "
$ad{'rfc2822'}"; @@ -5044,16 +5118,15 @@ sub git_commitdiff { -expires => $expires, -content_disposition => 'inline; filename="' . "$filename" . '"'); my %ad = parse_date($co{'author_epoch'}, $co{'author_tz'}); - print <self_url() . "\n\n"; foreach my $line (@{$co{'comment'}}) { - print "$line\n"; + print to_utf8($line) . "\n"; } print "---\n\n"; } @@ -5107,7 +5180,7 @@ sub git_history { $ftype = git_get_type($hash); } - my @commitlist = parse_commits($hash_base, 101, (100 * $page), "--full-history", $file_name); + my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history"); my $paging_nav = ''; if ($page > 0) { @@ -5189,14 +5262,17 @@ sub git_search { } elsif ($searchtype eq 'committer') { $greptype = "--committer="; } - $greptype .= $search_regexp; - my @commitlist = parse_commits($hash, 101, (100 * $page), $greptype); + $greptype .= $searchtext; + my @commitlist = parse_commits($hash, 101, (100 * $page), undef, + $greptype, '--regexp-ignore-case', + $search_use_regexp ? '--extended-regexp' : '--fixed-strings'); my $paging_nav = ''; if ($page > 0) { $paging_nav .= $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype)}, + searchtext=>$searchtext, + searchtype=>$searchtype)}, "first"); $paging_nav .= " ⋅ " . $cgi->a({-href => href(-replay=>1, page=>$page-1), @@ -5227,14 +5303,15 @@ sub git_search { git_print_page_nav('','', $hash,$co{'tree'},$hash); git_print_header_div('commit', esc_html($co{'title'}), $hash); - print "\n"; + print "
\n"; my $alternate = 1; $/ = "\n"; my $git_command = git_cmd_str(); my $searchqtext = $searchtext; $searchqtext =~ s/'/'\\''/; + my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : ''; open my $fd, "-|", "$git_command rev-list $hash | " . - "$git_command diff-tree -r --stdin -S\'$searchqtext\'"; + "$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags"; undef %co; my @files; while (my $line = <$fd>) { @@ -5294,11 +5371,13 @@ sub git_search { git_print_page_nav('','', $hash,$co{'tree'},$hash); git_print_header_div('commit', esc_html($co{'title'}), $hash); - print "
\n"; + print "
\n"; my $alternate = 1; my $matches = 0; $/ = "\n"; - open my $fd, "-|", git_cmd(), 'grep', '-n', '-i', '-E', $searchtext, $co{'tree'}; + open my $fd, "-|", git_cmd(), 'grep', '-n', + $search_use_regexp ? ('-E', '-i') : '-F', + $searchtext, $co{'tree'}; my $lastfile = ''; while (my $line = <$fd>) { chomp $line; @@ -5328,7 +5407,7 @@ sub git_search { print "
Binary file
\n"; } else { $ltext = untabify($ltext); - if ($ltext =~ m/^(.*)($searchtext)(.*)$/i) { + if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) { $ltext = esc_html($1, -nbsp=>1); $ltext .= ''; $ltext .= esc_html($2, -nbsp=>1); @@ -5363,27 +5442,31 @@ sub git_search_help { git_header_html(); git_print_page_nav('','', $hash,$hash,$hash); print <Pattern is by default a normal string that is matched precisely (but without +regard to case, except in the case of pickaxe). However, when you check the re checkbox, +the pattern entered is recognized as the POSIX extended +regular expression (also case +insensitive).

commit
-
The commit messages and authorship information will be scanned for the given string.
+
The commit messages and authorship information will be scanned for the given pattern.
EOT my ($have_grep) = gitweb_check_feature('grep'); if ($have_grep) { print <grep
All files in the currently selected tree (HEAD unless you are explicitly browsing - a different one) are searched for the given -regular expression -(POSIX extended) and the matches are listed. On large -trees, this search can take a while and put some strain on the server, so please use it with -some consideration.
+ a different one) are searched for the given pattern. On large trees, this search can take +a while and put some strain on the server, so please use it with some consideration. Note that +due to git-grep peculiarity, currently if regexp mode is turned off, the matches are +case-sensitive. EOT } print <author -
Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.
+
Name and e-mail of the change author and date of birth of the patch will be scanned for the given pattern.
committer
-
Name and e-mail of the committer and date of commit will be scanned for the given string.
+
Name and e-mail of the committer and date of commit will be scanned for the given pattern.
EOT my ($have_pickaxe) = gitweb_check_feature('pickaxe'); if ($have_pickaxe) { @@ -5391,7 +5474,8 @@ EOT
pickaxe
All commits that caused the string to appear or disappear from any file (changes that added, removed or "modified" the string) will be listed. This search can take a while and -takes a lot of strain on the server, so please use it wisely.
+takes a lot of strain on the server, so please use it wisely. Note that since you may be +interested even in changes just changing the case as well, this search is case sensitive. EOT } print "
\n"; @@ -5442,7 +5526,7 @@ sub git_feed { # log/feed of current (HEAD) branch, log of given branch, history of file/directory my $head = $hash || 'HEAD'; - my @commitlist = parse_commits($head, 150, 0, undef, $file_name); + my @commitlist = parse_commits($head, 150, 0, $file_name); my %latest_commit; my %latest_date; @@ -5562,7 +5646,7 @@ XML or next; # print element (entry, item) - my $co_url = href(-full=>1, action=>"commit", hash=>$commit); + my $co_url = href(-full=>1, action=>"commitdiff", hash=>$commit); if ($format eq 'rss') { print "\n" . "" . esc_html($co{'title'}) . "\n" .