#!@PERL@ ############################################################################# # # search.cgi - Customizable WWW Interface to the Harvest Broker # # Usage: Called as a CGI proccess from httpd # ############################################################################# # # Harvest Indexer http://harvest.sourceforge.net/ # ----------------------------------------------- # # The Harvest Indexer is a continued development of code developed by # the Harvest Project. Development is carried out by numerous individuals # in the Internet community, and is not officially connected with the # original Harvest Project or its funding sources. # # Please mail lee@arco.de if you are interested in participating # in the development effort. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # $ENV{'HARVEST_HOME'} = "@prefix@" unless defined($ENV{'HARVEST_HOME'}); # Uncomment this if you have problems with European 8-BIT characters on SunOS. #$ENV{'LANG'} = "C"; #$ENV{'LC_CTYPE'} = "iso_8859_1"; # Set this to a location for search.log, or to /dev/null #$BQLOG = "@prefix@/logs/search.log"; $BQLOG = "/dev/null"; $rcsid = '$Id: search.in,v 2.20 2002/07/27 16:25:00 sxw Exp $'; # $expire # Temporary files are deleted after this many hours. Or, more precisely, when # this program is run, files older than $expire hours are deleted. # # $tmp_dir # This is the location where temporary files are kept. This directory needs a # permissive access mode, so that the 'nobody' user (or whatever # user httpd uses) can write and delete files there. It is a fatal error if # this directory does not exist, or cannot be written in. # # $tmp_www # This prefaces the URL file reference that leads to the 'Next' and 'Previous' # pages of results, e.g.: # http://www.some.host/tmp/875722836-6913-2.html # ###### configure these locally! ####### $expire = 1; # expiration interval, in hours $tmp_dir = "$ENV{HARVEST_HOME}/tmp"; # dir for temp files $tmp_www = "/Harvest/tmp"; # URL path pointing to $tmp_dir ###### end configuration ####### #--- Image "powered by Harvest" $rHarvestIcon = "http://www.rediris.es/poweredHarvest18.gif"; #--- Image to use as weigth icon $rWeightIcon = "http://www.rediris.es/weightHarvest01.gif"; #--- URL of the search home page $rSearchPage = "http://www.xxx.com/search.html"; #--- URL of displaySOIF script $rDisplaySoifPage = "http://www.rediris.es/harvest/cgi-bin/displaySOIF.rediris"; #--- Elements before and after de current page in the navigation bar $rNavPart = 5; # If name is nph-search.cgi, then we behave as an nph- cgi (ie send more # headers, and use unbuffered output). $nph = $0 =~ /nph-/; @X = split ('/', $0); $MYNAME = pop @X; $DIR = join ('/', @X); $ENV{'TMPDIR'} = "/tmp" unless defined($ENV{'TMPDIR'}); unshift(@INC, "$ENV{'HARVEST_HOME'}/lib"); not_configured() unless (-d $ENV{'HARVEST_HOME'}); require 'socket.ph'; # not sys/socket.ph, we use $HARVEST_HOME/lib/socket.ph $debug = 0; $hp_url = ''; $brokers = $ENV{'HARVEST_HOME'} . '/brokers/Brokers.cf'; $rIndex = 0; $rWeight = 0; $rGreaterWeight = 0; $rResult = ""; $rNavigationBar = ""; $rTotHtmlFiles = 0; # ===== MAIN ================================================================= foreach $sig ('HUP', 'QUIT', 'TSTP', 'TERM', 'ABRT') { $SIG{$sig} = 'sigdie'; } foreach $sig ('ALRM') { $SIG{$sig} = 'sigharddie'; } # Parse the CGI request. %RQ = &get_request; $debug = 1 if defined $RQ{'debug'}; foreach $key (keys %RQ) { $RQ{$key} =~ s/\n/ /g; } # Send the MIME header *now* if we're in debug mode this means it will always # be text/html, but means when can see debugging information from parse_config send_header() if $debug; # Read in the 'master config' file. &parse_config ("$DIR/lib/search.cf"); &parse_defaults; $CFG{'rcsid'} = $rcsid; # Parse a broker-specific config file (included as the following HTML - ) # print "opening $DIR/lib/",&option('brokerqueryconfig'),"\n" if ($debug); &parse_config ("$DIR/lib/".&option('brokerqueryconfig')) if ( -f "$DIR/lib/".&option('brokerqueryconfig') ); &parse_defaults; # We can't send the MIME header *until* we've read the broker-specific file # (as they might change it in there) - so we have to wait until now to send # it. send_header() unless $debug; # Now - once we're sure that a MIME header has been sent, we can validate # their input &fatal ('NoQuery') if (%RQ == ()); &fatal ('rcsid') if ($RQ{'version'} ne ""); &dump_array (%RQ) if ($debug); &dump_array (%DEF) if ($debug); #&dump_array (%ENV) if ($debug); # EXTRACT QUERY OPTIONS # $lifetime = &option('lifetime'); $userquery = &option('query'); $category = &option('category'); $userclass = &option('class'); $caseflag = &option('caseflag') eq 'on' ? 1 : 0; $wordflag = &option('wordflag') eq 'on' ? 1 : 0; $csumflag = &option('csumflag') eq 'on' ? 1 : 0; $opaqflag = &option('opaqueflag') eq 'on' ? 1 : 0; $descflag = &option('descflag') eq 'on' ? 1 : 0; $noregex = &option('noregexflag') eq 'on' ? 1 : 0; $maxresult = &option('maxresultflag'); $maxfiles = &option('maxobjflag'); $maxlines = &option('maxlineflag'); $perpage = &option('perpageflag'); $errors = &option('errorflag'); $broker = &option('broker') || &option('host'); #$verbflag = &option('verbose') eq "" ? 0 : 1; $version = &option('version') eq "" ? 0 : 1; $hp_url = &option('hp_url'); @atts = split (/\s+/, &option('attribute')); $sort = &option('sort'); foreach $a (@atts) { $attributes .= " #attribute \"$a\""; } # SECURITY CHECKS AND TRANSLATION ON BROKER HOST,PORT # $errmsg = <<"EOF";
$MYNAME doesn't know the broker
$broker
Either it is not in the allowed list, or perhaps
$brokers is not readable.
EOF
&fatal($errmsg)
unless (@hostport = &get_host_port ($broker));
# HACKS FOR BROKEN LYNX BROWSER
#
$errors = 0 if ($errors eq 'None');
$errors = 1 if ($errors eq '1 Error');
$errors = 2 if ($errors eq '2 Errors');
# SET THE LIFETIME
#
$BQlife = $CFG{'Timeout'};
$BQlife = $lifetime + 300 if ($lifetime ne "");
alarm ($BQlife);
### # SANITY CHECKS
### #
### &fatal ('NoReplica') if ($host eq "No Replicas");
### &fatal ('Misconfig') if ($host eq "" || $port == 0);
# CHECK QUERY STRING FOR COMMON MISTAKES
#
$userquery =~ s/^\s+//; # remove leading whitespace
$userquery =~ s/\s+$//; # remove trailing whitespace
$userquery = &entities($userquery); # translate SGML entities
unless ( $userquery =~ /\s+and\s+/i || $userquery =~ /\s+or\s+/i
|| $userquery =~ /:\s+/ || $userquery =~ /\"/) {
if ($category ne "anytext") {
@X = split (/\s+/, $userquery);
for ($i=0; $i<=$#X; $i++) {
$X[$i] =~ s/^\+(.*)/$1/; # remove leading +
$X[$i] =~ s/^\-(.*)/NOT $1/; # replace leading - by NOT
$X[$i] =~ s/\,//; # remove commata: not supported by broker
# put quotes around unknown characters
$X[$i] = "\"$X[$i]\"" if ($X[$i] =~ /[^ \w\d-]/);
$X[$i] = "$category:$X[$i]" if (($category ne "any") && ($category ne ""));
}
$userquery = join (' AND ', @X);
} else {
@X = split (/\s+/, $userquery);
for ($i=0; $i<=$#X; $i++) {
$X[$i] = "\"$X[$i]\"" if ($X[$i] =~ /\W/);
$X[$i] = "(keywords:$X[$i] OR title:$X[$i] OR body:$X[$i] OR headings:$X[$i] OR address:$X[$i])"
}
$userquery = join (' AND ', @X);
}
}
# BUILD QUERY STRING
#
$query = "";
$query .= $userclass . " AND " if ($userclass ne "");
#----------------------------------------------------------------------
# JMM - 19960619
# We use the metatag "DC.Language" to specify the language os the page.
# We can search only the pages in a specific language if user selects
# it in the form (using the searchLang variable)
#---------------------------------------------------------------------,
#$query .= $userquery;
$rLang = $RQ{'searchLang'};
if ($rLang eq "es")
{ $query .= $userquery . " AND (\"DC.Language\" : es)"; }
elsif ($rLang eq "en")
{ $query .= $userquery . " AND (\"DC.Language\" : en)"; }
elsif ($rLang eq "ca")
{ $query .= $userquery . " AND (\"DC.Language\" : ca)"; }
elsif ($rLang eq "gl")
{ $query .= $userquery . " AND (\"DC.Language\" : gl)"; }
else
{ $query .= $userquery; }
#---------------------------------------------------------------------'
# BUILD BROKER QUERY
#
$bquery = "#USER";
$bquery .= " #opaque" if ($opaqflag);
$bquery .= " #desc" if ($descflag);
$bquery .= " #index timeout $lifetime" if ($lifetime ne "");
$bquery .= " #index error $errors" if ($errors ne "");
$bquery .= " #index maxresult $maxresult" if ($maxresult ne "");
$bquery .= " #index maxfiles $maxfiles" if ($maxfiles ne "");
$bquery .= " #index maxlines $maxlines" if ($maxlines ne "");
$bquery .= " #index case";
$bquery .= $caseflag ? " insensitive" : " sensitive";
$bquery .= " #index matchword" if ($wordflag);
$bquery .= " #index noregex" if ($noregex);
$bquery .= $attributes;
$bquery .= " #END ";
$bquery .= $query;
$simple_query = $1 if ($query =~ /^.*partial-text\s*:\s+"(.*)".*$/io);
# Call Init Function
#
eval $CFG{'InitFunction'} if (defined ($CFG{'InitFunction'}));
# DO THE QUERY
#
$html_query = &html_escape ($query);
print &expand ($CFG{'ResultHeader'});
$connected = 0;
while ($#hostport > $[) {
$host = shift (@hostport);
$port = shift (@hostport);
if ($SOCK = &client_socket ($host, $port)) {
$connected = 1;
last;
}
}
&broker_down ($host, $port) unless ($connected);
print "Sending $bqueryto $host:$port
\n";
foreach $key ( sort keys %A) {
print "$key=$A{$key}\n";
}
print "\n";
1;
}
sub broker_down {
local($host, $port) = @_;
print STDOUT <EOM &fatal("$host:$port: $!\n"); } sub not_configured { print <<"EOM"; Content-type: text/html
$ENV{'HARVEST_HOME'} does not exist.
Please refer to the current
Harvest
User's Manual.
EOM
exit 0;
}
# Read defaults from .cf
sub parse_defaults {
local($attr,$value);
local(@vars)=split(/\n/,$CFG{'Default'});
while (@vars) {
($attr,$value)=split(/:/,shift(@vars));
$attr=~s/\s//g;
$value=~s/^\s*//;
$DEF{$attr}=$value;
}
}
sub option {
local($attr)=@_[0];
return (defined $RQ{$attr}) ? $RQ{$attr} : $DEF{$attr};
}
######################################################################
# Below is cgi.pl...
#
# &get_request;
# $area=$rqpairs{'area'};
# $title=$rqpairs{'title'};
# $name=$rqpairs{'name'};
# $msg = $rqpairs{'message'};
# $date = &get_date;
# chop($thishost = `hostname`);
#
# # Check for blank title and URL
# #
# &failure ("Blank title") if ($title eq "");
# &failure ("Blank name") if ($name eq "");
# &failure ("Empty message") if ($msg eq "");
# &failure ("Empty subject area") if ($area eq "");
# The CGI_HANDLERS deal with basic CGI POST or GET method request
# elements such as those delivered by an HTTPD form, i.e. a url
# encoded line of "=" separated key=value pairs separated by &'s
# Routines:
# get_request: reads the request and returns both the raw and
# processed version.
# url_decode: URL decodes a string or array of strings
# html_header: Transmits a HTML header back to the caller
# html_trailer: Transmits a HTML trailer back to the caller
# Author:
# James Tappin: sjt@xun8.sr.bham.ac.uk
# School of Physics & Space Research University of Birmingham
# Feb 1993.
# Copyright & Disclaimer.
# This set of routines may be freely distributed, modified and
# used, provided this copyright & disclaimer remains intact.
# This package is used at your own risk, if it does what you
# want, good; if it doesn't, modify it or use something else--but
# don't blame me. Support level = negligable (i.e. mail bugs but
# not requests for extensions)
# Usage:
# needs a 'require "cgi_handlers.pl";' line in the main script
#
# &get_request; will get the request and decode it into an
# indexed array %rqpairs, the raw request is in
# $request
#
# ... = &url_decode(LIST); will return a URL decoded version of
# the contents of LIST
#
# &html_header(TITLE); will write to standard output an HTML
# header (including the content-type
# field) giving the document the title
# specified by TITLE.
#
# &html_trailer; Writes a trailer to the html document
# with the name of the script generating
# it and the date (in UT).
sub get_request {
# Subroutine get_request reads the POST or GET form request from STDIN
# into the variable $request, and then splits it into its
# name=value pairs in the associative array %rqpairs.
# The number of bytes is given in the environment variable
# CONTENT_LENGTH which is automatically set by the request generator.
# Encoded HEX values and spaces are decoded in the values at this
# stage.
# $request will contain the RAW request. N.B. spaces and other
# special characters are not handler in the name field.
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $request, $ENV{'CONTENT_LENGTH'});
} elsif ($ENV{'REQUEST_METHOD'} eq "GET" ) {
$request = $ENV{'QUERY_STRING'};
}
@F = split(/[&=]/, $request);
&url_decode(@F);
}
sub url_decode {
# Decode a URL encoded string or array of strings
# + -> space
# %xx -> character xx
foreach (@_) {
tr/+/ /;
s/%(..)/pack("c",hex($1))/ge;
}
#@_;
# This gross stuff handles multiply defined attributes. For example:
# foo=abc&foo=xyz
# comes back as
# $RQ{'foo'} eq 'abc xyz'
# Otherwise, the previous method just gave us one or the other. -DW
#
local ($k, $v);
local (%Y);
while (($k=shift @_) ne '' && ($#_ >= 0)) {
$v=shift @_;
$Y{$k} = defined $Y{$k} ? join (' ', $Y{$k}, $v) : $v;
}
%Y;
}
# sort the objects by number of matched lines
#
#sub bynml {
# split(/\n/, $b) <=> split(/\n/, $a); # number of lines in object
#}
# sort the objects by "rank". This is based on code from Wesley Alan Wright
sub rank_objects {
local (@objects) = @_;
local ($objnum) = 0;
local (%ratings);
local (@object_index);
foreach $object (@objects) {
$rank = 1;
$lastline = ""; # hw - don't count repeated lines...
split(/\n/,$object);
foreach $line (@_) {
# $rawline=$line;
$line =~ s/\s{2,}/ /g; # Remove multiple whitespaces
$line =~ s/(Matched line: )(.*)$/$2/;
$line =~ s/^(.*)\{(\d+)\}(.*)$/$1$3/; # Remove "{12}:" etc.
# if (open(BQLOG, ">>$BQLOG")) {
# printf BQLOG ($rawline."\n");
# printf BQLOG ($line."\n");
# printf BQLOG ($rank."\n");
# close BQLOG;
# }
if ($line ne $lastline) {
#----------------------------------------------------------------------
# JMM - 20010529
# We consider some metadata in Dublin Core format the most important
#---------------------------------------------------------------------,
$rank = $rank + 10000 - length($line)
if (index($line,"dc.subject#") > 0);
$rank = $rank + 5000 - length($line)
if (index($line,"dc.title#") > 0);
$rank = $rank + 1000 - length($line)
if (index($line,"dc.description#") > 0);
$rank = $rank + 500 - length($line)
if (index($line,"dc.creator#") > 0);
$rank = $rank + 100 - length($line)
if (index($line,"dc.publisher#") > 0);
$rank = $rank + 100 - length($line)
if (index($line,"dc.language#") > 0);
#---------------------------------------------------------------------'
#title is most important
$rank += 600 - length($line)*3
if (index($line,"title#") > 0 && length($line) < 200);
#url is also important
$rank += 150 - length($line)/1.5
if (index($line,"url#") > 0 && length($line) < 200);
#there are some very long headings...
$rank += 110 - length($line)/2
if (index($line,"headings#") > 0 && length($line)<200);
# used for PDF, PS etc.
$rank += 80 - length($line)/3
if (index($line,"description#") > 0 && length($line)<200);
$rank += 60 if (index($line,"subject#") > 0);
$rank += 30 if (index($line,"images#") > 0);
# these are sometimes too long.
$rank += 25 - length($line)/8
if (index($line,"url-references#") > 0 );
# somehow redundant, not as important as it may seem...
$rank += 20 if (index($line,"keywords#") > 0);
$rank += 10 if (index($line,"body#") > 0);
# Consider length of URL of every Page
$rank += 400 - length($line)*2
if (index($line,"120 - ") == 0 && length($line) < 200);
}
$lastline = $line;
}
$ratings{$objnum} = $rank;
$object_index[$objnum] = $objnum;
$objnum++;
}
# pop off the "126" and "103" results (I hope they're at the end!)
pop(@object_index);
pop(@object_index);
@sorted_index= sort byrate @object_index;
$objnum=0;
#----------------------------------------------------------------------
# JMM - 20010605
# The first element has the higher weight. We need it to calculate
# the number of balls to show with an resource.
#---------------------------------------------------------------------,
$rGreaterWeight = $ratings{$sorted_index[0]};
#---------------------------------------------------------------------'
foreach $index (@sorted_index) {
$OBJ[$objnum] = $objects[$index];
#----------------------------------------------------------------------
# JMM - 20010529
# We save the weight of each object.
#---------------------------------------------------------------------,
$raWeight[$objnum] = $ratings{$index};
#---------------------------------------------------------------------'
$objnum++;
}
}
sub byrate {
$ratings{$b} <=> $ratings{$a};
}
# translate SGML entities
# produced from
# perl -ne 'if (/^ *<.ENTITY *([\S]*) *CDATA *"([\d]+);".*>/)
# { if ($2 <0x100) {printf "s/&$1;/\\x%x/g;\n", $2;}
# else {printf "s/&$1;/\\\\#$2/g;\n";}}'
sub entities {
$_ = $_[0];
# ISO Latin 1
s/ /\xa0/g;
s/¡/\xa1/g;
s/¢/\xa2/g;
s/£/\xa3/g;
s/¤/\xa4/g;
s/¥/\xa5/g;
s/¦/\xa6/g;
s/§/\xa7/g;
s/¨/\xa8/g;
s/©/\xa9/g;
s/ª/\xaa/g;
s/«/\xab/g;
s/¬/\xac/g;
s//\xad/g;
s/®/\xae/g;
s/¯/\xaf/g;
s/°/\xb0/g;
s/±/\xb1/g;
s/²/\xb2/g;
s/³/\xb3/g;
s/´/\xb4/g;
s/µ/\xb5/g;
s/¶/\xb6/g;
s/·/\xb7/g;
s/¸/\xb8/g;
s/¹/\xb9/g;
s/º/\xba/g;
s/»/\xbb/g;
s/¼/\xbc/g;
s/½/\xbd/g;
s/¾/\xbe/g;
s/¿/\xbf/g;
s/À/\xc0/g;
s/Á/\xc1/g;
s/Â/\xc2/g;
s/Ã/\xc3/g;
s/Ä/\xc4/g;
s/Å/\xc5/g;
s/Æ/\xc6/g;
s/Ç/\xc7/g;
s/È/\xc8/g;
s/É/\xc9/g;
s/Ê/\xca/g;
s/Ë/\xcb/g;
s/Ì/\xcc/g;
s/Í/\xcd/g;
s/Î/\xce/g;
s/Ï/\xcf/g;
s/Ð/\xd0/g;
s/Ñ/\xd1/g;
s/Ò/\xd2/g;
s/Ó/\xd3/g;
s/Ô/\xd4/g;
s/Õ/\xd5/g;
s/Ö/\xd6/g;
s/×/\xd7/g;
s/Ø/\xd8/g;
s/Ù/\xd9/g;
s/Ú/\xda/g;
s/Û/\xdb/g;
s/Ü/\xdc/g;
s/Ý/\xdd/g;
s/Þ/\xde/g;
s/ß/\xdf/g;
s/à/\xe0/g;
s/á/\xe1/g;
s/â/\xe2/g;
s/ã/\xe3/g;
s/ä/\xe4/g;
s/å/\xe5/g;
s/æ/\xe6/g;
s/ç/\xe7/g;
s/è/\xe8/g;
s/é/\xe9/g;
s/ê/\xea/g;
s/ë/\xeb/g;
s/ì/\xec/g;
s/í/\xed/g;
s/î/\xee/g;
s/ï/\xef/g;
s/ð/\xf0/g;
s/ñ/\xf1/g;
s/ò/\xf2/g;
s/ó/\xf3/g;
s/ô/\xf4/g;
s/õ/\xf5/g;
s/ö/\xf6/g;
s/÷/\xf7/g;
s/ø/\xf8/g;
s/ù/\xf9/g;
s/ú/\xfa/g;
s/û/\xfb/g;
s/ü/\xfc/g;
s/ý/\xfd/g;
s/þ/\xfe/g;
s/ÿ/\xff/g;
# Cougar HTMLsym
s/ƒ/\\#402/g;
s/Α/\\#913/g;
s/Β/\\#914/g;
s/Γ/\\#915/g;
s/Δ/\\#916/g;
s/Ε/\\#917/g;
s/Ζ/\\#918/g;
s/Η/\\#919/g;
s/Θ/\\#920/g;
s/Ι/\\#921/g;
s/Κ/\\#922/g;
s/Λ/\\#923/g;
s/Μ/\\#924/g;
s/Ν/\\#925/g;
s/Ξ/\\#926/g;
s/Ο/\\#927/g;
s/Π/\\#928/g;
s/Ρ/\\#929/g;
s/Σ/\\#931/g;
s/Τ/\\#932/g;
s/Υ/\\#933/g;
s/Φ/\\#934/g;
s/Χ/\\#935/g;
s/Ψ/\\#936/g;
s/Ω/\\#937/g;
s/α/\\#945/g;
s/β/\\#946/g;
s/γ/\\#947/g;
s/δ/\\#948/g;
s/ε/\\#949/g;
s/ζ/\\#950/g;
s/η/\\#951/g;
s/θ/\\#952/g;
s/ι/\\#953/g;
s/κ/\\#954/g;
s/λ/\\#955/g;
s/μ/\\#956/g;
s/ν/\\#957/g;
s/ξ/\\#958/g;
s/ο/\\#959/g;
s/π/\\#960/g;
s/ρ/\\#961/g;
s/ς/\\#962/g;
s/σ/\\#963/g;
s/τ/\\#964/g;
s/υ/\\#965/g;
s/φ/\\#966/g;
s/χ/\\#967/g;
s/ψ/\\#968/g;
s/ω/\\#969/g;
s/ϑ/\\#977/g;
s/ϒ/\\#978/g;
s/ϖ/\\#982/g;
s/•/\\#8226/g;
s/…/\\#8230/g;
s/′/\\#8242/g;
s/″/\\#8243/g;
s/‾/\\#8254/g;
s/⁄/\\#8260/g;
s/℘/\\#8472/g;
s/ℑ/\\#8465/g;
s/ℜ/\\#8476/g;
s/™/\\#8482/g;
s/ℵ/\\#8501/g;
s/←/\\#8592/g;
s/↑/\\#8593/g;
s/→/\\#8594/g;
s/↓/\\#8595/g;
s/↔/\\#8596/g;
s/↵/\\#8629/g;
s/⇐/\\#8656/g;
s/⇑/\\#8657/g;
s/⇒/\\#8658/g;
s/⇓/\\#8659/g;
s/⇔/\\#8660/g;
s/∀/\\#8704/g;
s/∂/\\#8706/g;
s/∃/\\#8707/g;
s/∅/\\#8709/g;
s/∇/\\#8711/g;
s/∈/\\#8712/g;
s/∉/\\#8713/g;
s/∋/\\#8715/g;
s/∏/\\#8719/g;
s/∑/\\#8721/g;
s/−/\\#8722/g;
s/∗/\\#8727/g;
s/√/\\#8730/g;
s/∝/\\#8733/g;
s/∞/\\#8734/g;
s/∠/\\#8736/g;
s/∧/\\#8869/g;
s/∨/\\#8870/g;
s/∩/\\#8745/g;
s/∪/\\#8746/g;
s/∫/\\#8747/g;
s/∴/\\#8756/g;
s/∼/\\#8764/g;
s/≅/\\#8773/g;
s/≈/\\#8776/g;
s/≠/\\#8800/g;
s/≡/\\#8801/g;
s/≤/\\#8804/g;
s/≥/\\#8805/g;
s/⊂/\\#8834/g;
s/⊃/\\#8835/g;
s/⊄/\\#8836/g;
s/⊆/\\#8838/g;
s/⊇/\\#8839/g;
s/⊕/\\#8853/g;
s/⊗/\\#8855/g;
s/⊥/\\#8869/g;
s/⋅/\\#8901/g;
s/⌈/\\#8968/g;
s/⌉/\\#8969/g;
s/⌊/\\#8970/g;
s/⌋/\\#8971/g;
s/〈/\\#9001/g;
s/〉/\\#9002/g;
s/◊/\\#9674/g;
s/♠/\\#9824/g;
s/♣/\\#9827/g;
s/♥/\\#9829/g;
s/♦/\\#9830/g;
# Cougar HTMLmisc
s/"/\x22/g;
s/&/\x26/g;
s/</\x3c/g;
s/>/\x3e/g;
s/Œ/\\#338/g;
s/œ/\\#339/g;
s/Š/\\#352/g;
s/š/\\#353/g;
s/Ÿ/\\#376/g;
s/ˆ/\\#710/g;
s/˜/\\#732/g;
s/ /\\#8194/g;
s/ /\\#8195/g;
s/ /\\#8201/g;
s//\\#8204/g;
s//\\#8205/g;
s//\\#8206/g;
s//\\#8207/g;
s/–/\\#8211/g;
s/—/\\#8212/g;
s/‘/\\#8216/g;
s/’/\\#8217/g;
s/‚/\\#8218/g;
s/“/\\#8220/g;
s/”/\\#8221/g;
s/„/\\#8222/g;
s/†/\\#8224/g;
s/‡/\\#8225/g;
s/‰/\\#8240/g;
s/‹/\\#8249/g;
s/›/\\#8250/g;
return($_);
}
# David Hoekman Oct 1, 1997
# Split search results into segments, 'n' results at a time. The value of
# 'n' is set by the $perpage variable, which is defined via the 'perpageflag'
# query option. Each segment is written to a separate temporary file; the
# location of these files must be configured locally. This routine also
# removes old temporary files, when they are older than a certain age.
#
sub N_at_a_time {
local($more) = @_;
local($previous_page, $next_page);
local($tmp_prefix) = "$^T-${$}"; # prefix for temporary files
# if this is the last page of results, remove old temporary files
# (if $expire=3, then 3/24 sets a 3 hour expiration cycle)
unless ($more) {
chdir "$tmp_dir";
foreach $file (<[1-9]*-[1-9]*-[1-9]*\.html>) {
unlink "$file" if -M $file > $expire/24;
}
}
# write stored 'first' page (duplicates data sent to STDOUT/browser)
if (! $current_page) {
$current_page = 1;
open(TEMP,">$tmp_dir/$tmp_prefix-1.html") ||
&fatal("Error: cannot write temporary files at '$tmp_dir'!");
print TEMP "\n";
print TEMP &expand ($CFG{'ResultHeader'});
print TEMP @first_page;
print TEMP &expand ($CFG{'ResultSetEnd'});
#----------------------------------------------------------------------
# JMM - 20010531
# We change this lines to print the navigation bar $rNavigationBar (we
# constructed it when we evaluated $CFG{'CreateNavBars'})
#---------------------------------------------------------------------,
# print TEMP qq{
Total: $totnumber} if ($more && defined $sort);
print TEMP "
\n
\n