#!/usr/bin/perl -Tw use strict; delete @::ENV{qw(IFS PATH CDPATH ENV BASH_ENV)}; package select; use CGI; use CGI::Carp qw(fatalsToBrowser); # select.cgi # ~~~~~~~~~~ # Provides a page containing multiple frames, each of which contains # one of the web pages specified in the arguments. If the browser is # not supporting frames, the page returned just contains links to the # specified web pages. # # Useful for things like searching multiple web search engines at the # same time with a much thinner software layer (and hence better # response time) than things like savvy or metacrawler. # # See http://www.zip.com.au/~raf2 for an example of its use. # # 1997/10/2 raf # # Invocation # ~~~~~~~~~~ #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # url1 # # # url2 # # # url3 #
# # # # # #
#
# # Error codes and messages. # my $error; sub ERR_MISSING_PARAMETER { return 1; } sub ERR_NOTHING_SELECTED { return 2; } sub ERR_NO_SUCH_LAYOUT { return 3; } my @error = ( '', 'Parameter missing: ', 'No selections made.', 'Undefined layout: ' ); cgi: { print fill(selection(), params()); exit(0); } # # Build the parameter list for the HTML template below. # sub params { my $cgi = new CGI; my %params = ( 'Header' => 'Content-type: text/html', 'Title' => 'select.cgi', 'Frames' => '', 'NoFrames' => '' ); # # Set the title. # $params{'Title'} = $cgi->param('title') if (defined($cgi->param('title'))); # # Get any user defined error urls. # if (defined($cgi->param('error'))) { $error = $cgi->param('error'); } # # Get the choices (from 'set') that have been selected. # my @choices; if (defined($cgi->param('set'))) { my $choice; for $choice (split(/[,\s]+/, $cgi->param('set'))) { push(@choices, evaluate_choice($cgi, $choice)) if (defined($cgi->param($choice))); } } else { fail($cgi, ERR_MISSING_PARAMETER(), 'set'); } # # If nothing was selected, go beserk. # # redirect back to referer? fail($cgi, ERR_NOTHING_SELECTED()) if ($#choices == -1); # # If there's only one selected, just go there. # redirect($cgi, $choices[0]) if ($#choices == 0); # # Get the layout to use. # my $layout = 'horizontal'; $layout = $cgi->param('layout') if (defined($cgi->param('layout'))); my %strategy = ( 'horizontal' => \&horizontal, 'vertical' => \&vertical, 'grid' => \&grid ); if (defined($strategy{$layout})) { my $strategy = $strategy{$layout}; ($params{'Columns'}, $params{'Rows'}) = &$strategy($#choices + 1); } else { fail($cgi, ERR_NO_SUCH_LAYOUT(), $layout); } # # Build the selection frames and links. # my $choice; for $choice (@choices) { $params{'NoFrames'} .= mk_link($choice); $params{'Frames'} .= mk_frame($choice); } # # Provide results in a separate browser window? # if (defined($cgi->param('fork'))) { $params{'Header'} .= "\n" . 'Window-target: ' . $$; } return %params; } # # Evaluate all '$' parameters in the selected url. Result is a url. # Note: Evaluation may nest. Nested evaluation is breadth first. # sub evaluate_choice { my ($cgi, $choice) = @_; my $arg = $cgi->param($choice); while ($arg =~ /(\$\w+)/) { my $var = substr($1, 1); # strip off '$' to get var name if (defined($cgi->param($var))) # did the user select this? { my $value = CGI::escape($cgi->param($var)); $arg =~ s/\$$var/$value/g; # evaluate var to value } else { fail($cgi, ERR_MISSING_PARAMETER(), $var); } } return $arg; } # # Provides an error page. # sub fail { my ($cgi, $err, $name) = @_; if (defined($error)) { my $errarg = '?' . 'err=' . $err; $errarg .= '&' . 'name=' . $name if (defined($name)); redirect($cgi, $error . $errarg); } else { my $errmsg = $error[$err]; $errmsg .= ' ' . $name if (defined($name)); my $target = ''; if (defined($cgi->param('fork'))) { $target = "\n" . window(); } print failure($target, $errmsg); } exit(0); } # # Provides redirection to another page. # sub redirect { my ($cgi, $url) = @_; print 'Location: ', $url; if (defined($cgi->param('fork'))) { print "\n", window(); } print "\n\n"; exit(0); } # # Horizontal layout strategy: 1 column, n rows. # sub horizontal { my ($num) = @_; return ('*', stars($num)); } # # Vertical layout strategy: n columns, 1 row. # sub vertical { my ($num) = @_; return (stars($num), '*'); } # # Grid layout strategy: p columns, q rows where p and q are # nearest factors of n (number of choices selected by the user). # The bias is towards horizontal. # sub grid { my ($num) = @_; my ($cols, $rows) = nearest_factors($num); return (stars($cols), stars($rows)); } # # Calculate the nearest factors of $num. Highest first. # sub nearest_factors { my ($num) = @_; my ($f1, $f2); for ($f1 = int(sqrt($num));; --$f1) { $f2 = $num / $f1; last if ($f2 == int($f2)); } return ($f1, $f2); } # # Generate a string of $num comma separated asterisks. # For use in frame tags when specifying rows and columns. # sub stars { my ($num) = @_; return '*' . ',*' x ($num - 1); } # # Make a hyperlink to a selection for frameless browsing. # Link text is the url without any cgi parameters. # sub mk_link { my ($src) = @_; my $link = $src; $link =~ s/\?.*$//; return "
\n
\n\t$link\n"; } # # Make a frame for a selection. # sub mk_frame { my ($src) = @_; return "\t\n"; } # # Returns http target directive to place response in a separate browser window. # sub window { return 'Window-target: ' . time() . '-' . $$; } # # Replace '@@Parameters@@' in the $template with corresponding values in %arg. # sub fill { my ($template, %arg) = @_; my $arg; for $arg (keys %arg) { $template =~ s/\@\@$arg\@\@/$arg{$arg}/g; } return $template; } # # HTML template for a selection. # sub selection { return << 'SELECTION'; @@Header@@ @@Title@@ @@Frames@@ @@NoFrames@@ SELECTION } # # HTML template for default error page. # sub failure { my ($target, $errmsg) = @_; return << "FAILURE"; Content-type: text/html$target error: select.cgi error in select.cgi
$errmsg

Try again? Bug report? FAILURE }