source 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. #!/usr/bin/perl
  2. # $Id: source,v 1.18 2006/12/07 04:59:38 reed%reedloden.com Exp $
  3. # source -- Present sourcecode as html, complete with references
  4. #
  5. # Arne Georg Gleditsch <argggh@ifi.uio.no>
  6. # Per Kristian Gjermshus <pergj@ifi.uio.no>
  7. #
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. ######################################################################
  23. use lib 'lib';
  24. use Local;
  25. use SimpleParse;
  26. use LXR::Common;
  27. use LXR::Config;
  28. use Cwd;
  29. use File::Basename;
  30. my $force;
  31. sub diricon {
  32. my ($img, $link);
  33. if ($filename eq '..') {
  34. $img = "/icons/back.gif";
  35. $link = $parentdir;
  36. } else {
  37. my $dir = $Path->{'real'}.$filename;
  38. $dir =~ s#/$##;
  39. if (-l $dir) {
  40. $img = "/icons/forward.gif";
  41. } else {
  42. $img = "/icons/folder.gif";
  43. }
  44. $link = $Path->{'virt'}.$filename;
  45. }
  46. $link =~ s/&/&amp;/g;
  47. $link =~ s/"/&quot;/g;
  48. $link =~ s/</&lt;/g;
  49. $link =~ s/>/&gt;/g;
  50. return "<a href=\"$link\"><img class=\"dir icon\" align=\"absbottom\" border=\"0\" src=\"$img\"></a>";
  51. }
  52. sub dirnamehtml {
  53. if ($filename eq '..') {
  54. return(&fileref("Parent directory", $parentdir));
  55. } else {
  56. return(&fileref($filename, $Path->{'virt'}.$filename));
  57. }
  58. }
  59. sub resolvelink {
  60. my $almost = readlink(shift);
  61. my $rel = shift;
  62. unless ($almost =~ m{^/}) {
  63. $almost = $rel . '/' . $almost;
  64. }
  65. return $almost;
  66. }
  67. sub fileicon {
  68. my $img;
  69. my $tag = 'img';
  70. my $realf = $Path->{'real'}.$filename;
  71. if (-l $realf && !-e resolvelink($realf, $Path->{'real'})) {
  72. $img = "/icons/broken.gif";
  73. } elsif (!-r $realf) {
  74. $img = "/icons/generic.sec.gif";
  75. } elsif ($filename =~ /^.*\.[ch]$/) {
  76. $img = "/icons/c.gif";
  77. } elsif ($filename =~ /^.*\.(idl|cpp?|c[cs]|hh|java|s)$/) {
  78. # TODO: Find a nice icon for c++ files (KDE?)
  79. $img = "/icons/c.gif";
  80. } elsif (isImage($filename, 1)) {
  81. $img = "/icons/image2.gif";
  82. my $s = (-s $realf);
  83. if ($s < 10<<10) {
  84. $img = "$filename?raw=1";
  85. if ($filename =~ /\.svg$/i) {
  86. my $ctype = 'image/svg+xml';
  87. $img .= "&ctype=$ctype";
  88. $tag = "embed type='$ctype'";
  89. }
  90. }
  91. } else {
  92. $img = "/icons/text.gif";
  93. }
  94. my $link = $Path->{'virt'} . $filename;
  95. $link =~ s/&/&amp;/g;
  96. $link =~ s/"/&quot;/g;
  97. $link =~ s/</&lt;/g;
  98. $link =~ s/>/&gt;/g;
  99. return "<a href=\"$link\"><$tag class=\"file icon\" align=\"absbottom\" border=\"0\" src=\"$img\"></a>";
  100. }
  101. sub filename {
  102. my $string =
  103. &fileref($filename, $Path->{'virt'}.$filename);
  104. if (isHTML($filename) || isCSS($filename) || isREADME($filename)) {
  105. $string =~ s/(a href=".*)(")/$1?force=1$2/g;
  106. }
  107. return $string;
  108. }
  109. sub filesize {
  110. my $templ = shift;
  111. my $s = (-s $Path->{'real'}.$filename);
  112. my $str;
  113. if ($s < 1<<10) {
  114. $str = "$s";
  115. } else {
  116. # if ($s < 1<<20) {
  117. $str = ($s>>10) . "k";
  118. # } else {
  119. # $str = ($s>>20) . "M";
  120. # }
  121. }
  122. return(&expandtemplate($templ,
  123. ('bytes', sub {return($str)}),
  124. ('kbytes', sub {return($str)}),
  125. ('mbytes', sub {return($str)})
  126. ));
  127. }
  128. sub modtime {
  129. my $current_time = time;
  130. my $realf = $Path->{'real'}.$filename;
  131. return "Missing" unless -e $realf;
  132. my $file_time = (stat($realf))[9];
  133. my @t = gmtime($file_time);
  134. my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
  135. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
  136. my ($sec, $min, $hour, $mday, $mon, $year) = @t;
  137. $year += 1900;
  138. $mon = $months[$mon];
  139. my $one_hour = (60 * 60);
  140. my $six_months = $one_hour * 24 * int(365/2);
  141. if ($file_time <= ($current_time - $six_months) ||
  142. $file_time >= ($current_time + $one_hour)) {
  143. return sprintf("%s %2d %04d", $mon, $mday, $year);
  144. } else {
  145. return sprintf("%s %2d %02d:%02d", $mon, $mday, $hour, $min);
  146. }
  147. }
  148. sub bgcolor {
  149. if (!($line % 3)) {
  150. $color = ($color eq "#EEEEEE")? "#FFFFFF": "#EEEEEE";
  151. }
  152. return($color);
  153. }
  154. sub direxpand {
  155. my $templ = shift;
  156. my $direx = '';
  157. local $line = 0;
  158. local $filename;
  159. local $color="#FFFFFF";
  160. my $virtpath = $Path->{'virt'};
  161. my $realpath = $Path->{'real'};
  162. foreach $filename (@dirs) {
  163. $line++;
  164. $direx .= &expandtemplate($templ,
  165. ('iconlink', \&diricon),
  166. ('namelink', \&dirnamehtml),
  167. ('filesize', sub {return('-')}),
  168. ('modtime', \&modtime),
  169. ('bgcolor', \&bgcolor),
  170. ('description', \&descexpand));
  171. }
  172. foreach $filename (@files) {
  173. $line++;
  174. next if $filename =~ /^.*\.[oa]$|^core$|^00-INDEX$/;
  175. $direx .= &expandtemplate($templ,
  176. ('iconlink', \&fileicon),
  177. ('namelink', \&filename),
  178. ('filesize', \&filesize),
  179. ('modtime', \&modtime),
  180. ('bgcolor', \&bgcolor),
  181. ('description', \&fdescexpand));
  182. }
  183. return($direx);
  184. }
  185. sub unreadable {
  186. my ($realf, $reald) = @_;
  187. unless ($reald) {
  188. $realf =~ m{^(.*)/};
  189. $reald = $1;
  190. }
  191. return " links to a file that does not exist." if -l $realf && !-e resolvelink($realf, $reald);
  192. return " does not exist." unless -e $realf;
  193. return " is not readable." unless -r $realf;
  194. return " could not be read for an unknown reason.";
  195. }
  196. sub printdir {
  197. my $template;
  198. my $index;
  199. local %index;
  200. local @dirs;
  201. local @files;
  202. local $parentdir;
  203. $template = "<ul>\n\$files{\n<li>\$iconlink \$namelink\n}</ul>\n";
  204. if ($Conf->htmldir) {
  205. unless (open(TEMPL, $Conf->htmldir)) {
  206. &warning("Template ".$Conf->htmldir.unreadable($Conf->htmldir), 'htmldir');
  207. } else {
  208. local $/;
  209. $template = <TEMPL>;
  210. close(TEMPL);
  211. }
  212. }
  213. if (opendir(DIR, $Path->{'real'})) {
  214. foreach $f (sort {lc $a cmp lc $b} (grep/^[^\.]/,readdir(DIR))) {
  215. if (-d $Path->{'real'}.$f) {
  216. if ($f =~ /(^CVS|^\.svn|_files)$/) {
  217. #skip it
  218. } else {
  219. push(@dirs,"$f/");
  220. }
  221. } else {
  222. push(@files,$f);
  223. }
  224. }
  225. closedir(DIR);
  226. } else {
  227. print("<p align=center>\n<i>This directory".unreadable($Path->{'real'})."</i>\n");
  228. if ($Path->{'real'} =~ m#(.+[^/])[/]*$#) {
  229. if (-e $1) {
  230. &warning("Unable to open ".$Conf->{'treename'}.$Path->{'virt'}, 'virt');
  231. }
  232. }
  233. return;
  234. }
  235. if (-f $Path->{'real'}."00-INDEX") {
  236. open(INDEX,$Path->{'real'}."00-INDEX") ||
  237. &warning("Existing \"00-INDEX\" could not be opened.", '00-index');
  238. local $/;
  239. $index = <INDEX>;
  240. %index = $index =~ /\n(\S*)\s*\n\t-\s*([^\n]*)/gs;
  241. }
  242. if ($Path->{'virt'} =~ m#^(.*/)[^/]*/$#) {
  243. $parentdir = $1;
  244. unshift(@dirs, '..');
  245. }
  246. # print the description of the current directory
  247. dirdesc($Path->{'virt'});
  248. #print the listing itself
  249. print(&expandtemplate($template,
  250. ('files', \&direxpand)));
  251. }
  252. sub isHTML {
  253. return 0 if $force;
  254. my $file = shift;
  255. return ($file =~ /\.html?$/);
  256. }
  257. sub isCSS {
  258. return 0 if $force;
  259. my $file = shift;
  260. return ($file =~ /stylesheet\.(css)$/) ||
  261. (($file =~ /\.(css)$/) && $ENV{HTTP_ACCEPT} !~ 'text/html');
  262. }
  263. sub isImage {
  264. return 0 if $force;
  265. my ($file, $ignoreAccept) = @_;
  266. return 0 unless $ignoreAccept || $ENV{HTTP_ACCEPT} !~ 'text/html';
  267. return $file =~ /\.([jmp][pnm]e?g|gif|ico)$/i;
  268. }
  269. sub isREADME {
  270. return 0 if $force;
  271. my $file = shift;
  272. return $file =~ /README$/i;
  273. }
  274. sub noWrap {
  275. my $file = shift;
  276. return $HTTP->{'param'}->{'raw'} ||
  277. isHTML($file) ||
  278. isImage($file) ||
  279. isCSS($file);
  280. }
  281. sub printfile {
  282. my $string;
  283. my $file = $Path->{'file'};
  284. unless ($file) {
  285. &printdir;
  286. } else {
  287. my ($openresult, $cat);
  288. if (defined $HTTP->{'param'}->{'rev'} &&
  289. $HTTP->{'param'}->{'rev'} =~ /([a-f0-9]+)/i) {
  290. $cat = 'cat -r '.$1;
  291. }
  292. if ($cat) {
  293. my $dir = getcwd;
  294. chdir $Path->{'real'};
  295. my $verb;
  296. if (-d '.svn') {
  297. $verb = 'svn';
  298. } else {
  299. for my $vcs (qw(hg bzr)) {
  300. unless (system("$vcs st $file")) {
  301. $verb = $vcs;
  302. last;
  303. }
  304. }
  305. }
  306. if ($verb) {
  307. my $command = "$verb $cat ".$Path->{'realf'}.' |';
  308. $openresult = open(SRCFILE, $command);
  309. }
  310. chdir $dir;
  311. } else {
  312. $openresult = open(SRCFILE, $Path->{'realf'});
  313. }
  314. if ($openresult) {
  315. if (0) {
  316. print "<!--
  317. ";
  318. foreach my $key (keys %ENV)
  319. {
  320. print "export $key=".'"'.$ENV{$key}.'"'."
  321. ";
  322. }
  323. print "-->
  324. ";
  325. }
  326. my $kind = getMimeType($file);
  327. if (isHTML($file)) {
  328. local $/ = undef;
  329. print <SRCFILE>;
  330. } elsif (isCSS($file)) {
  331. $head = "Content-Type: text/css\r\n\r\n";
  332. print $head;
  333. local $/ = undef;
  334. my $body = <SRCFILE>;
  335. print $body;
  336. } elsif (isImage($file)) {
  337. my $kind = 'x-unknown';
  338. $kind = 'jpeg' if $file =~ /\.jpe?g$/i;
  339. $kind = 'pjepg' if $file =~ /\.pjpe?g$/i;
  340. $kind = 'gif' if $file =~ /\.gif$/i;
  341. $kind = 'png' if $file =~ /\.[jp]ng$/i;
  342. $kind = 'bitmap' if $file =~ /\.bmp$/i;
  343. $kind = 'svg+xml' if $file =~ /\.svg$/i;
  344. $kind = 'x-icon' if $file =~ /\.(ico|ani|xpm)$/i;
  345. print
  346. $head = "Content-Type: image/$kind\r\n\r\n";
  347. local $/ = undef;
  348. my $body = <SRCFILE>;
  349. print $body;
  350. } elsif (!$force && isREADME($file)) {
  351. print("<pre lang='en'>");
  352. while(<SRCFILE>) {
  353. $string = $string . $_;
  354. }
  355. print(markupstring($string, $Path->{'virt'}));
  356. print("</pre>");
  357. } elsif ($skip_wrap) {
  358. local $/ = undef;
  359. print <SRCFILE>;
  360. } else {
  361. if (-e "$Path->{'root'}/client.mk" && ($file =~ /\.idl$/)) {
  362. my $base = basename($file, ".idl");
  363. my $dir = $Path->{'virt'};
  364. $dir =~ s#^/([^/]+)(.*)#$1#;
  365. my $doxRoot = 'http://doxygen.db48x.net/mozilla/html/';
  366. my $doxURL = "${doxRoot}interface${base}";
  367. # safari 1 gives alert() if it finds an <object> for svg and has no plugin
  368. # ff2 gives a non grown image for <object> for svg, i.e. so badly truncated
  369. # that no one could possibly want it
  370. print qq#
  371. <p>Inheritance diagram for $base:</P>
  372. <p align="center">
  373. <!--
  374. <object data="${doxURL}__inherit__graph.svg" type="image/svg+xml" border="0">
  375. <param name="src" value="${doxURL}__inherit__graph.svg">
  376. -->
  377. <a href="${doxURL}__inherit__graph.svg">
  378. <img src="${doxURL}__inherit__graph.png" alt="Inheritance graph" border="0">
  379. </a>
  380. </p>
  381. <p>Collaboration diagram for $base:</p>
  382. <p align="center">
  383. <a href="${doxURL}__coll__graph.svg">
  384. <img src="${doxURL}__coll__graph.png" alt="Collaboration graph" border="0">
  385. </a>
  386. </p>
  387. <p align="center">
  388. [ <a href="${doxURL}.html"><i>$base</i> Interface Reference</a> |
  389. <a href="${doxRoot}graph_legend.html">Graph Legend</a> ]
  390. </p>
  391. #;
  392. }
  393. print("<pre lang='en'>");
  394. &markupfile(\*SRCFILE, $Path, $file,
  395. sub { print shift }, $force);
  396. print("</pre>");
  397. }
  398. close(SRCFILE);
  399. } else {
  400. print("<p align=center>\n<i>This file".unreadable(url_quote($Path->{'realf'}))."</i>\n");
  401. if (-l $Path->{'realf'}) {
  402. print('<br><tt>'.unreadable(url_quote(readlink($Path->{'realf'})))."</tt></p>\n");
  403. }
  404. $rev = "&rev=$rev" if ($rev ne '');
  405. my $hint = $Path->{'virt'};
  406. if (defined $hint && $hint ne '/') {
  407. $hint = clean_hint($hint);
  408. $hint = "&amp;hint=$hint";
  409. } else {
  410. $hint = '';
  411. }
  412. my $markstring = '';
  413. if (defined $HTTP->{'param'}->{'mark'}) {
  414. my $marks = clean_mark($HTTP->{'param'}->{'mark'});
  415. if ($marks ne '') {
  416. $markstring = "&amp;mark=$marks";
  417. }
  418. }
  419. print("<p>Maybe you can <a href='" .
  420. $Conf->baseurl .
  421. "/find?string=/" .
  422. url_quote($file) .
  423. $hint .
  424. $markstring .
  425. $rev .
  426. "'>find it elsewhere</a>.\n");
  427. if (-f $Path->{'realf'}) {
  428. &warning("Unable to open ".$Conf->{'treename'}.$Path->{'virtf'}, 'virtf');
  429. }
  430. }
  431. }
  432. }
  433. ($Conf, $HTTP, $Path, $head) = &init($0);
  434. my $skip_wrap = 0;
  435. sub http_header_stuff {
  436. my $exit = 0;
  437. my $tree = $HTTP->{'param'}->{'tree'};
  438. #only allow access to registered roots
  439. #for anything else redirect to the directory containing source
  440. unless (defined $Path->{'root'}) {
  441. #if we're accessed as source/ then we need to be a bit more directed.
  442. my $path = $ENV{'PATH_INFO'};
  443. $path =~ s|[^/]+||g;
  444. $path =~ s{/}{../}g;
  445. my $prefix = $path || './';
  446. my $refresh = "Refresh: 0; url=$prefix
  447. ";
  448. $head .= "$refresh
  449. ";
  450. $exit = 1;
  451. } elsif (defined $Path->{'rewriteurl'}) {
  452. my $path = $ENV{'PATH_INFO'};
  453. my $refresh = "Refresh: 0; url=$rewriteurl$path
  454. ";
  455. $head .= "$refresh
  456. ";
  457. $exit = 1;
  458. }
  459. if (($ENV{'PATH_INFO'} !~ m|/$|) && (-d $Path->{'realf'})) {
  460. # access to rootname/source needs to be redirected to rootname/source/
  461. my $entryname = 'source';
  462. if ($ENV{'PATH_INFO'} ne '') {
  463. my @dirs = split m|/|, $Path->{'realf'};
  464. $entryname = $dirs[$#dirs];
  465. }
  466. my $refresh = "Refresh: 0; url=$entryname/
  467. ";
  468. $head .= "$refresh
  469. ";
  470. $exit = 1;
  471. }
  472. $force = $HTTP->{'param'}->{'force'};
  473. $force = (defined $force && $force =~ /1|on|yes/ ? 1 : 0);
  474. unless ($exit) {
  475. my $baseurl = $Conf->{baseurl};
  476. my $localurl = $baseurl . '/source' . $ENV{'PATH_INFO'};
  477. $localurl = url_quote($localurl);
  478. $localurl =~ s/%3A/:/;
  479. $localurl =~ m{(^.*/)/*[^/]+/*(?:|\?.*)$};
  480. my $parenturl = $1;
  481. $head .=
  482. 'Link: <' . $localurl . '?force=1>; rel="First"; title="Marked up"
  483. Link: <' . $localurl . '?raw=1>; rel="Last"; title="Raw"
  484. ';
  485. }
  486. if (defined($HTTP->{'param'}->{'raw'})) {
  487. unless (open(RAW, "<", $Path->{'realf'})) {
  488. $Path->{'realf'} =~ m{/([-a-z0-9_.]+)$}i;
  489. print "Status: 404 File Not Found
  490. Link: <" . $Conf->{baseurl} . "/find?string=$1>; rel='Contents'; title='Find file'
  491. Content-Type: text/html
  492. ";
  493. my $virtf = $Path->{'virtf'};
  494. $virtf =~ s/</&lt;/g;
  495. print "<h1>File Not Found</h1>
  496. <h4><em>Couldn't open $Conf->{'treename'}:$virtf";
  497. exit;
  498. }
  499. print "$head
  500. ";
  501. while (<RAW>) {
  502. print;
  503. }
  504. close(RAW);
  505. exit;
  506. }
  507. $exit = 1 if $ENV{'REQUEST_METHOD'} eq 'HEAD';
  508. #if the file is html then don't print a header because the file
  509. #has its own -dme
  510. my $strange_inexplicable_check = (-f $Path->{'real'}.$Path->{'file'});
  511. $skip_wrap = $Path->{'file'} && noWrap($Path->{'file'});
  512. print "$head
  513. " if (!$Path->{'file'} || isHTML($Path->{'file'}) || !$skip_wrap);
  514. exit if $exit;
  515. }
  516. &http_header_stuff;
  517. sub html_header_stuff {
  518. if (
  519. !$skip_wrap
  520. ) {
  521. if ($Path->{'file'}) {
  522. &makeheader('source');
  523. } else {
  524. &makeheader('sourcedir');
  525. }
  526. }
  527. }
  528. &html_header_stuff;
  529. &printfile;
  530. sub footer_stuff {
  531. if (
  532. !$skip_wrap
  533. ) {
  534. if ($Path->{'file'}) {
  535. &makefooter('source');
  536. } else {
  537. &makefooter('sourcedir');
  538. }
  539. }
  540. }
  541. &footer_stuff;
  542. 1;