#!/usr/bin/perl # search.cgi # Sam's hack for quickly searching the course Web. Primarily # cut-and-pasted from Perl code originally written in 1995 (!) # and last updated in 2001. # +-------+----------------------------------------------------------- # | Notes | # +-------+ # * To cache search results, create the directory $ROOT/search and # make it readable and writable by the web user (www-data on MathLAN). # * Usage can be found by grepping search.cgi in /var/logs/apache2/access.log # It looks like the logs are compressed every Sunday. # +------+------------------------------------------------------------ # | Todo | # +------+ # [ ] The todo list really should be on the github page :-) # [ ] Improve the search for translated files by identifying the # source files with grep and then grepping again in the HTML # versions of those files. (Or it may not be worth it.) # +----------+-------------------------------------------------------- # | Settings | # +----------+ # $ROOT # The root of the course Web site my $ROOT = $ENV{"PWD"} . ".."; # $PATTERNS # A space-separated list of all the files to search my $PATTERNS = "$ROOT/home/*.sect $ROOT/handouts/*.sect $ROOT/readings/*.sect $ROOT/outlines/*.md $ROOT/eboards/*.md $ROOT/labs/*.sect $ROOT/reference/*.sect $ROOT/assignments/*.sect"; # $DEBUG # Are we debugging or not $DEBUG = 0; # Set to 1 if you want to debug # $GREP # The version of grep to use $GREP = "/bin/grep -H"; # +------+------------------------------------------------------------ # | Main | # +------+ local($exitval) = main(); exit $exitval; sub main() { # Set up variables my $query = getQuery(); my $keyword = extractField($query, "keyword"); # Clean up the query for safety $keyword =~ s/[^-_0-9 a-zA-Z.]/./g; # my $template = minimalTemplate(); my $template = readFile("template.html"); return searchPage($template, $keyword, $PATTERNS, "search.cgi"); } # main # +---------+--------------------------------------------------------- # | Helpers | # +---------+ # Routines # extractField(query,fieldname) # Returns # The value for the field. If there are multiple values, they # will be returned with commas separating them. sub extractField($$) { my $query = shift; # The query string my $fld = shift; # The field name we're looking for my $result = ""; # The result of extracting the field my $match; # For pattern matching my $next; # The next set of field contents # Keep finding versions of the field that follow an ampersand. Note # that we remove from the back, rather than from the front. while (($match=$query) =~ m/&${fld}=/) { $next = $query; $next =~ s/.*&${fld}=([^&]*).*/$1/; $result = "$next,$result"; $query =~ s/(.*)&${fld}=.*/$1/; } # See if we're left with something that matches if (($match=$query) =~ m/^${fld}=/) { $next = $query; $next =~ s/&.*//; # Remove any subsequent fields $next =~ s/${fld}=//; # Remove the field name $result = "$next,$result"; } # if there is anything left that matches # We're done $result =~ s/,$//; return webDecode($result); } # extractField # Routine # extractHtmlTitle(fname) # Parameters # fname, the name of a file # Purpose # Find the title in the file. sub extractHtmlTitle($) { my $fname = shift; my $contents = readFile($fname); $contents =~ s/.*
Search conducted on $date.<\/p>\n";
}
# Identify all portions that contain the appropriate stuff
# We need to do separate greps in case there are too many files
if ($keyword) {
my($found) = "";
my($pattern);
my($morefound);
foreach $pattern (split(/\s+/,$PATTERNS)) {
if ($pattern) {
if ($DEBUG) { print "Looking at pattern '$pattern'
\n"; }
$morefound = `$GREP -i "$keyword" $pattern`;
if ($morefound) {
if ($DEBUG) { print "Found stuff
\n"; }
$found .= $morefound;
} # if more stuff was found
} # if the pattern matched
} # foreach pattern
# Get rid of HTML commands from that stuff
if ($DEBUG) {
# We need to change all tags to "plain text" for printing out
my($tmp) = $found;
$tmp =~ s/\&/\&/g;
$tmp =~ s/>/\>/g;
$tmp =~ s/\</g;
print "Search results: $tmp
";
}
$found =~ s/<[^>]*>//g;
$found =~ s/<[^>]*$//;
if ($DEBUG) {
print "Cleaned up: $found
";
}
# Build HTML containing the found lines (which may not be the
# same as those before, given the stripping of HTML)
my @lines = split(/\n/, $found); # All the found lines
my $line; # One such line
my $newfile,$contents; # One line of info
my $fname; # The last file mentioned
my $html = ""; # The HTML for all of this
my $title; # The title of the file
my $dir; # The directory in which it is found
foreach $line (@lines) {
if ($DEBUG) { print "Considering '$line'
\n"; }
# The pattern is ":.*$keyword" so that we ensure that the keyword
# falls in the body and not the filename
if ($line =~ m/:.*$keyword/i) {
# Split the line into filename and matching info
($newfile,$contents) = split(/:/,$line,2);
# Update the file name to deal with .md and .sect files
$newfile =~ s/md$/html/;
$newfile =~ s/sect$/html/;
# Identify the parent directory (which clarifies location)
$dir = $newfile;
if ($dir !~ s/\/[^\/]*$//) {
$dir = "";
}
$dir =~ s/^.*\///;
if ($DEBUG) {
print " File: $newfile
\n";
print " Dir: $dir
\n";
print " Contents: $contents
\n";
}
# If the file is different, make a new entry
if ($newfile ne $fname) {
if ($DEBUG) { print "Starting a new entry!\n"; }
$fname = $newfile;
# End the old entry (we know that there's an old entry b/c we've
# actually generated some HTML)
if ($html) { $html .= "\n\n"; }
# Begin the new entry
$title = getTitle($fname);
if (!$title) { $title = $fname; }
# if ($dir) { $html .= "[$dir] "; }
# Convert the file name fo a url
my $url = $fname;
$url =~ s/^\/home\//http:\/\/www.cs.grinnell.edu\/~/;
$url =~ s/public_html\///;
$url =~ s/Web\///;
$html .= "$title\n";
$html .= "
Sorry, I am unable to find any pages that contain the text $keyword.
NOTFOUND } # if we didn't find something else { print $RESULTS <<"FOUND";
For each of the files that contains the word
${keyword}
, the file and lines with the word
${keyword}
are listed. Click on the name of a
file to view that file.
The limitations of WWW and HTML currently make it difficult, if not
impossible, to allow you to jump directly to a particular line in
a page. After navigating to the page, you may use the search function of
your Web browser to find ${keyword}
.