#!/usr/bin/perl -w # # frame_generator # # AUTHOR: # Dan Harkless http://harkless.org/dan/software/ # # COPYRIGHT: # This file is Copyright (C) 2008 by Dan Harkless, and is released under the # GNU General Public License . # # DESCRIPTION: # Generates an HTML 4.01 Frameset on the fly. # # PARAMETERS: # cols # The value to use for the 'cols' attribute of the tag. # # frame # The URL for the th frame (e.g. "frame1", "frame2", ...). # # ncols # Instead of specifying an exact column specification, one can call # frame_generator with this parameter instead, which simply specifies the # number of equal-width columns to generate. This can be useful, for # instance, when you have a simple HTML form needs to be able to generate a # frameset with an arbitrary number of columns. # # If not enough frame parameters are specified (which would be the case, # again, in our static form example) to fill out ncols * nrows, the last # frame specified will be repeated as necessary. This repetition does not # occur when not using ncols or nrows. # # nrows # nrows is to rows as ncols is to cols. # # rows # The value to use for the 'rows' attribute of the tag. # # title # The title for the frameset page. If not specified, tht title defaults to # "Frameset generated by frame_generator". # # EXAMPLES: # http://site/frame_generator.cgi?cols=200,*&frame1=nav.html&frame2=body.html # http://site/frame_generator.cgi?nrows=3&frame1=buying_guide_table.html # http://site/frame_generator.cgi?rows=25%25,75%25&frame1=1.html&frame2=2.html # # Note that the '%' character needs to be encoded as "%25" in URLs. # # For a live instance of this script, check out the subpages of # . # # DATE MODIFICATION # ========== ================================================================== # 2008-09-02 "use English qw(-no_match_vars)": avoid regex performance penalty. # 2006-02-16 Removed \n from Generator -- Firefox displays it as a funky glyph. # 2003-03-15 Use CGI.pm's DISABLE_UPLOADS and POST_MAX variables to protect # against DoS attacks. POSTs of more than 1 MiB will error. # 2003-01-18 text now explains when additional frames caused by # 'ncols' and/or 'nrows' parameters are just copies of the last one. # 2002-11-21 Original. ## Modules used ################################################################ use CGI; use English qw(-no_match_vars); # allow use of names like @ARG rather than @_ ## Initializations ############################################################# $CGI::DISABLE_UPLOADS = 1; $CGI::POST_MAX = 1048576; # 1 MiB $OUTPUT_AUTOFLUSH = 1; # let the browser render as dynamically as possible ($program_name_no_path = $PROGRAM_NAME) =~ s<.*/><>; $program_name_no_path = html_escape($program_name_no_path); ## Prototypes ################################################################## sub die_pre_html_start; sub html_escape; sub html_head ; ## Subroutines ################################################################# sub die_pre_html_start { print '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">', "\n"; print "<html>\n"; $title = "ERROR from $program_name_no_path"; html_head(); print " <body>\n"; print " <h1>$title:</h1>\n"; print " <p>", @ARG, "</p>\n"; print " </body>\n"; print "</html>\n"; exit 1; } sub html_escape { # This is a copy & paste of CGI.pm's internal escapeHTML() routine except # that I've changed '"' to escape as '&#34'; instead of '&quot;' since the # latter was accidentally left out of the HTML 3.2 DTD, making # http://validator.w3.org/ complain about pages that have transformed # strings like 'Vinyl 12" Single'. Also removed the here-meaningless # 'dontescape' checking. my $toencode = shift; return undef unless defined($toencode); $toencode=~s/&/&amp;/g; $toencode=~s/\"/&\#34;/g; $toencode=~s/>/&gt;/g; $toencode=~s/</&lt;/g; return $toencode; } sub html_head { print " <head>\n"; print " <meta name=\"Generator\" content=\n \"frame_generator, by", ' Dan Harkless &lt;software@harkless.org&gt; --', ' http://harkless.org/dan/software/">' . "\n"; print " <title>$title</title>\n"; print " </head>\n"; } ## HTTP header ################################################################# # Do this first thing in case any errors occur: browser won't be happy if we # print them out before the HTTP header. # # TBD: Output a fake one-minute-in-the-past Last-Modified header like others of # my scripts so the browser can do "Once per session" caching? $cgi = new CGI; if ($cgi->cgi_error()) { # Surprisingly, current browsers (as of 2003) don't respond properly to HTTP # status code 413, so we'll generate an HTML error page rather than calling # $cgi->header($cgi->cgi_error()). die_pre_html_start($cgi->cgi_error()); } print $cgi->header(-type => "text/html; charset=ISO-8859-1"); open(STDERR, ">&" . STDOUT); # duplicate stderr to stdout so we see errors ## Main ######################################################################## $frameset_spec = ""; $total_frames_needed = 1; $cols = $cgi->param('cols'); if ($cols) { $cols = html_escape($cols); $frameset_spec .= " cols='$cols'"; } $ncols = $cgi->param('ncols'); if ($ncols) { if ($cols) { die_pre_html_start("<tt>cols</tt> and <tt>ncols</tt> may not both be", " specified."); } $total_frames_needed = $ncols; $percentage = 100 / $ncols; $frameset_spec .= " cols='$percentage%"; $i = $ncols - 1; while ($i > 0) { $frameset_spec .= ",$percentage%"; $i--; } $frameset_spec .= "'"; } $rows = $cgi->param('rows'); if ($rows) { $rows = html_escape($rows); $frameset_spec .= " rows='$rows'"; } $nrows = $cgi->param('nrows'); if ($nrows) { if ($rows) { die_pre_html_start("<tt>rows</tt> and <tt>nrows</tt> may not both be", " specified."); } $total_frames_needed *= $nrows; $percentage = 100 / $nrows; $frameset_spec .= " rows='$percentage%"; $i = $nrows - 1; while ($i > 0) { $frameset_spec .= ",$percentage%"; $i--; } $frameset_spec .= "'"; } if (not $frameset_spec) { die_pre_html_start("At least one of the parameters <tt>cols</tt>,", " <tt>ncols</tt>, <tt>nrows</tt>, or <tt>rows</tt>", " must be specified."); } $title = $cgi->param('title'); if (not $title) { $title = "Frameset generated by $program_name_no_path"; } $title = html_escape($title); print '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">', "\n"; print "<html>\n"; html_head(); print " <frameset$frameset_spec>\n"; $i = 1; while ($frame_url = $cgi->param("frame$i")) { $frame_url = html_escape($frame_url); print " <frame src='$frame_url'>\n"; $i++; $last_frame_url = $frame_url; } if ($ncols or $nrows) { while ($i <= $total_frames_needed) { print " <frame src='$last_frame_url'>\n"; $i++; } } print " <noframes>\n"; print " <p>If you're seeing this, your browser apparently does not have\n"; print " frame support. Here are links to the individual frames:</p>\n"; $i = 1; while ($frame_url = $cgi->param("frame$i")) { $frame_url = html_escape($frame_url); print " <p>Frame $i: <a href='$frame_url'>$frame_url</a></p>\n"; $i++; } if (($ncols or $nrows) and $i <= $total_frames_needed) { print " <p>(Additional frames which were caused by the <tt>ncols</tt>\n"; print " and/or <tt>nrows</tt> parameters are just copies of that last\n"; print " frame.)</p>\n"; } print " <hr>\n"; print ' <a href="http://validator.w3.org/check/referer">Validated HTML 4.01', " Frameset</a><br>\n"; print " Generated by:\n"; print ' <a href="http://harkless.org/dan/software/#frame_generator"', ">frame_generator</a>\n"; print " \n"; print " \n"; print "\n";