# $Id: Common.pm,v 1.23 2001-08-31 00:46:09 myk%mozilla.org Exp $ package LXR::Common; use DB_File; use lib '../..'; use Local; require Exporter; @ISA = qw(Exporter); @EXPORT = qw($Path &warning &fatal &abortall &fflush &urlargs &fileref &idref &htmlquote &freetextmarkup &markupfile &markspecials &htmlquote &freetextmarkup &markupstring &init &glimpse_init &makeheader &makefooter &expandtemplate); $wwwdebug = 1; $SIG{__WARN__} = 'warning'; $SIG{__DIE__} = 'fatal'; @cterm = ('atom', '\\\\.', '', 'comment', '/\*', '\*/', 'comment', '//', "\n", 'string', '"', '"', 'string', "'", "'", 'include', '#include', "\n"); sub warning { print(STDERR "[",scalar(localtime),"] warning: $_[0]\n"); print("
\n".
#"');
&linetag($virtp.$fname, $line++));
($btype, $frag) = &SimpleParse::nextfrag;
while (defined($frag)) {
&markspecials($frag);
if ($btype eq 'comment') {
# Comment
# Convert mail adresses to mailto:
&freetextmarkup($frag);
$frag = "$frag";
$frag =~ s#\n#\n#g;
} elsif ($btype eq 'string') {
# String
$frag = "$frag";
} elsif ($btype eq 'include') {
# Include directive
$frag =~ s#(\")(.*)(\")#
$1.&fileref($2, $virtp.$2).$3#e;
$frag =~ s#(\0<)(.*)(\0>)#
$1.
&fileref($2, $Conf->mappath($Conf->incprefix."/$2")).
$3#e;
} else {
# Code
$frag =~ s#(^|[^a-zA-Z_\#0-9])([a-zA-Z_~][a-zA-Z0-9_]*)\b#
$1.(defined($xref{$2}) ? &idref($2,$2) : $2)#ge;
}
&htmlquote($frag);
$frag =~ s/\n/"\n".&linetag($virtp.$fname, $line++)/ge;
&$outfun($frag);
($btype, $frag) = &SimpleParse::nextfrag;
}
# &$outfun("\n");
untie(%xref);
} elsif ($fname =~ /\.(gif|jpg|jpeg|pjpg|pjpeg|xbm)$/i) {
&$outfun("");
&$outfun("| Image: | "); &$outfun("");
&$outfun(" |
|---|
");
} elsif ($fname eq 'CREDITS') {
while (<$INFILE>) {
&SimpleParse::untabify($_);
&markspecials($_);
&htmlquote($_);
s/^N:\s+(.*)/$1<\/strong>/gm;
s/^(E:\s+)(\S+@\S+)/$1$2<\/a>/gm;
s/^(W:\s+)(.*)/$1$2<\/a>/gm;
# &$outfun("<\/a>".$_);
&$outfun(&linetag($virtp.$fname, $.).$_);
}
} else {
my $first_line = <$INFILE>;
my $is_binary = -1;
$_ = $first_line;
if ( m/^\#!/ ) { # it's a script
$is_binary = 0;
} elsif ( m/-\*-.*mode:/i ) { # has an emacs mode spec
$is_binary = 0;
} elsif (length($_) > 132) { # no linebreaks
$is_binary = 1;
} elsif ( m/[\000-\010\013\014\016-\037\200-Ÿ]/ ) { # ctrl or ctrl+
$is_binary = 1;
} else { # no idea, but assume text.
$is_binary = 0;
}
if ( $is_binary ) {
&$outfun("");
&$outfun("");
} else {
$_ = $first_line;
do {
&SimpleParse::untabify($_);
&markspecials($_);
&htmlquote($_);
&freetextmarkup($_);
# &$outfun("<\/a>".$_);
&$outfun(&linetag($virtp.$fname, $.).$_);
} while (<$INFILE>);
}
}
}
sub fixpaths {
$Path->{'virtf'} = '/'.shift;
$Path->{'root'} = $Conf->sourceroot;
while ($Path->{'virtf'} =~ s#/[^/]+/\.\./#/#g) {
}
$Path->{'virtf'} =~ s#/\.\./#/#g;
$Path->{'virtf'} .= '/' if (-d $Path->{'root'}.$Path->{'virtf'});
$Path->{'virtf'} =~ s#//+#/#g;
($Path->{'virt'}, $Path->{'file'}) = $Path->{'virtf'} =~ m#^(.*/)([^/]*)$#;
$Path->{'real'} = $Path->{'root'}.$Path->{'virt'};
$Path->{'realf'} = $Path->{'root'}.$Path->{'virtf'};
@pathelem = $Path->{'virtf'} =~ /([^\/]+$|[^\/]+\/)/g;
$fpath = '';
foreach (@pathelem) {
$fpath .= $_;
push(@addrelem, $fpath);
}
unshift(@pathelem, $Conf->sourcerootname.'/');
unshift(@addrelem, "");
foreach (0..$#pathelem) {
if (defined($addrelem[$_])) {
# jwz: put a space after each / in the banner so that it's possible
# for the pathnames to wrap. The tag ought to do this, but
# it is ignored when sizing table cells, so we have to use a real
# space. It's somewhat ugly to have these spaces be visible, but
# not as ugly as getting a horizontal scrollbar...
#
$Path->{'xref'} .= &fileref($pathelem[$_], "/$addrelem[$_]") . " ";
} else {
$Path->{'xref'} .= $pathelem[$_];
}
}
$Path->{'xref'} =~ s#/ #/#gi;
}
sub glimpse_init {
$HTTP->{'this_url'} = join('', 'http://',
$ENV{'SERVER_NAME'},
':', $ENV{'SERVER_PORT'},
$ENV{'SCRIPT_NAME'},
$ENV{'PATH_INFO'},
'?', $ENV{'QUERY_STRING'});
my @a;
if ($ENV{'QUERY_STRING'} =~ s/®exp=on//) {
$Conf->{'regexp'} = 'on';
} else {
$ENV{'QUERY_STRING'} =~ s/®exp=off//;
$Conf->{'regexp'} = 'off';
}
foreach ($ENV{'QUERY_STRING'} =~ /([^;&=]+)(?:=([^;&]+)|)/g) {
push(@a, $_);
}
$HTTP->{'param'} = {@a};
init_all();
return($Conf, $HTTP, $Path);
}
sub init {
my @a;
$HTTP->{'this_url'} = &http_wash(join('', 'http://',
$ENV{'SERVER_NAME'},
':', $ENV{'SERVER_PORT'},
$ENV{'SCRIPT_NAME'},
$ENV{'PATH_INFO'},
'?', $ENV{'QUERY_STRING'}));
foreach ($ENV{'QUERY_STRING'} =~ /([^;&=]+)(?:=([^;&]+)|)/g) {
push(@a, &http_wash($_));
}
$HTTP->{'param'} = {@a};
init_all();
return($Conf, $HTTP, $Path);
}
sub init_all {
my ($argv_0) = @_;
$HTTP->{'path_info'} = &http_wash($ENV{'PATH_INFO'});
$HTTP->{'param'}->{'v'} ||= $HTTP->{'param'}->{'version'};
$HTTP->{'param'}->{'a'} ||= $HTTP->{'param'}->{'arch'};
$HTTP->{'param'}->{'i'} ||= $HTTP->{'param'}->{'identifier'};
$identifier = $HTTP->{'param'}->{'i'};
$readraw = $HTTP->{'param'}->{'raw'};
$Conf = new LXR::Config;
foreach ($Conf->allvariables) {
$Conf->variable($_, $HTTP->{'param'}->{$_}) if $HTTP->{'param'}->{$_};
}
&fixpaths($HTTP->{'path_info'} || $HTTP->{'param'}->{'file'});
if (defined($readraw)) {
print("\n");
} else {
print("Content-Type: text/html\n");
#
# Print out a Last-Modified date that is the larger of: the
# underlying file that we are presenting; and the "source" script
# itself (passed in as an argument to this function.) If we can't
# stat either of them, don't print out a L-M header. (Note that this
# stats lxr/source but not lxr/lib/LXR/Common.pm. Oh well, I can
# live with that I guess...) -- jwz, 16-Jun-98
#
my $file1 = $Path->{'realf'};
my $file2 = $argv_0;
# make sure the thing we call stat with doesn't end in /.
if ($file1) { $file1 =~ s@/$@@; }
if ($file2) { $file2 =~ s@/$@@; }
my $time1 = 0, $time2 = 0;
if ($file1) { $time1 = (stat($file1))[9]; }
if ($file2) { $time2 = (stat($file2))[9]; }
my $time = ($time1 > $time2 ? $time1 : $time2);
if ($time > 0) {
my @t = gmtime($time);
my ($sec, $min, $hour, $mday, $mon, $year,$wday) = @t;
my @days = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
my @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
$year += 1900;
$wday = $days[$wday];
$mon = $months[$mon];
# Last-Modified: Wed, 10 Dec 1997 00:55:32 GMT
print sprintf("Last-Modified: %s, %2d %s %d %02d:%02d:%02d GMT\n",
$wday, $mday, $mon, $year, $hour, $min, $sec);
}
# Close the HTTP header block.
print("\n");
}
if (defined($readraw)) {
open(RAW, $Path->{'realf'});
while () {
print;
}
close(RAW);
exit;
}
return($Conf, $HTTP, $Path);
}
sub expandtemplate {
my ($templ, %expfunc) = @_;
my ($expfun, $exppar);
while ($templ =~ s/(\{[^\{\}]*)\{([^\{\}]*)\}/$1\01$2\02/s) {}
$templ =~ s/(\$(\w+)(\{([^\}]*)\}|))/{
if (defined($expfun = $expfunc{$2})) {
if ($3 eq '') {
&$expfun;
} else {
$exppar = $4;
$exppar =~ s#\01#\{#gs;
$exppar =~ s#\02#\}#gs;
&$expfun($exppar);
}
} else {
$1;
}
}/ges;
$templ =~ s/\01/\{/gs;
$templ =~ s/\02/\}/gs;
return($templ);
}
# What follows is a pretty hairy way of expanding nested templates.
# State information is passed via localized variables.
# The first one is simple, the "banner" template is empty, so we
# simply return an appropriate value.
sub bannerexpand {
if ($who eq 'source' || $who eq 'sourcedir' || $who eq 'diff') {
return($Path->{'xref'});
} else {
return('');
}
}
sub pathname {
return $Path->{'virtf'};
}
sub treename {
return $Conf->{'treename'};
}
sub titleexpand {
if ($who eq 'source' || $who eq 'sourcedir' || $who eq 'diff') {
return($Conf->sourcerootname.$Path->{'virtf'});
} elsif ($who eq 'ident') {
my $i = $HTTP->{'param'}->{'i'};
return($Conf->sourcerootname.' identifier search'.
($i ? " \"$i\"" : ''));
} elsif ($who eq 'search') {
my $s = $HTTP->{'param'}->{'string'};
$s =~ tr/+/ /;
$s =~ s/%(\w\w)/chr(hex $1)/ge;
$s =~ s/&/&/g;
$s =~ s/</g;
$s =~ s/>/>/g;
return($Conf->sourcerootname.' freetext search'.
($s ? " \"$s\"" : ''));
} elsif ($who eq 'find') {
my $s = $HTTP->{'param'}->{'string'};
return($Conf->sourcerootname.' file search'.
($s ? " \"$s\"" : ''));
}
}
sub thisurl {
my $url = $HTTP->{'this_url'};
$url =~ s/([\?\&\;\=])/sprintf('%%%02x',(unpack('c',$1)))/ge;
return($url);
}
sub baseurl {
return($Conf->baseurl);
}
sub dotdoturl {
my $url = $Conf->baseurl;
$url =~ s@/$@@;
$url =~ s@/[^/]*$@@;
return($url);
}
# This one isn't too bad either. We just expand the "modes" template
# by filling in all the relevant values in the nested "modelink"
# template.
sub modeexpand {
my $templ = shift;
my $modex = '';
my @mlist = ();
local $mode;
if ($who eq 'source' || $who eq 'sourcedir') {
push(@mlist, "source navigation");
} else {
push(@mlist, &fileref("source navigation", $Path->{'virtf'}));
}
if ($who eq 'diff') {
push(@mlist, "diff markup");
} elsif (($who eq 'source' || $who eq 'sourcedir') && $Path->{'file'}) {
push(@mlist, &diffref("diff markup", $Path->{'virtf'}));
}
if ($who eq 'ident') {
push(@mlist, "identifier search");
} else {
push(@mlist, &idref("identifier search", ""));
}
if ($who eq 'search') {
push(@mlist, "freetext search");
} else {
push(@mlist, "{virtroot}/search".
&urlargs."\">freetext search");
}
if ($who eq 'find') {
push(@mlist, "file search");
} else {
push(@mlist, "{virtroot}/find".
&urlargs."\">file search");
}
foreach $mode (@mlist) {
$modex .= &expandtemplate($templ,
('modelink', sub { return($mode) }));
}
return($modex);
}
# This is where it gets a bit tricky. varexpand expands the
# "variables" template using varname and varlinks, the latter in turn
# expands the nested "varlinks" template using varval.
sub varlinks {
my $templ = shift;
my $vlex = '';
my ($val, $oldval);
local $vallink;
$oldval = $Conf->variable($var);
foreach $val ($Conf->varrange($var)) {
if ($val eq $oldval) {
$vallink = "$val";
} else {
if ($who eq 'source' || $who eq 'sourcedir') {
$vallink = &fileref($val,
$Conf->mappath($Path->{'virtf'},
"$var=$val"),
0,
"$var=$val");
} elsif ($who eq 'diff') {
$vallink = &diffref($val, $Path->{'virtf'}, "$var=$val");
} elsif ($who eq 'ident') {
$vallink = &idref($val, $identifier, "$var=$val");
} elsif ($who eq 'search') {
$vallink = "{virtroot}/search".
&urlargs("$var=$val",
"string=".$HTTP->{'param'}->{'string'}).
"\">$val";
} elsif ($who eq 'find') {
$vallink = "{virtroot}/find".
&urlargs("$var=$val",
"string=".$HTTP->{'param'}->{'string'}).
"\">$val";
}
}
$vlex .= &expandtemplate($templ,
('varvalue', sub { return($vallink) }));
}
return($vlex);
}
sub varexpand {
my $templ = shift;
my $varex = '';
local $var;
foreach $var ($Conf->allvariables) {
$varex .= &expandtemplate($templ,
('varname', sub {
return($Conf->vardescription($var))}),
('varlinks', \&varlinks));
}
return($varex);
}
sub makeheader {
local $who = shift;
$template = undef;
my $def_templ = "\n
\n";
if ($who eq "sourcedir" && $Conf->sourcedirhead) {
if (!open(TEMPL, $Conf->sourcedirhead)) {
&warning("Template ".$Conf->sourcedirhead." does not exist.");
$template = $def_templ;
}
} elsif (($who eq "source" || $who eq 'sourcedir') && $Conf->sourcehead) {
if (!open(TEMPL, $Conf->sourcehead)) {
&warning("Template ".$Conf->sourcehead." does not exist.");
$template = $def_templ;
}
} elsif ($who eq "find" && $Conf->findhead) {
if (!open(TEMPL, $Conf->findhead)) {
&warning("Template ".$Conf->findhead." does not exist.");
$template = $def_templ;
}
} elsif ($who eq "ident" && $Conf->identhead) {
if (!open(TEMPL, $Conf->identhead)) {
&warning("Template ".$Conf->identhead." does not exist.");
$template = $def_templ;
}
} elsif ($who eq "search" && $Conf->searchhead) {
if (!open(TEMPL, $Conf->searchhead)) {
&warning("Template ".$Conf->searchhead." does not exist.");
$template = $def_templ;
}
} elsif ($Conf->htmlhead) {
if (!open(TEMPL, $Conf->htmlhead)) {
&warning("Template ".$Conf->htmlhead." does not exist.");
$template = $def_templ;
}
}
if (!$template) {
$save = $/; undef($/);
$template = ;
$/ = $save;
close(TEMPL);
}
print(
#"\n",
# "\n",
# "\n",
# "",$Conf->sourcerootname," Cross Reference \n",
# " baseurl,"\">\n",
# "\n",
&expandtemplate($template,
('title', \&titleexpand),
('banner', \&bannerexpand),
('baseurl', \&baseurl),
('dotdoturl', \&dotdoturl),
('thisurl', \&thisurl),
('pathname', \&pathname),
('treename', \&treename),
('modes', \&modeexpand),
('variables', \&varexpand)));
}
sub makefooter {
local $who = shift;
$template = undef;
my $def_templ = "
\n\n";
if ($who eq "sourcedir" && $Conf->sourcedirtail) {
if (!open(TEMPL, $Conf->sourcedirtail)) {
&warning("Template ".$Conf->sourcedirtail." does not exist.");
$template = $def_templ;
}
} elsif (($who eq "source" || $who eq 'sourcedir') && $Conf->sourcetail) {
if (!open(TEMPL, $Conf->sourcetail)) {
&warning("Template ".$Conf->sourcetail." does not exist.");
$template = $def_templ;
}
} elsif ($who eq "find" && $Conf->findtail) {
if (!open(TEMPL, $Conf->findtail)) {
&warning("Template ".$Conf->findtail." does not exist.");
$template = $def_templ;
}
} elsif ($who eq "ident" && $Conf->identtail) {
if (!open(TEMPL, $Conf->identtail)) {
&warning("Template ".$Conf->identtail." does not exist.");
$template = $def_templ;
}
} elsif ($who eq "search" && $Conf->searchtail) {
if (!open(TEMPL, $Conf->searchtail)) {
&warning("Template ".$Conf->searchtail." does not exist.");
$template = $def_templ;
}
} elsif ($Conf->htmltail) {
if (!open(TEMPL, $Conf->htmltail)) {
&warning("Template ".$Conf->htmltail." does not exist.");
$template = $def_templ;
}
}
if (!$template) {
$save = $/; undef($/);
$template = ;
$/ = $save;
close(TEMPL);
}
print(&expandtemplate($template,
('banner', \&bannerexpand),
('thisurl', \&thisurl),
('modes', \&modeexpand),
('variables', \&varexpand)),
"\n");
}
1;