xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/CGI.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gatepackage CGI;
2*0Sstevel@tonic-gaterequire 5.004;
3*0Sstevel@tonic-gateuse Carp 'croak';
4*0Sstevel@tonic-gate
5*0Sstevel@tonic-gate# See the bottom of this file for the POD documentation.  Search for the
6*0Sstevel@tonic-gate# string '=head'.
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate# You can run this file through either pod2man or pod2html to produce pretty
9*0Sstevel@tonic-gate# documentation in manual or html file format (these utilities are part of the
10*0Sstevel@tonic-gate# Perl 5 distribution).
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gate# Copyright 1995-1998 Lincoln D. Stein.  All rights reserved.
13*0Sstevel@tonic-gate# It may be used and modified freely, but I do request that this copyright
14*0Sstevel@tonic-gate# notice remain attached to the file.  You may modify this module as you
15*0Sstevel@tonic-gate# wish, but if you redistribute a modified version, please attach a note
16*0Sstevel@tonic-gate# listing the modifications you have made.
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate# The most recent version and complete docs are available at:
19*0Sstevel@tonic-gate#   http://stein.cshl.org/WWW/software/CGI/
20*0Sstevel@tonic-gate
21*0Sstevel@tonic-gate$CGI::revision = '$Id: CGI.pm,v 1.151 2004/01/13 16:28:35 lstein Exp $';
22*0Sstevel@tonic-gate$CGI::VERSION=3.04;
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate# HARD-CODED LOCATION FOR FILE UPLOAD TEMPORARY FILES.
25*0Sstevel@tonic-gate# UNCOMMENT THIS ONLY IF YOU KNOW WHAT YOU'RE DOING.
26*0Sstevel@tonic-gate# $CGITempFile::TMPDIRECTORY = '/usr/tmp';
27*0Sstevel@tonic-gateuse CGI::Util qw(rearrange make_attributes unescape escape expires ebcdic2ascii ascii2ebcdic);
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate#use constant XHTML_DTD => ['-//W3C//DTD XHTML Basic 1.0//EN',
30*0Sstevel@tonic-gate#                           'http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd'];
31*0Sstevel@tonic-gate
32*0Sstevel@tonic-gateuse constant XHTML_DTD => ['-//W3C//DTD XHTML 1.0 Transitional//EN',
33*0Sstevel@tonic-gate                           'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'];
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate{
36*0Sstevel@tonic-gate  local $^W = 0;
37*0Sstevel@tonic-gate  $TAINTED = substr("$0$^X",0,0);
38*0Sstevel@tonic-gate}
39*0Sstevel@tonic-gate
40*0Sstevel@tonic-gatemy @SAVED_SYMBOLS;
41*0Sstevel@tonic-gate
42*0Sstevel@tonic-gate$MOD_PERL = 0; # no mod_perl by default
43*0Sstevel@tonic-gate
44*0Sstevel@tonic-gate# >>>>> Here are some globals that you might want to adjust <<<<<<
45*0Sstevel@tonic-gatesub initialize_globals {
46*0Sstevel@tonic-gate    # Set this to 1 to enable copious autoloader debugging messages
47*0Sstevel@tonic-gate    $AUTOLOAD_DEBUG = 0;
48*0Sstevel@tonic-gate
49*0Sstevel@tonic-gate    # Set this to 1 to generate XTML-compatible output
50*0Sstevel@tonic-gate    $XHTML = 1;
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gate    # Change this to the preferred DTD to print in start_html()
53*0Sstevel@tonic-gate    # or use default_dtd('text of DTD to use');
54*0Sstevel@tonic-gate    $DEFAULT_DTD = [ '-//W3C//DTD HTML 4.01 Transitional//EN',
55*0Sstevel@tonic-gate		     'http://www.w3.org/TR/html4/loose.dtd' ] ;
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate    # Set this to 1 to enable NOSTICKY scripts
58*0Sstevel@tonic-gate    # or:
59*0Sstevel@tonic-gate    #    1) use CGI qw(-nosticky)
60*0Sstevel@tonic-gate    #    2) $CGI::nosticky(1)
61*0Sstevel@tonic-gate    $NOSTICKY = 0;
62*0Sstevel@tonic-gate
63*0Sstevel@tonic-gate    # Set this to 1 to enable NPH scripts
64*0Sstevel@tonic-gate    # or:
65*0Sstevel@tonic-gate    #    1) use CGI qw(-nph)
66*0Sstevel@tonic-gate    #    2) CGI::nph(1)
67*0Sstevel@tonic-gate    #    3) print header(-nph=>1)
68*0Sstevel@tonic-gate    $NPH = 0;
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate    # Set this to 1 to enable debugging from @ARGV
71*0Sstevel@tonic-gate    # Set to 2 to enable debugging from STDIN
72*0Sstevel@tonic-gate    $DEBUG = 1;
73*0Sstevel@tonic-gate
74*0Sstevel@tonic-gate    # Set this to 1 to make the temporary files created
75*0Sstevel@tonic-gate    # during file uploads safe from prying eyes
76*0Sstevel@tonic-gate    # or do...
77*0Sstevel@tonic-gate    #    1) use CGI qw(:private_tempfiles)
78*0Sstevel@tonic-gate    #    2) CGI::private_tempfiles(1);
79*0Sstevel@tonic-gate    $PRIVATE_TEMPFILES = 0;
80*0Sstevel@tonic-gate
81*0Sstevel@tonic-gate    # Set this to 1 to cause files uploaded in multipart documents
82*0Sstevel@tonic-gate    # to be closed, instead of caching the file handle
83*0Sstevel@tonic-gate    # or:
84*0Sstevel@tonic-gate    #    1) use CGI qw(:close_upload_files)
85*0Sstevel@tonic-gate    #    2) $CGI::close_upload_files(1);
86*0Sstevel@tonic-gate    # Uploads with many files run out of file handles.
87*0Sstevel@tonic-gate    # Also, for performance, since the file is already on disk,
88*0Sstevel@tonic-gate    # it can just be renamed, instead of read and written.
89*0Sstevel@tonic-gate    $CLOSE_UPLOAD_FILES = 0;
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate    # Set this to a positive value to limit the size of a POSTing
92*0Sstevel@tonic-gate    # to a certain number of bytes:
93*0Sstevel@tonic-gate    $POST_MAX = -1;
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate    # Change this to 1 to disable uploads entirely:
96*0Sstevel@tonic-gate    $DISABLE_UPLOADS = 0;
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gate    # Automatically determined -- don't change
99*0Sstevel@tonic-gate    $EBCDIC = 0;
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate    # Change this to 1 to suppress redundant HTTP headers
102*0Sstevel@tonic-gate    $HEADERS_ONCE = 0;
103*0Sstevel@tonic-gate
104*0Sstevel@tonic-gate    # separate the name=value pairs by semicolons rather than ampersands
105*0Sstevel@tonic-gate    $USE_PARAM_SEMICOLONS = 1;
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate    # Do not include undefined params parsed from query string
108*0Sstevel@tonic-gate    # use CGI qw(-no_undef_params);
109*0Sstevel@tonic-gate    $NO_UNDEF_PARAMS = 0;
110*0Sstevel@tonic-gate
111*0Sstevel@tonic-gate    # Other globals that you shouldn't worry about.
112*0Sstevel@tonic-gate    undef $Q;
113*0Sstevel@tonic-gate    $BEEN_THERE = 0;
114*0Sstevel@tonic-gate    undef @QUERY_PARAM;
115*0Sstevel@tonic-gate    undef %EXPORT;
116*0Sstevel@tonic-gate    undef $QUERY_CHARSET;
117*0Sstevel@tonic-gate    undef %QUERY_FIELDNAMES;
118*0Sstevel@tonic-gate
119*0Sstevel@tonic-gate    # prevent complaints by mod_perl
120*0Sstevel@tonic-gate    1;
121*0Sstevel@tonic-gate}
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate# ------------------ START OF THE LIBRARY ------------
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate# make mod_perlhappy
126*0Sstevel@tonic-gateinitialize_globals();
127*0Sstevel@tonic-gate
128*0Sstevel@tonic-gate# FIGURE OUT THE OS WE'RE RUNNING UNDER
129*0Sstevel@tonic-gate# Some systems support the $^O variable.  If not
130*0Sstevel@tonic-gate# available then require() the Config library
131*0Sstevel@tonic-gateunless ($OS) {
132*0Sstevel@tonic-gate    unless ($OS = $^O) {
133*0Sstevel@tonic-gate	require Config;
134*0Sstevel@tonic-gate	$OS = $Config::Config{'osname'};
135*0Sstevel@tonic-gate    }
136*0Sstevel@tonic-gate}
137*0Sstevel@tonic-gateif ($OS =~ /^MSWin/i) {
138*0Sstevel@tonic-gate  $OS = 'WINDOWS';
139*0Sstevel@tonic-gate} elsif ($OS =~ /^VMS/i) {
140*0Sstevel@tonic-gate  $OS = 'VMS';
141*0Sstevel@tonic-gate} elsif ($OS =~ /^dos/i) {
142*0Sstevel@tonic-gate  $OS = 'DOS';
143*0Sstevel@tonic-gate} elsif ($OS =~ /^MacOS/i) {
144*0Sstevel@tonic-gate    $OS = 'MACINTOSH';
145*0Sstevel@tonic-gate} elsif ($OS =~ /^os2/i) {
146*0Sstevel@tonic-gate    $OS = 'OS2';
147*0Sstevel@tonic-gate} elsif ($OS =~ /^epoc/i) {
148*0Sstevel@tonic-gate    $OS = 'EPOC';
149*0Sstevel@tonic-gate} elsif ($OS =~ /^cygwin/i) {
150*0Sstevel@tonic-gate    $OS = 'CYGWIN';
151*0Sstevel@tonic-gate} else {
152*0Sstevel@tonic-gate    $OS = 'UNIX';
153*0Sstevel@tonic-gate}
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gate# Some OS logic.  Binary mode enabled on DOS, NT and VMS
156*0Sstevel@tonic-gate$needs_binmode = $OS=~/^(WINDOWS|DOS|OS2|MSWin|CYGWIN)/;
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gate# This is the default class for the CGI object to use when all else fails.
159*0Sstevel@tonic-gate$DefaultClass = 'CGI' unless defined $CGI::DefaultClass;
160*0Sstevel@tonic-gate
161*0Sstevel@tonic-gate# This is where to look for autoloaded routines.
162*0Sstevel@tonic-gate$AutoloadClass = $DefaultClass unless defined $CGI::AutoloadClass;
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate# The path separator is a slash, backslash or semicolon, depending
165*0Sstevel@tonic-gate# on the paltform.
166*0Sstevel@tonic-gate$SL = {
167*0Sstevel@tonic-gate     UNIX    => '/',  OS2 => '\\', EPOC      => '/', CYGWIN => '/',
168*0Sstevel@tonic-gate     WINDOWS => '\\', DOS => '\\', MACINTOSH => ':', VMS    => '/'
169*0Sstevel@tonic-gate    }->{$OS};
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate# This no longer seems to be necessary
172*0Sstevel@tonic-gate# Turn on NPH scripts by default when running under IIS server!
173*0Sstevel@tonic-gate# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;
174*0Sstevel@tonic-gate$IIS++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gate# Turn on special checking for Doug MacEachern's modperl
177*0Sstevel@tonic-gateif (exists $ENV{MOD_PERL}) {
178*0Sstevel@tonic-gate  eval "require mod_perl";
179*0Sstevel@tonic-gate  # mod_perl handlers may run system() on scripts using CGI.pm;
180*0Sstevel@tonic-gate  # Make sure so we don't get fooled by inherited $ENV{MOD_PERL}
181*0Sstevel@tonic-gate  if (defined $mod_perl::VERSION) {
182*0Sstevel@tonic-gate    if ($mod_perl::VERSION >= 1.99) {
183*0Sstevel@tonic-gate      $MOD_PERL = 2;
184*0Sstevel@tonic-gate      require Apache::Response;
185*0Sstevel@tonic-gate      require Apache::RequestRec;
186*0Sstevel@tonic-gate      require Apache::RequestUtil;
187*0Sstevel@tonic-gate      require APR::Pool;
188*0Sstevel@tonic-gate    } else {
189*0Sstevel@tonic-gate      $MOD_PERL = 1;
190*0Sstevel@tonic-gate      require Apache;
191*0Sstevel@tonic-gate    }
192*0Sstevel@tonic-gate  }
193*0Sstevel@tonic-gate}
194*0Sstevel@tonic-gate
195*0Sstevel@tonic-gate# Turn on special checking for ActiveState's PerlEx
196*0Sstevel@tonic-gate$PERLEX++ if defined($ENV{'GATEWAY_INTERFACE'}) && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/;
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate# Define the CRLF sequence.  I can't use a simple "\r\n" because the meaning
199*0Sstevel@tonic-gate# of "\n" is different on different OS's (sometimes it generates CRLF, sometimes LF
200*0Sstevel@tonic-gate# and sometimes CR).  The most popular VMS web server
201*0Sstevel@tonic-gate# doesn't accept CRLF -- instead it wants a LR.  EBCDIC machines don't
202*0Sstevel@tonic-gate# use ASCII, so \015\012 means something different.  I find this all
203*0Sstevel@tonic-gate# really annoying.
204*0Sstevel@tonic-gate$EBCDIC = "\t" ne "\011";
205*0Sstevel@tonic-gateif ($OS eq 'VMS') {
206*0Sstevel@tonic-gate  $CRLF = "\n";
207*0Sstevel@tonic-gate} elsif ($EBCDIC) {
208*0Sstevel@tonic-gate  $CRLF= "\r\n";
209*0Sstevel@tonic-gate} else {
210*0Sstevel@tonic-gate  $CRLF = "\015\012";
211*0Sstevel@tonic-gate}
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gateif ($needs_binmode) {
214*0Sstevel@tonic-gate    $CGI::DefaultClass->binmode(\*main::STDOUT);
215*0Sstevel@tonic-gate    $CGI::DefaultClass->binmode(\*main::STDIN);
216*0Sstevel@tonic-gate    $CGI::DefaultClass->binmode(\*main::STDERR);
217*0Sstevel@tonic-gate}
218*0Sstevel@tonic-gate
219*0Sstevel@tonic-gate%EXPORT_TAGS = (
220*0Sstevel@tonic-gate		':html2'=>['h1'..'h6',qw/p br hr ol ul li dl dt dd menu code var strong em
221*0Sstevel@tonic-gate			   tt u i b blockquote pre img a address cite samp dfn html head
222*0Sstevel@tonic-gate			   base body Link nextid title meta kbd start_html end_html
223*0Sstevel@tonic-gate			   input Select option comment charset escapeHTML/],
224*0Sstevel@tonic-gate		':html3'=>[qw/div table caption th td TR Tr sup Sub strike applet Param
225*0Sstevel@tonic-gate			   embed basefont style span layer ilayer font frameset frame script small big Area Map/],
226*0Sstevel@tonic-gate                ':html4'=>[qw/abbr acronym bdo col colgroup del fieldset iframe
227*0Sstevel@tonic-gate                            ins label legend noframes noscript object optgroup Q
228*0Sstevel@tonic-gate                            thead tbody tfoot/],
229*0Sstevel@tonic-gate		':netscape'=>[qw/blink fontsize center/],
230*0Sstevel@tonic-gate		':form'=>[qw/textfield textarea filefield password_field hidden checkbox checkbox_group
231*0Sstevel@tonic-gate			  submit reset defaults radio_group popup_menu button autoEscape
232*0Sstevel@tonic-gate			  scrolling_list image_button start_form end_form startform endform
233*0Sstevel@tonic-gate			  start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART/],
234*0Sstevel@tonic-gate		':cgi'=>[qw/param upload path_info path_translated url self_url script_name cookie Dump
235*0Sstevel@tonic-gate			 raw_cookie request_method query_string Accept user_agent remote_host content_type
236*0Sstevel@tonic-gate			 remote_addr referer server_name server_software server_port server_protocol virtual_port
237*0Sstevel@tonic-gate			 virtual_host remote_ident auth_type http append
238*0Sstevel@tonic-gate			 save_parameters restore_parameters param_fetch
239*0Sstevel@tonic-gate			 remote_user user_name header redirect import_names put
240*0Sstevel@tonic-gate			 Delete Delete_all url_param cgi_error/],
241*0Sstevel@tonic-gate		':ssl' => [qw/https/],
242*0Sstevel@tonic-gate		':cgi-lib' => [qw/ReadParse PrintHeader HtmlTop HtmlBot SplitParam Vars/],
243*0Sstevel@tonic-gate		':html' => [qw/:html2 :html3 :html4 :netscape/],
244*0Sstevel@tonic-gate		':standard' => [qw/:html2 :html3 :html4 :form :cgi/],
245*0Sstevel@tonic-gate		':push' => [qw/multipart_init multipart_start multipart_end multipart_final/],
246*0Sstevel@tonic-gate		':all' => [qw/:html2 :html3 :netscape :form :cgi :internal :html4/]
247*0Sstevel@tonic-gate		);
248*0Sstevel@tonic-gate
249*0Sstevel@tonic-gate# to import symbols into caller
250*0Sstevel@tonic-gatesub import {
251*0Sstevel@tonic-gate    my $self = shift;
252*0Sstevel@tonic-gate
253*0Sstevel@tonic-gate    # This causes modules to clash.
254*0Sstevel@tonic-gate    undef %EXPORT_OK;
255*0Sstevel@tonic-gate    undef %EXPORT;
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate    $self->_setup_symbols(@_);
258*0Sstevel@tonic-gate    my ($callpack, $callfile, $callline) = caller;
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate    # To allow overriding, search through the packages
261*0Sstevel@tonic-gate    # Till we find one in which the correct subroutine is defined.
262*0Sstevel@tonic-gate    my @packages = ($self,@{"$self\:\:ISA"});
263*0Sstevel@tonic-gate    foreach $sym (keys %EXPORT) {
264*0Sstevel@tonic-gate	my $pck;
265*0Sstevel@tonic-gate	my $def = ${"$self\:\:AutoloadClass"} || $DefaultClass;
266*0Sstevel@tonic-gate	foreach $pck (@packages) {
267*0Sstevel@tonic-gate	    if (defined(&{"$pck\:\:$sym"})) {
268*0Sstevel@tonic-gate		$def = $pck;
269*0Sstevel@tonic-gate		last;
270*0Sstevel@tonic-gate	    }
271*0Sstevel@tonic-gate	}
272*0Sstevel@tonic-gate	*{"${callpack}::$sym"} = \&{"$def\:\:$sym"};
273*0Sstevel@tonic-gate    }
274*0Sstevel@tonic-gate}
275*0Sstevel@tonic-gate
276*0Sstevel@tonic-gatesub compile {
277*0Sstevel@tonic-gate    my $pack = shift;
278*0Sstevel@tonic-gate    $pack->_setup_symbols('-compile',@_);
279*0Sstevel@tonic-gate}
280*0Sstevel@tonic-gate
281*0Sstevel@tonic-gatesub expand_tags {
282*0Sstevel@tonic-gate    my($tag) = @_;
283*0Sstevel@tonic-gate    return ("start_$1","end_$1") if $tag=~/^(?:\*|start_|end_)(.+)/;
284*0Sstevel@tonic-gate    my(@r);
285*0Sstevel@tonic-gate    return ($tag) unless $EXPORT_TAGS{$tag};
286*0Sstevel@tonic-gate    foreach (@{$EXPORT_TAGS{$tag}}) {
287*0Sstevel@tonic-gate	push(@r,&expand_tags($_));
288*0Sstevel@tonic-gate    }
289*0Sstevel@tonic-gate    return @r;
290*0Sstevel@tonic-gate}
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gate#### Method: new
293*0Sstevel@tonic-gate# The new routine.  This will check the current environment
294*0Sstevel@tonic-gate# for an existing query string, and initialize itself, if so.
295*0Sstevel@tonic-gate####
296*0Sstevel@tonic-gatesub new {
297*0Sstevel@tonic-gate  my($class,@initializer) = @_;
298*0Sstevel@tonic-gate  my $self = {};
299*0Sstevel@tonic-gate
300*0Sstevel@tonic-gate  bless $self,ref $class || $class || $DefaultClass;
301*0Sstevel@tonic-gate  if (ref($initializer[0])
302*0Sstevel@tonic-gate      && (UNIVERSAL::isa($initializer[0],'Apache')
303*0Sstevel@tonic-gate	  ||
304*0Sstevel@tonic-gate	  UNIVERSAL::isa($initializer[0],'Apache::RequestRec')
305*0Sstevel@tonic-gate	 )) {
306*0Sstevel@tonic-gate    $self->r(shift @initializer);
307*0Sstevel@tonic-gate  }
308*0Sstevel@tonic-gate if (ref($initializer[0])
309*0Sstevel@tonic-gate     && (UNIVERSAL::isa($initializer[0],'CODE'))) {
310*0Sstevel@tonic-gate    $self->upload_hook(shift @initializer, shift @initializer);
311*0Sstevel@tonic-gate  }
312*0Sstevel@tonic-gate  if ($MOD_PERL) {
313*0Sstevel@tonic-gate    $self->r(Apache->request) unless $self->r;
314*0Sstevel@tonic-gate    my $r = $self->r;
315*0Sstevel@tonic-gate    if ($MOD_PERL == 1) {
316*0Sstevel@tonic-gate      $r->register_cleanup(\&CGI::_reset_globals);
317*0Sstevel@tonic-gate    }
318*0Sstevel@tonic-gate    else {
319*0Sstevel@tonic-gate      # XXX: once we have the new API
320*0Sstevel@tonic-gate      # will do a real PerlOptions -SetupEnv check
321*0Sstevel@tonic-gate      $r->subprocess_env unless exists $ENV{REQUEST_METHOD};
322*0Sstevel@tonic-gate      $r->pool->cleanup_register(\&CGI::_reset_globals);
323*0Sstevel@tonic-gate    }
324*0Sstevel@tonic-gate    undef $NPH;
325*0Sstevel@tonic-gate  }
326*0Sstevel@tonic-gate  $self->_reset_globals if $PERLEX;
327*0Sstevel@tonic-gate  $self->init(@initializer);
328*0Sstevel@tonic-gate  return $self;
329*0Sstevel@tonic-gate}
330*0Sstevel@tonic-gate
331*0Sstevel@tonic-gate# We provide a DESTROY method so that we can ensure that
332*0Sstevel@tonic-gate# temporary files are closed (via Fh->DESTROY) before they
333*0Sstevel@tonic-gate# are unlinked (via CGITempFile->DESTROY) because it is not
334*0Sstevel@tonic-gate# possible to unlink an open file on Win32. We explicitly
335*0Sstevel@tonic-gate# call DESTROY on each, rather than just undefing them and
336*0Sstevel@tonic-gate# letting Perl DESTROY them by garbage collection, in case the
337*0Sstevel@tonic-gate# user is still holding any reference to them as well.
338*0Sstevel@tonic-gatesub DESTROY {
339*0Sstevel@tonic-gate  my $self = shift;
340*0Sstevel@tonic-gate  foreach my $href (values %{$self->{'.tmpfiles'}}) {
341*0Sstevel@tonic-gate    $href->{hndl}->DESTROY if defined $href->{hndl};
342*0Sstevel@tonic-gate    $href->{name}->DESTROY if defined $href->{name};
343*0Sstevel@tonic-gate  }
344*0Sstevel@tonic-gate}
345*0Sstevel@tonic-gate
346*0Sstevel@tonic-gatesub r {
347*0Sstevel@tonic-gate  my $self = shift;
348*0Sstevel@tonic-gate  my $r = $self->{'.r'};
349*0Sstevel@tonic-gate  $self->{'.r'} = shift if @_;
350*0Sstevel@tonic-gate  $r;
351*0Sstevel@tonic-gate}
352*0Sstevel@tonic-gate
353*0Sstevel@tonic-gatesub upload_hook {
354*0Sstevel@tonic-gate  my ($self,$hook,$data) = self_or_default(@_);
355*0Sstevel@tonic-gate  $self->{'.upload_hook'} = $hook;
356*0Sstevel@tonic-gate  $self->{'.upload_data'} = $data;
357*0Sstevel@tonic-gate}
358*0Sstevel@tonic-gate
359*0Sstevel@tonic-gate#### Method: param
360*0Sstevel@tonic-gate# Returns the value(s)of a named parameter.
361*0Sstevel@tonic-gate# If invoked in a list context, returns the
362*0Sstevel@tonic-gate# entire list.  Otherwise returns the first
363*0Sstevel@tonic-gate# member of the list.
364*0Sstevel@tonic-gate# If name is not provided, return a list of all
365*0Sstevel@tonic-gate# the known parameters names available.
366*0Sstevel@tonic-gate# If more than one argument is provided, the
367*0Sstevel@tonic-gate# second and subsequent arguments are used to
368*0Sstevel@tonic-gate# set the value of the parameter.
369*0Sstevel@tonic-gate####
370*0Sstevel@tonic-gatesub param {
371*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
372*0Sstevel@tonic-gate    return $self->all_parameters unless @p;
373*0Sstevel@tonic-gate    my($name,$value,@other);
374*0Sstevel@tonic-gate
375*0Sstevel@tonic-gate    # For compatibility between old calling style and use_named_parameters() style,
376*0Sstevel@tonic-gate    # we have to special case for a single parameter present.
377*0Sstevel@tonic-gate    if (@p > 1) {
378*0Sstevel@tonic-gate	($name,$value,@other) = rearrange([NAME,[DEFAULT,VALUE,VALUES]],@p);
379*0Sstevel@tonic-gate	my(@values);
380*0Sstevel@tonic-gate
381*0Sstevel@tonic-gate	if (substr($p[0],0,1) eq '-') {
382*0Sstevel@tonic-gate	    @values = defined($value) ? (ref($value) && ref($value) eq 'ARRAY' ? @{$value} : $value) : ();
383*0Sstevel@tonic-gate	} else {
384*0Sstevel@tonic-gate	    foreach ($value,@other) {
385*0Sstevel@tonic-gate		push(@values,$_) if defined($_);
386*0Sstevel@tonic-gate	    }
387*0Sstevel@tonic-gate	}
388*0Sstevel@tonic-gate	# If values is provided, then we set it.
389*0Sstevel@tonic-gate	if (@values) {
390*0Sstevel@tonic-gate	    $self->add_parameter($name);
391*0Sstevel@tonic-gate	    $self->{$name}=[@values];
392*0Sstevel@tonic-gate	}
393*0Sstevel@tonic-gate    } else {
394*0Sstevel@tonic-gate	$name = $p[0];
395*0Sstevel@tonic-gate    }
396*0Sstevel@tonic-gate
397*0Sstevel@tonic-gate    return unless defined($name) && $self->{$name};
398*0Sstevel@tonic-gate    return wantarray ? @{$self->{$name}} : $self->{$name}->[0];
399*0Sstevel@tonic-gate}
400*0Sstevel@tonic-gate
401*0Sstevel@tonic-gatesub self_or_default {
402*0Sstevel@tonic-gate    return @_ if defined($_[0]) && (!ref($_[0])) &&($_[0] eq 'CGI');
403*0Sstevel@tonic-gate    unless (defined($_[0]) &&
404*0Sstevel@tonic-gate	    (ref($_[0]) eq 'CGI' || UNIVERSAL::isa($_[0],'CGI')) # slightly optimized for common case
405*0Sstevel@tonic-gate	    ) {
406*0Sstevel@tonic-gate	$Q = $CGI::DefaultClass->new unless defined($Q);
407*0Sstevel@tonic-gate	unshift(@_,$Q);
408*0Sstevel@tonic-gate    }
409*0Sstevel@tonic-gate    return wantarray ? @_ : $Q;
410*0Sstevel@tonic-gate}
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gatesub self_or_CGI {
413*0Sstevel@tonic-gate    local $^W=0;                # prevent a warning
414*0Sstevel@tonic-gate    if (defined($_[0]) &&
415*0Sstevel@tonic-gate	(substr(ref($_[0]),0,3) eq 'CGI'
416*0Sstevel@tonic-gate	 || UNIVERSAL::isa($_[0],'CGI'))) {
417*0Sstevel@tonic-gate	return @_;
418*0Sstevel@tonic-gate    } else {
419*0Sstevel@tonic-gate	return ($DefaultClass,@_);
420*0Sstevel@tonic-gate    }
421*0Sstevel@tonic-gate}
422*0Sstevel@tonic-gate
423*0Sstevel@tonic-gate########################################
424*0Sstevel@tonic-gate# THESE METHODS ARE MORE OR LESS PRIVATE
425*0Sstevel@tonic-gate# GO TO THE __DATA__ SECTION TO SEE MORE
426*0Sstevel@tonic-gate# PUBLIC METHODS
427*0Sstevel@tonic-gate########################################
428*0Sstevel@tonic-gate
429*0Sstevel@tonic-gate# Initialize the query object from the environment.
430*0Sstevel@tonic-gate# If a parameter list is found, this object will be set
431*0Sstevel@tonic-gate# to an associative array in which parameter names are keys
432*0Sstevel@tonic-gate# and the values are stored as lists
433*0Sstevel@tonic-gate# If a keyword list is found, this method creates a bogus
434*0Sstevel@tonic-gate# parameter list with the single parameter 'keywords'.
435*0Sstevel@tonic-gate
436*0Sstevel@tonic-gatesub init {
437*0Sstevel@tonic-gate  my $self = shift;
438*0Sstevel@tonic-gate  my($query_string,$meth,$content_length,$fh,@lines) = ('','','','');
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate  my $initializer = shift;  # for backward compatibility
441*0Sstevel@tonic-gate  local($/) = "\n";
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate    # set autoescaping on by default
444*0Sstevel@tonic-gate    $self->{'escape'} = 1;
445*0Sstevel@tonic-gate
446*0Sstevel@tonic-gate    # if we get called more than once, we want to initialize
447*0Sstevel@tonic-gate    # ourselves from the original query (which may be gone
448*0Sstevel@tonic-gate    # if it was read from STDIN originally.)
449*0Sstevel@tonic-gate    if (defined(@QUERY_PARAM) && !defined($initializer)) {
450*0Sstevel@tonic-gate	foreach (@QUERY_PARAM) {
451*0Sstevel@tonic-gate	    $self->param('-name'=>$_,'-value'=>$QUERY_PARAM{$_});
452*0Sstevel@tonic-gate	}
453*0Sstevel@tonic-gate	$self->charset($QUERY_CHARSET);
454*0Sstevel@tonic-gate	$self->{'.fieldnames'} = {%QUERY_FIELDNAMES};
455*0Sstevel@tonic-gate	return;
456*0Sstevel@tonic-gate    }
457*0Sstevel@tonic-gate
458*0Sstevel@tonic-gate    $meth=$ENV{'REQUEST_METHOD'} if defined($ENV{'REQUEST_METHOD'});
459*0Sstevel@tonic-gate    $content_length = defined($ENV{'CONTENT_LENGTH'}) ? $ENV{'CONTENT_LENGTH'} : 0;
460*0Sstevel@tonic-gate
461*0Sstevel@tonic-gate    $fh = to_filehandle($initializer) if $initializer;
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate    # set charset to the safe ISO-8859-1
464*0Sstevel@tonic-gate    $self->charset('ISO-8859-1');
465*0Sstevel@tonic-gate
466*0Sstevel@tonic-gate  METHOD: {
467*0Sstevel@tonic-gate
468*0Sstevel@tonic-gate      # avoid unreasonably large postings
469*0Sstevel@tonic-gate      if (($POST_MAX > 0) && ($content_length > $POST_MAX)) {
470*0Sstevel@tonic-gate	# quietly read and discard the post
471*0Sstevel@tonic-gate	  my $buffer;
472*0Sstevel@tonic-gate	  my $max = $content_length;
473*0Sstevel@tonic-gate	  while ($max > 0 &&
474*0Sstevel@tonic-gate		 (my $bytes = $MOD_PERL
475*0Sstevel@tonic-gate                  ? $self->r->read($buffer,$max < 10000 ? $max : 10000)
476*0Sstevel@tonic-gate                  : read(STDIN,$buffer,$max < 10000 ? $max : 10000)
477*0Sstevel@tonic-gate                 )) {
478*0Sstevel@tonic-gate	    $self->cgi_error("413 Request entity too large");
479*0Sstevel@tonic-gate	    last METHOD;
480*0Sstevel@tonic-gate	  }
481*0Sstevel@tonic-gate	}
482*0Sstevel@tonic-gate
483*0Sstevel@tonic-gate      # Process multipart postings, but only if the initializer is
484*0Sstevel@tonic-gate      # not defined.
485*0Sstevel@tonic-gate      if ($meth eq 'POST'
486*0Sstevel@tonic-gate	  && defined($ENV{'CONTENT_TYPE'})
487*0Sstevel@tonic-gate	  && $ENV{'CONTENT_TYPE'}=~m|^multipart/form-data|
488*0Sstevel@tonic-gate	  && !defined($initializer)
489*0Sstevel@tonic-gate	  ) {
490*0Sstevel@tonic-gate	  my($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\"?/;
491*0Sstevel@tonic-gate	  $self->read_multipart($boundary,$content_length);
492*0Sstevel@tonic-gate	  last METHOD;
493*0Sstevel@tonic-gate      }
494*0Sstevel@tonic-gate
495*0Sstevel@tonic-gate      # If initializer is defined, then read parameters
496*0Sstevel@tonic-gate      # from it.
497*0Sstevel@tonic-gate      if (defined($initializer)) {
498*0Sstevel@tonic-gate	  if (UNIVERSAL::isa($initializer,'CGI')) {
499*0Sstevel@tonic-gate	      $query_string = $initializer->query_string;
500*0Sstevel@tonic-gate	      last METHOD;
501*0Sstevel@tonic-gate	  }
502*0Sstevel@tonic-gate	  if (ref($initializer) && ref($initializer) eq 'HASH') {
503*0Sstevel@tonic-gate	      foreach (keys %$initializer) {
504*0Sstevel@tonic-gate		  $self->param('-name'=>$_,'-value'=>$initializer->{$_});
505*0Sstevel@tonic-gate	      }
506*0Sstevel@tonic-gate	      last METHOD;
507*0Sstevel@tonic-gate	  }
508*0Sstevel@tonic-gate
509*0Sstevel@tonic-gate	  if (defined($fh) && ($fh ne '')) {
510*0Sstevel@tonic-gate	      while (<$fh>) {
511*0Sstevel@tonic-gate		  chomp;
512*0Sstevel@tonic-gate		  last if /^=/;
513*0Sstevel@tonic-gate		  push(@lines,$_);
514*0Sstevel@tonic-gate	      }
515*0Sstevel@tonic-gate	      # massage back into standard format
516*0Sstevel@tonic-gate	      if ("@lines" =~ /=/) {
517*0Sstevel@tonic-gate		  $query_string=join("&",@lines);
518*0Sstevel@tonic-gate	      } else {
519*0Sstevel@tonic-gate		  $query_string=join("+",@lines);
520*0Sstevel@tonic-gate	      }
521*0Sstevel@tonic-gate	      last METHOD;
522*0Sstevel@tonic-gate	  }
523*0Sstevel@tonic-gate
524*0Sstevel@tonic-gate          if (defined($fh) && ($fh ne '')) {
525*0Sstevel@tonic-gate              while (<$fh>) {
526*0Sstevel@tonic-gate                  chomp;
527*0Sstevel@tonic-gate                  last if /^=/;
528*0Sstevel@tonic-gate                  push(@lines,$_);
529*0Sstevel@tonic-gate              }
530*0Sstevel@tonic-gate              # massage back into standard format
531*0Sstevel@tonic-gate              if ("@lines" =~ /=/) {
532*0Sstevel@tonic-gate                  $query_string=join("&",@lines);
533*0Sstevel@tonic-gate              } else {
534*0Sstevel@tonic-gate                  $query_string=join("+",@lines);
535*0Sstevel@tonic-gate              }
536*0Sstevel@tonic-gate              last METHOD;
537*0Sstevel@tonic-gate          }
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate	  # last chance -- treat it as a string
540*0Sstevel@tonic-gate	  $initializer = $$initializer if ref($initializer) eq 'SCALAR';
541*0Sstevel@tonic-gate	  $query_string = $initializer;
542*0Sstevel@tonic-gate
543*0Sstevel@tonic-gate	  last METHOD;
544*0Sstevel@tonic-gate      }
545*0Sstevel@tonic-gate
546*0Sstevel@tonic-gate      # If method is GET or HEAD, fetch the query from
547*0Sstevel@tonic-gate      # the environment.
548*0Sstevel@tonic-gate      if ($meth=~/^(GET|HEAD)$/) {
549*0Sstevel@tonic-gate	  if ($MOD_PERL) {
550*0Sstevel@tonic-gate	    $query_string = $self->r->args;
551*0Sstevel@tonic-gate	  } else {
552*0Sstevel@tonic-gate	      $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
553*0Sstevel@tonic-gate	      $query_string ||= $ENV{'REDIRECT_QUERY_STRING'} if defined $ENV{'REDIRECT_QUERY_STRING'};
554*0Sstevel@tonic-gate	  }
555*0Sstevel@tonic-gate	  last METHOD;
556*0Sstevel@tonic-gate      }
557*0Sstevel@tonic-gate
558*0Sstevel@tonic-gate      if ($meth eq 'POST') {
559*0Sstevel@tonic-gate	  $self->read_from_client(\$query_string,$content_length,0)
560*0Sstevel@tonic-gate	      if $content_length > 0;
561*0Sstevel@tonic-gate	  # Some people want to have their cake and eat it too!
562*0Sstevel@tonic-gate	  # Uncomment this line to have the contents of the query string
563*0Sstevel@tonic-gate	  # APPENDED to the POST data.
564*0Sstevel@tonic-gate	  # $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
565*0Sstevel@tonic-gate	  last METHOD;
566*0Sstevel@tonic-gate      }
567*0Sstevel@tonic-gate
568*0Sstevel@tonic-gate      # If $meth is not of GET, POST or HEAD, assume we're being debugged offline.
569*0Sstevel@tonic-gate      # Check the command line and then the standard input for data.
570*0Sstevel@tonic-gate      # We use the shellwords package in order to behave the way that
571*0Sstevel@tonic-gate      # UN*X programmers expect.
572*0Sstevel@tonic-gate      if ($DEBUG)
573*0Sstevel@tonic-gate      {
574*0Sstevel@tonic-gate          my $cmdline_ret = read_from_cmdline();
575*0Sstevel@tonic-gate          $query_string = $cmdline_ret->{'query_string'};
576*0Sstevel@tonic-gate          if (defined($cmdline_ret->{'subpath'}))
577*0Sstevel@tonic-gate          {
578*0Sstevel@tonic-gate              $self->path_info($cmdline_ret->{'subpath'});
579*0Sstevel@tonic-gate          }
580*0Sstevel@tonic-gate      }
581*0Sstevel@tonic-gate  }
582*0Sstevel@tonic-gate
583*0Sstevel@tonic-gate# YL: Begin Change for XML handler 10/19/2001
584*0Sstevel@tonic-gate    if ($meth eq 'POST'
585*0Sstevel@tonic-gate        && defined($ENV{'CONTENT_TYPE'})
586*0Sstevel@tonic-gate        && $ENV{'CONTENT_TYPE'} !~ m|^application/x-www-form-urlencoded|
587*0Sstevel@tonic-gate	&& $ENV{'CONTENT_TYPE'} !~ m|^multipart/form-data| ) {
588*0Sstevel@tonic-gate        my($param) = 'POSTDATA' ;
589*0Sstevel@tonic-gate        $self->add_parameter($param) ;
590*0Sstevel@tonic-gate      push (@{$self->{$param}},$query_string);
591*0Sstevel@tonic-gate      undef $query_string ;
592*0Sstevel@tonic-gate    }
593*0Sstevel@tonic-gate# YL: End Change for XML handler 10/19/2001
594*0Sstevel@tonic-gate
595*0Sstevel@tonic-gate    # We now have the query string in hand.  We do slightly
596*0Sstevel@tonic-gate    # different things for keyword lists and parameter lists.
597*0Sstevel@tonic-gate    if (defined $query_string && length $query_string) {
598*0Sstevel@tonic-gate	if ($query_string =~ /[&=;]/) {
599*0Sstevel@tonic-gate	    $self->parse_params($query_string);
600*0Sstevel@tonic-gate	} else {
601*0Sstevel@tonic-gate	    $self->add_parameter('keywords');
602*0Sstevel@tonic-gate	    $self->{'keywords'} = [$self->parse_keywordlist($query_string)];
603*0Sstevel@tonic-gate	}
604*0Sstevel@tonic-gate    }
605*0Sstevel@tonic-gate
606*0Sstevel@tonic-gate    # Special case.  Erase everything if there is a field named
607*0Sstevel@tonic-gate    # .defaults.
608*0Sstevel@tonic-gate    if ($self->param('.defaults')) {
609*0Sstevel@tonic-gate      $self->delete_all();
610*0Sstevel@tonic-gate    }
611*0Sstevel@tonic-gate
612*0Sstevel@tonic-gate    # Associative array containing our defined fieldnames
613*0Sstevel@tonic-gate    $self->{'.fieldnames'} = {};
614*0Sstevel@tonic-gate    foreach ($self->param('.cgifields')) {
615*0Sstevel@tonic-gate	$self->{'.fieldnames'}->{$_}++;
616*0Sstevel@tonic-gate    }
617*0Sstevel@tonic-gate
618*0Sstevel@tonic-gate    # Clear out our default submission button flag if present
619*0Sstevel@tonic-gate    $self->delete('.submit');
620*0Sstevel@tonic-gate    $self->delete('.cgifields');
621*0Sstevel@tonic-gate
622*0Sstevel@tonic-gate    $self->save_request unless defined $initializer;
623*0Sstevel@tonic-gate}
624*0Sstevel@tonic-gate
625*0Sstevel@tonic-gate# FUNCTIONS TO OVERRIDE:
626*0Sstevel@tonic-gate# Turn a string into a filehandle
627*0Sstevel@tonic-gatesub to_filehandle {
628*0Sstevel@tonic-gate    my $thingy = shift;
629*0Sstevel@tonic-gate    return undef unless $thingy;
630*0Sstevel@tonic-gate    return $thingy if UNIVERSAL::isa($thingy,'GLOB');
631*0Sstevel@tonic-gate    return $thingy if UNIVERSAL::isa($thingy,'FileHandle');
632*0Sstevel@tonic-gate    if (!ref($thingy)) {
633*0Sstevel@tonic-gate	my $caller = 1;
634*0Sstevel@tonic-gate	while (my $package = caller($caller++)) {
635*0Sstevel@tonic-gate	    my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy";
636*0Sstevel@tonic-gate	    return $tmp if defined(fileno($tmp));
637*0Sstevel@tonic-gate	}
638*0Sstevel@tonic-gate    }
639*0Sstevel@tonic-gate    return undef;
640*0Sstevel@tonic-gate}
641*0Sstevel@tonic-gate
642*0Sstevel@tonic-gate# send output to the browser
643*0Sstevel@tonic-gatesub put {
644*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
645*0Sstevel@tonic-gate    $self->print(@p);
646*0Sstevel@tonic-gate}
647*0Sstevel@tonic-gate
648*0Sstevel@tonic-gate# print to standard output (for overriding in mod_perl)
649*0Sstevel@tonic-gatesub print {
650*0Sstevel@tonic-gate    shift;
651*0Sstevel@tonic-gate    CORE::print(@_);
652*0Sstevel@tonic-gate}
653*0Sstevel@tonic-gate
654*0Sstevel@tonic-gate# get/set last cgi_error
655*0Sstevel@tonic-gatesub cgi_error {
656*0Sstevel@tonic-gate    my ($self,$err) = self_or_default(@_);
657*0Sstevel@tonic-gate    $self->{'.cgi_error'} = $err if defined $err;
658*0Sstevel@tonic-gate    return $self->{'.cgi_error'};
659*0Sstevel@tonic-gate}
660*0Sstevel@tonic-gate
661*0Sstevel@tonic-gatesub save_request {
662*0Sstevel@tonic-gate    my($self) = @_;
663*0Sstevel@tonic-gate    # We're going to play with the package globals now so that if we get called
664*0Sstevel@tonic-gate    # again, we initialize ourselves in exactly the same way.  This allows
665*0Sstevel@tonic-gate    # us to have several of these objects.
666*0Sstevel@tonic-gate    @QUERY_PARAM = $self->param; # save list of parameters
667*0Sstevel@tonic-gate    foreach (@QUERY_PARAM) {
668*0Sstevel@tonic-gate      next unless defined $_;
669*0Sstevel@tonic-gate      $QUERY_PARAM{$_}=$self->{$_};
670*0Sstevel@tonic-gate    }
671*0Sstevel@tonic-gate    $QUERY_CHARSET = $self->charset;
672*0Sstevel@tonic-gate    %QUERY_FIELDNAMES = %{$self->{'.fieldnames'}};
673*0Sstevel@tonic-gate}
674*0Sstevel@tonic-gate
675*0Sstevel@tonic-gatesub parse_params {
676*0Sstevel@tonic-gate    my($self,$tosplit) = @_;
677*0Sstevel@tonic-gate    my(@pairs) = split(/[&;]/,$tosplit);
678*0Sstevel@tonic-gate    my($param,$value);
679*0Sstevel@tonic-gate    foreach (@pairs) {
680*0Sstevel@tonic-gate	($param,$value) = split('=',$_,2);
681*0Sstevel@tonic-gate	next unless defined $param;
682*0Sstevel@tonic-gate	next if $NO_UNDEF_PARAMS and not defined $value;
683*0Sstevel@tonic-gate	$value = '' unless defined $value;
684*0Sstevel@tonic-gate	$param = unescape($param);
685*0Sstevel@tonic-gate	$value = unescape($value);
686*0Sstevel@tonic-gate	$self->add_parameter($param);
687*0Sstevel@tonic-gate	push (@{$self->{$param}},$value);
688*0Sstevel@tonic-gate    }
689*0Sstevel@tonic-gate}
690*0Sstevel@tonic-gate
691*0Sstevel@tonic-gatesub add_parameter {
692*0Sstevel@tonic-gate    my($self,$param)=@_;
693*0Sstevel@tonic-gate    return unless defined $param;
694*0Sstevel@tonic-gate    push (@{$self->{'.parameters'}},$param)
695*0Sstevel@tonic-gate	unless defined($self->{$param});
696*0Sstevel@tonic-gate}
697*0Sstevel@tonic-gate
698*0Sstevel@tonic-gatesub all_parameters {
699*0Sstevel@tonic-gate    my $self = shift;
700*0Sstevel@tonic-gate    return () unless defined($self) && $self->{'.parameters'};
701*0Sstevel@tonic-gate    return () unless @{$self->{'.parameters'}};
702*0Sstevel@tonic-gate    return @{$self->{'.parameters'}};
703*0Sstevel@tonic-gate}
704*0Sstevel@tonic-gate
705*0Sstevel@tonic-gate# put a filehandle into binary mode (DOS)
706*0Sstevel@tonic-gatesub binmode {
707*0Sstevel@tonic-gate    return unless defined($_[1]) && defined fileno($_[1]);
708*0Sstevel@tonic-gate    CORE::binmode($_[1]);
709*0Sstevel@tonic-gate}
710*0Sstevel@tonic-gate
711*0Sstevel@tonic-gatesub _make_tag_func {
712*0Sstevel@tonic-gate    my ($self,$tagname) = @_;
713*0Sstevel@tonic-gate    my $func = qq(
714*0Sstevel@tonic-gate	sub $tagname {
715*0Sstevel@tonic-gate         my (\$q,\$a,\@rest) = self_or_default(\@_);
716*0Sstevel@tonic-gate         my(\$attr) = '';
717*0Sstevel@tonic-gate	 if (ref(\$a) && ref(\$a) eq 'HASH') {
718*0Sstevel@tonic-gate	    my(\@attr) = make_attributes(\$a,\$q->{'escape'});
719*0Sstevel@tonic-gate	    \$attr = " \@attr" if \@attr;
720*0Sstevel@tonic-gate	  } else {
721*0Sstevel@tonic-gate	    unshift \@rest,\$a if defined \$a;
722*0Sstevel@tonic-gate	  }
723*0Sstevel@tonic-gate	);
724*0Sstevel@tonic-gate    if ($tagname=~/start_(\w+)/i) {
725*0Sstevel@tonic-gate	$func .= qq! return "<\L$1\E\$attr>";} !;
726*0Sstevel@tonic-gate    } elsif ($tagname=~/end_(\w+)/i) {
727*0Sstevel@tonic-gate	$func .= qq! return "<\L/$1\E>"; } !;
728*0Sstevel@tonic-gate    } else {
729*0Sstevel@tonic-gate	$func .= qq#
730*0Sstevel@tonic-gate	    return \$XHTML ? "\L<$tagname\E\$attr />" : "\L<$tagname\E\$attr>" unless \@rest;
731*0Sstevel@tonic-gate	    my(\$tag,\$untag) = ("\L<$tagname\E\$attr>","\L</$tagname>\E");
732*0Sstevel@tonic-gate	    my \@result = map { "\$tag\$_\$untag" }
733*0Sstevel@tonic-gate                              (ref(\$rest[0]) eq 'ARRAY') ? \@{\$rest[0]} : "\@rest";
734*0Sstevel@tonic-gate	    return "\@result";
735*0Sstevel@tonic-gate            }#;
736*0Sstevel@tonic-gate    }
737*0Sstevel@tonic-gatereturn $func;
738*0Sstevel@tonic-gate}
739*0Sstevel@tonic-gate
740*0Sstevel@tonic-gatesub AUTOLOAD {
741*0Sstevel@tonic-gate    print STDERR "CGI::AUTOLOAD for $AUTOLOAD\n" if $CGI::AUTOLOAD_DEBUG;
742*0Sstevel@tonic-gate    my $func = &_compile;
743*0Sstevel@tonic-gate    goto &$func;
744*0Sstevel@tonic-gate}
745*0Sstevel@tonic-gate
746*0Sstevel@tonic-gatesub _compile {
747*0Sstevel@tonic-gate    my($func) = $AUTOLOAD;
748*0Sstevel@tonic-gate    my($pack,$func_name);
749*0Sstevel@tonic-gate    {
750*0Sstevel@tonic-gate	local($1,$2); # this fixes an obscure variable suicide problem.
751*0Sstevel@tonic-gate	$func=~/(.+)::([^:]+)$/;
752*0Sstevel@tonic-gate	($pack,$func_name) = ($1,$2);
753*0Sstevel@tonic-gate	$pack=~s/::SUPER$//;	# fix another obscure problem
754*0Sstevel@tonic-gate	$pack = ${"$pack\:\:AutoloadClass"} || $CGI::DefaultClass
755*0Sstevel@tonic-gate	    unless defined(${"$pack\:\:AUTOLOADED_ROUTINES"});
756*0Sstevel@tonic-gate
757*0Sstevel@tonic-gate        my($sub) = \%{"$pack\:\:SUBS"};
758*0Sstevel@tonic-gate        unless (%$sub) {
759*0Sstevel@tonic-gate	   my($auto) = \${"$pack\:\:AUTOLOADED_ROUTINES"};
760*0Sstevel@tonic-gate	   eval "package $pack; $$auto";
761*0Sstevel@tonic-gate	   croak("$AUTOLOAD: $@") if $@;
762*0Sstevel@tonic-gate           $$auto = '';  # Free the unneeded storage (but don't undef it!!!)
763*0Sstevel@tonic-gate       }
764*0Sstevel@tonic-gate       my($code) = $sub->{$func_name};
765*0Sstevel@tonic-gate
766*0Sstevel@tonic-gate       $code = "sub $AUTOLOAD { }" if (!$code and $func_name eq 'DESTROY');
767*0Sstevel@tonic-gate       if (!$code) {
768*0Sstevel@tonic-gate	   (my $base = $func_name) =~ s/^(start_|end_)//i;
769*0Sstevel@tonic-gate	   if ($EXPORT{':any'} ||
770*0Sstevel@tonic-gate	       $EXPORT{'-any'} ||
771*0Sstevel@tonic-gate	       $EXPORT{$base} ||
772*0Sstevel@tonic-gate	       (%EXPORT_OK || grep(++$EXPORT_OK{$_},&expand_tags(':html')))
773*0Sstevel@tonic-gate	           && $EXPORT_OK{$base}) {
774*0Sstevel@tonic-gate	       $code = $CGI::DefaultClass->_make_tag_func($func_name);
775*0Sstevel@tonic-gate	   }
776*0Sstevel@tonic-gate       }
777*0Sstevel@tonic-gate       croak("Undefined subroutine $AUTOLOAD\n") unless $code;
778*0Sstevel@tonic-gate       eval "package $pack; $code";
779*0Sstevel@tonic-gate       if ($@) {
780*0Sstevel@tonic-gate	   $@ =~ s/ at .*\n//;
781*0Sstevel@tonic-gate	   croak("$AUTOLOAD: $@");
782*0Sstevel@tonic-gate       }
783*0Sstevel@tonic-gate    }
784*0Sstevel@tonic-gate    CORE::delete($sub->{$func_name});  #free storage
785*0Sstevel@tonic-gate    return "$pack\:\:$func_name";
786*0Sstevel@tonic-gate}
787*0Sstevel@tonic-gate
788*0Sstevel@tonic-gatesub _selected {
789*0Sstevel@tonic-gate  my $self = shift;
790*0Sstevel@tonic-gate  my $value = shift;
791*0Sstevel@tonic-gate  return '' unless $value;
792*0Sstevel@tonic-gate  return $XHTML ? qq( selected="selected") : qq( selected);
793*0Sstevel@tonic-gate}
794*0Sstevel@tonic-gate
795*0Sstevel@tonic-gatesub _checked {
796*0Sstevel@tonic-gate  my $self = shift;
797*0Sstevel@tonic-gate  my $value = shift;
798*0Sstevel@tonic-gate  return '' unless $value;
799*0Sstevel@tonic-gate  return $XHTML ? qq( checked="checked") : qq( checked);
800*0Sstevel@tonic-gate}
801*0Sstevel@tonic-gate
802*0Sstevel@tonic-gatesub _reset_globals { initialize_globals(); }
803*0Sstevel@tonic-gate
804*0Sstevel@tonic-gatesub _setup_symbols {
805*0Sstevel@tonic-gate    my $self = shift;
806*0Sstevel@tonic-gate    my $compile = 0;
807*0Sstevel@tonic-gate
808*0Sstevel@tonic-gate    # to avoid reexporting unwanted variables
809*0Sstevel@tonic-gate    undef %EXPORT;
810*0Sstevel@tonic-gate
811*0Sstevel@tonic-gate    foreach (@_) {
812*0Sstevel@tonic-gate	$HEADERS_ONCE++,         next if /^[:-]unique_headers$/;
813*0Sstevel@tonic-gate	$NPH++,                  next if /^[:-]nph$/;
814*0Sstevel@tonic-gate	$NOSTICKY++,             next if /^[:-]nosticky$/;
815*0Sstevel@tonic-gate	$DEBUG=0,                next if /^[:-]no_?[Dd]ebug$/;
816*0Sstevel@tonic-gate	$DEBUG=2,                next if /^[:-][Dd]ebug$/;
817*0Sstevel@tonic-gate	$USE_PARAM_SEMICOLONS++, next if /^[:-]newstyle_urls$/;
818*0Sstevel@tonic-gate	$XHTML++,                next if /^[:-]xhtml$/;
819*0Sstevel@tonic-gate	$XHTML=0,                next if /^[:-]no_?xhtml$/;
820*0Sstevel@tonic-gate	$USE_PARAM_SEMICOLONS=0, next if /^[:-]oldstyle_urls$/;
821*0Sstevel@tonic-gate	$PRIVATE_TEMPFILES++,    next if /^[:-]private_tempfiles$/;
822*0Sstevel@tonic-gate    $CLOSE_UPLOAD_FILES++,   next if /^[:-]close_upload_files$/;
823*0Sstevel@tonic-gate	$EXPORT{$_}++,           next if /^[:-]any$/;
824*0Sstevel@tonic-gate	$compile++,              next if /^[:-]compile$/;
825*0Sstevel@tonic-gate	$NO_UNDEF_PARAMS++,      next if /^[:-]no_undef_params$/;
826*0Sstevel@tonic-gate
827*0Sstevel@tonic-gate	# This is probably extremely evil code -- to be deleted some day.
828*0Sstevel@tonic-gate	if (/^[-]autoload$/) {
829*0Sstevel@tonic-gate	    my($pkg) = caller(1);
830*0Sstevel@tonic-gate	    *{"${pkg}::AUTOLOAD"} = sub {
831*0Sstevel@tonic-gate		my($routine) = $AUTOLOAD;
832*0Sstevel@tonic-gate		$routine =~ s/^.*::/CGI::/;
833*0Sstevel@tonic-gate		&$routine;
834*0Sstevel@tonic-gate	    };
835*0Sstevel@tonic-gate	    next;
836*0Sstevel@tonic-gate	}
837*0Sstevel@tonic-gate
838*0Sstevel@tonic-gate	foreach (&expand_tags($_)) {
839*0Sstevel@tonic-gate	    tr/a-zA-Z0-9_//cd;  # don't allow weird function names
840*0Sstevel@tonic-gate	    $EXPORT{$_}++;
841*0Sstevel@tonic-gate	}
842*0Sstevel@tonic-gate    }
843*0Sstevel@tonic-gate    _compile_all(keys %EXPORT) if $compile;
844*0Sstevel@tonic-gate    @SAVED_SYMBOLS = @_;
845*0Sstevel@tonic-gate}
846*0Sstevel@tonic-gate
847*0Sstevel@tonic-gatesub charset {
848*0Sstevel@tonic-gate  my ($self,$charset) = self_or_default(@_);
849*0Sstevel@tonic-gate  $self->{'.charset'} = $charset if defined $charset;
850*0Sstevel@tonic-gate  $self->{'.charset'};
851*0Sstevel@tonic-gate}
852*0Sstevel@tonic-gate
853*0Sstevel@tonic-gate###############################################################################
854*0Sstevel@tonic-gate################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
855*0Sstevel@tonic-gate###############################################################################
856*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES = '';      # get rid of -w warning
857*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
858*0Sstevel@tonic-gate
859*0Sstevel@tonic-gate%SUBS = (
860*0Sstevel@tonic-gate
861*0Sstevel@tonic-gate'URL_ENCODED'=> <<'END_OF_FUNC',
862*0Sstevel@tonic-gatesub URL_ENCODED { 'application/x-www-form-urlencoded'; }
863*0Sstevel@tonic-gateEND_OF_FUNC
864*0Sstevel@tonic-gate
865*0Sstevel@tonic-gate'MULTIPART' => <<'END_OF_FUNC',
866*0Sstevel@tonic-gatesub MULTIPART {  'multipart/form-data'; }
867*0Sstevel@tonic-gateEND_OF_FUNC
868*0Sstevel@tonic-gate
869*0Sstevel@tonic-gate'SERVER_PUSH' => <<'END_OF_FUNC',
870*0Sstevel@tonic-gatesub SERVER_PUSH { 'multipart/x-mixed-replace;boundary="' . shift() . '"'; }
871*0Sstevel@tonic-gateEND_OF_FUNC
872*0Sstevel@tonic-gate
873*0Sstevel@tonic-gate'new_MultipartBuffer' => <<'END_OF_FUNC',
874*0Sstevel@tonic-gate# Create a new multipart buffer
875*0Sstevel@tonic-gatesub new_MultipartBuffer {
876*0Sstevel@tonic-gate    my($self,$boundary,$length) = @_;
877*0Sstevel@tonic-gate    return MultipartBuffer->new($self,$boundary,$length);
878*0Sstevel@tonic-gate}
879*0Sstevel@tonic-gateEND_OF_FUNC
880*0Sstevel@tonic-gate
881*0Sstevel@tonic-gate'read_from_client' => <<'END_OF_FUNC',
882*0Sstevel@tonic-gate# Read data from a file handle
883*0Sstevel@tonic-gatesub read_from_client {
884*0Sstevel@tonic-gate    my($self, $buff, $len, $offset) = @_;
885*0Sstevel@tonic-gate    local $^W=0;                # prevent a warning
886*0Sstevel@tonic-gate    return $MOD_PERL
887*0Sstevel@tonic-gate        ? $self->r->read($$buff, $len, $offset)
888*0Sstevel@tonic-gate        : read(\*STDIN, $$buff, $len, $offset);
889*0Sstevel@tonic-gate}
890*0Sstevel@tonic-gateEND_OF_FUNC
891*0Sstevel@tonic-gate
892*0Sstevel@tonic-gate'delete' => <<'END_OF_FUNC',
893*0Sstevel@tonic-gate#### Method: delete
894*0Sstevel@tonic-gate# Deletes the named parameter entirely.
895*0Sstevel@tonic-gate####
896*0Sstevel@tonic-gatesub delete {
897*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
898*0Sstevel@tonic-gate    my(@names) = rearrange([NAME],@p);
899*0Sstevel@tonic-gate    my @to_delete = ref($names[0]) eq 'ARRAY' ? @$names[0] : @names;
900*0Sstevel@tonic-gate    my %to_delete;
901*0Sstevel@tonic-gate    foreach my $name (@to_delete)
902*0Sstevel@tonic-gate    {
903*0Sstevel@tonic-gate        CORE::delete $self->{$name};
904*0Sstevel@tonic-gate        CORE::delete $self->{'.fieldnames'}->{$name};
905*0Sstevel@tonic-gate        $to_delete{$name}++;
906*0Sstevel@tonic-gate    }
907*0Sstevel@tonic-gate    @{$self->{'.parameters'}}=grep { !exists($to_delete{$_}) } $self->param();
908*0Sstevel@tonic-gate    return wantarray ? () : undef;
909*0Sstevel@tonic-gate}
910*0Sstevel@tonic-gateEND_OF_FUNC
911*0Sstevel@tonic-gate
912*0Sstevel@tonic-gate#### Method: import_names
913*0Sstevel@tonic-gate# Import all parameters into the given namespace.
914*0Sstevel@tonic-gate# Assumes namespace 'Q' if not specified
915*0Sstevel@tonic-gate####
916*0Sstevel@tonic-gate'import_names' => <<'END_OF_FUNC',
917*0Sstevel@tonic-gatesub import_names {
918*0Sstevel@tonic-gate    my($self,$namespace,$delete) = self_or_default(@_);
919*0Sstevel@tonic-gate    $namespace = 'Q' unless defined($namespace);
920*0Sstevel@tonic-gate    die "Can't import names into \"main\"\n" if \%{"${namespace}::"} == \%::;
921*0Sstevel@tonic-gate    if ($delete || $MOD_PERL || exists $ENV{'FCGI_ROLE'}) {
922*0Sstevel@tonic-gate	# can anyone find an easier way to do this?
923*0Sstevel@tonic-gate	foreach (keys %{"${namespace}::"}) {
924*0Sstevel@tonic-gate	    local *symbol = "${namespace}::${_}";
925*0Sstevel@tonic-gate	    undef $symbol;
926*0Sstevel@tonic-gate	    undef @symbol;
927*0Sstevel@tonic-gate	    undef %symbol;
928*0Sstevel@tonic-gate	}
929*0Sstevel@tonic-gate    }
930*0Sstevel@tonic-gate    my($param,@value,$var);
931*0Sstevel@tonic-gate    foreach $param ($self->param) {
932*0Sstevel@tonic-gate	# protect against silly names
933*0Sstevel@tonic-gate	($var = $param)=~tr/a-zA-Z0-9_/_/c;
934*0Sstevel@tonic-gate	$var =~ s/^(?=\d)/_/;
935*0Sstevel@tonic-gate	local *symbol = "${namespace}::$var";
936*0Sstevel@tonic-gate	@value = $self->param($param);
937*0Sstevel@tonic-gate	@symbol = @value;
938*0Sstevel@tonic-gate	$symbol = $value[0];
939*0Sstevel@tonic-gate    }
940*0Sstevel@tonic-gate}
941*0Sstevel@tonic-gateEND_OF_FUNC
942*0Sstevel@tonic-gate
943*0Sstevel@tonic-gate#### Method: keywords
944*0Sstevel@tonic-gate# Keywords acts a bit differently.  Calling it in a list context
945*0Sstevel@tonic-gate# returns the list of keywords.
946*0Sstevel@tonic-gate# Calling it in a scalar context gives you the size of the list.
947*0Sstevel@tonic-gate####
948*0Sstevel@tonic-gate'keywords' => <<'END_OF_FUNC',
949*0Sstevel@tonic-gatesub keywords {
950*0Sstevel@tonic-gate    my($self,@values) = self_or_default(@_);
951*0Sstevel@tonic-gate    # If values is provided, then we set it.
952*0Sstevel@tonic-gate    $self->{'keywords'}=[@values] if @values;
953*0Sstevel@tonic-gate    my(@result) = defined($self->{'keywords'}) ? @{$self->{'keywords'}} : ();
954*0Sstevel@tonic-gate    @result;
955*0Sstevel@tonic-gate}
956*0Sstevel@tonic-gateEND_OF_FUNC
957*0Sstevel@tonic-gate
958*0Sstevel@tonic-gate# These are some tie() interfaces for compatibility
959*0Sstevel@tonic-gate# with Steve Brenner's cgi-lib.pl routines
960*0Sstevel@tonic-gate'Vars' => <<'END_OF_FUNC',
961*0Sstevel@tonic-gatesub Vars {
962*0Sstevel@tonic-gate    my $q = shift;
963*0Sstevel@tonic-gate    my %in;
964*0Sstevel@tonic-gate    tie(%in,CGI,$q);
965*0Sstevel@tonic-gate    return %in if wantarray;
966*0Sstevel@tonic-gate    return \%in;
967*0Sstevel@tonic-gate}
968*0Sstevel@tonic-gateEND_OF_FUNC
969*0Sstevel@tonic-gate
970*0Sstevel@tonic-gate# These are some tie() interfaces for compatibility
971*0Sstevel@tonic-gate# with Steve Brenner's cgi-lib.pl routines
972*0Sstevel@tonic-gate'ReadParse' => <<'END_OF_FUNC',
973*0Sstevel@tonic-gatesub ReadParse {
974*0Sstevel@tonic-gate    local(*in);
975*0Sstevel@tonic-gate    if (@_) {
976*0Sstevel@tonic-gate	*in = $_[0];
977*0Sstevel@tonic-gate    } else {
978*0Sstevel@tonic-gate	my $pkg = caller();
979*0Sstevel@tonic-gate	*in=*{"${pkg}::in"};
980*0Sstevel@tonic-gate    }
981*0Sstevel@tonic-gate    tie(%in,CGI);
982*0Sstevel@tonic-gate    return scalar(keys %in);
983*0Sstevel@tonic-gate}
984*0Sstevel@tonic-gateEND_OF_FUNC
985*0Sstevel@tonic-gate
986*0Sstevel@tonic-gate'PrintHeader' => <<'END_OF_FUNC',
987*0Sstevel@tonic-gatesub PrintHeader {
988*0Sstevel@tonic-gate    my($self) = self_or_default(@_);
989*0Sstevel@tonic-gate    return $self->header();
990*0Sstevel@tonic-gate}
991*0Sstevel@tonic-gateEND_OF_FUNC
992*0Sstevel@tonic-gate
993*0Sstevel@tonic-gate'HtmlTop' => <<'END_OF_FUNC',
994*0Sstevel@tonic-gatesub HtmlTop {
995*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
996*0Sstevel@tonic-gate    return $self->start_html(@p);
997*0Sstevel@tonic-gate}
998*0Sstevel@tonic-gateEND_OF_FUNC
999*0Sstevel@tonic-gate
1000*0Sstevel@tonic-gate'HtmlBot' => <<'END_OF_FUNC',
1001*0Sstevel@tonic-gatesub HtmlBot {
1002*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1003*0Sstevel@tonic-gate    return $self->end_html(@p);
1004*0Sstevel@tonic-gate}
1005*0Sstevel@tonic-gateEND_OF_FUNC
1006*0Sstevel@tonic-gate
1007*0Sstevel@tonic-gate'SplitParam' => <<'END_OF_FUNC',
1008*0Sstevel@tonic-gatesub SplitParam {
1009*0Sstevel@tonic-gate    my ($param) = @_;
1010*0Sstevel@tonic-gate    my (@params) = split ("\0", $param);
1011*0Sstevel@tonic-gate    return (wantarray ? @params : $params[0]);
1012*0Sstevel@tonic-gate}
1013*0Sstevel@tonic-gateEND_OF_FUNC
1014*0Sstevel@tonic-gate
1015*0Sstevel@tonic-gate'MethGet' => <<'END_OF_FUNC',
1016*0Sstevel@tonic-gatesub MethGet {
1017*0Sstevel@tonic-gate    return request_method() eq 'GET';
1018*0Sstevel@tonic-gate}
1019*0Sstevel@tonic-gateEND_OF_FUNC
1020*0Sstevel@tonic-gate
1021*0Sstevel@tonic-gate'MethPost' => <<'END_OF_FUNC',
1022*0Sstevel@tonic-gatesub MethPost {
1023*0Sstevel@tonic-gate    return request_method() eq 'POST';
1024*0Sstevel@tonic-gate}
1025*0Sstevel@tonic-gateEND_OF_FUNC
1026*0Sstevel@tonic-gate
1027*0Sstevel@tonic-gate'TIEHASH' => <<'END_OF_FUNC',
1028*0Sstevel@tonic-gatesub TIEHASH {
1029*0Sstevel@tonic-gate    my $class = shift;
1030*0Sstevel@tonic-gate    my $arg   = $_[0];
1031*0Sstevel@tonic-gate    if (ref($arg) && UNIVERSAL::isa($arg,'CGI')) {
1032*0Sstevel@tonic-gate       return $arg;
1033*0Sstevel@tonic-gate    }
1034*0Sstevel@tonic-gate    return $Q ||= $class->new(@_);
1035*0Sstevel@tonic-gate}
1036*0Sstevel@tonic-gateEND_OF_FUNC
1037*0Sstevel@tonic-gate
1038*0Sstevel@tonic-gate'STORE' => <<'END_OF_FUNC',
1039*0Sstevel@tonic-gatesub STORE {
1040*0Sstevel@tonic-gate    my $self = shift;
1041*0Sstevel@tonic-gate    my $tag  = shift;
1042*0Sstevel@tonic-gate    my $vals = shift;
1043*0Sstevel@tonic-gate    my @vals = index($vals,"\0")!=-1 ? split("\0",$vals) : $vals;
1044*0Sstevel@tonic-gate    $self->param(-name=>$tag,-value=>\@vals);
1045*0Sstevel@tonic-gate}
1046*0Sstevel@tonic-gateEND_OF_FUNC
1047*0Sstevel@tonic-gate
1048*0Sstevel@tonic-gate'FETCH' => <<'END_OF_FUNC',
1049*0Sstevel@tonic-gatesub FETCH {
1050*0Sstevel@tonic-gate    return $_[0] if $_[1] eq 'CGI';
1051*0Sstevel@tonic-gate    return undef unless defined $_[0]->param($_[1]);
1052*0Sstevel@tonic-gate    return join("\0",$_[0]->param($_[1]));
1053*0Sstevel@tonic-gate}
1054*0Sstevel@tonic-gateEND_OF_FUNC
1055*0Sstevel@tonic-gate
1056*0Sstevel@tonic-gate'FIRSTKEY' => <<'END_OF_FUNC',
1057*0Sstevel@tonic-gatesub FIRSTKEY {
1058*0Sstevel@tonic-gate    $_[0]->{'.iterator'}=0;
1059*0Sstevel@tonic-gate    $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++];
1060*0Sstevel@tonic-gate}
1061*0Sstevel@tonic-gateEND_OF_FUNC
1062*0Sstevel@tonic-gate
1063*0Sstevel@tonic-gate'NEXTKEY' => <<'END_OF_FUNC',
1064*0Sstevel@tonic-gatesub NEXTKEY {
1065*0Sstevel@tonic-gate    $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++];
1066*0Sstevel@tonic-gate}
1067*0Sstevel@tonic-gateEND_OF_FUNC
1068*0Sstevel@tonic-gate
1069*0Sstevel@tonic-gate'EXISTS' => <<'END_OF_FUNC',
1070*0Sstevel@tonic-gatesub EXISTS {
1071*0Sstevel@tonic-gate    exists $_[0]->{$_[1]};
1072*0Sstevel@tonic-gate}
1073*0Sstevel@tonic-gateEND_OF_FUNC
1074*0Sstevel@tonic-gate
1075*0Sstevel@tonic-gate'DELETE' => <<'END_OF_FUNC',
1076*0Sstevel@tonic-gatesub DELETE {
1077*0Sstevel@tonic-gate    $_[0]->delete($_[1]);
1078*0Sstevel@tonic-gate}
1079*0Sstevel@tonic-gateEND_OF_FUNC
1080*0Sstevel@tonic-gate
1081*0Sstevel@tonic-gate'CLEAR' => <<'END_OF_FUNC',
1082*0Sstevel@tonic-gatesub CLEAR {
1083*0Sstevel@tonic-gate    %{$_[0]}=();
1084*0Sstevel@tonic-gate}
1085*0Sstevel@tonic-gate####
1086*0Sstevel@tonic-gateEND_OF_FUNC
1087*0Sstevel@tonic-gate
1088*0Sstevel@tonic-gate####
1089*0Sstevel@tonic-gate# Append a new value to an existing query
1090*0Sstevel@tonic-gate####
1091*0Sstevel@tonic-gate'append' => <<'EOF',
1092*0Sstevel@tonic-gatesub append {
1093*0Sstevel@tonic-gate    my($self,@p) = @_;
1094*0Sstevel@tonic-gate    my($name,$value) = rearrange([NAME,[VALUE,VALUES]],@p);
1095*0Sstevel@tonic-gate    my(@values) = defined($value) ? (ref($value) ? @{$value} : $value) : ();
1096*0Sstevel@tonic-gate    if (@values) {
1097*0Sstevel@tonic-gate	$self->add_parameter($name);
1098*0Sstevel@tonic-gate	push(@{$self->{$name}},@values);
1099*0Sstevel@tonic-gate    }
1100*0Sstevel@tonic-gate    return $self->param($name);
1101*0Sstevel@tonic-gate}
1102*0Sstevel@tonic-gateEOF
1103*0Sstevel@tonic-gate
1104*0Sstevel@tonic-gate#### Method: delete_all
1105*0Sstevel@tonic-gate# Delete all parameters
1106*0Sstevel@tonic-gate####
1107*0Sstevel@tonic-gate'delete_all' => <<'EOF',
1108*0Sstevel@tonic-gatesub delete_all {
1109*0Sstevel@tonic-gate    my($self) = self_or_default(@_);
1110*0Sstevel@tonic-gate    my @param = $self->param();
1111*0Sstevel@tonic-gate    $self->delete(@param);
1112*0Sstevel@tonic-gate}
1113*0Sstevel@tonic-gateEOF
1114*0Sstevel@tonic-gate
1115*0Sstevel@tonic-gate'Delete' => <<'EOF',
1116*0Sstevel@tonic-gatesub Delete {
1117*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1118*0Sstevel@tonic-gate    $self->delete(@p);
1119*0Sstevel@tonic-gate}
1120*0Sstevel@tonic-gateEOF
1121*0Sstevel@tonic-gate
1122*0Sstevel@tonic-gate'Delete_all' => <<'EOF',
1123*0Sstevel@tonic-gatesub Delete_all {
1124*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1125*0Sstevel@tonic-gate    $self->delete_all(@p);
1126*0Sstevel@tonic-gate}
1127*0Sstevel@tonic-gateEOF
1128*0Sstevel@tonic-gate
1129*0Sstevel@tonic-gate#### Method: autoescape
1130*0Sstevel@tonic-gate# If you want to turn off the autoescaping features,
1131*0Sstevel@tonic-gate# call this method with undef as the argument
1132*0Sstevel@tonic-gate'autoEscape' => <<'END_OF_FUNC',
1133*0Sstevel@tonic-gatesub autoEscape {
1134*0Sstevel@tonic-gate    my($self,$escape) = self_or_default(@_);
1135*0Sstevel@tonic-gate    my $d = $self->{'escape'};
1136*0Sstevel@tonic-gate    $self->{'escape'} = $escape;
1137*0Sstevel@tonic-gate    $d;
1138*0Sstevel@tonic-gate}
1139*0Sstevel@tonic-gateEND_OF_FUNC
1140*0Sstevel@tonic-gate
1141*0Sstevel@tonic-gate
1142*0Sstevel@tonic-gate#### Method: version
1143*0Sstevel@tonic-gate# Return the current version
1144*0Sstevel@tonic-gate####
1145*0Sstevel@tonic-gate'version' => <<'END_OF_FUNC',
1146*0Sstevel@tonic-gatesub version {
1147*0Sstevel@tonic-gate    return $VERSION;
1148*0Sstevel@tonic-gate}
1149*0Sstevel@tonic-gateEND_OF_FUNC
1150*0Sstevel@tonic-gate
1151*0Sstevel@tonic-gate#### Method: url_param
1152*0Sstevel@tonic-gate# Return a parameter in the QUERY_STRING, regardless of
1153*0Sstevel@tonic-gate# whether this was a POST or a GET
1154*0Sstevel@tonic-gate####
1155*0Sstevel@tonic-gate'url_param' => <<'END_OF_FUNC',
1156*0Sstevel@tonic-gatesub url_param {
1157*0Sstevel@tonic-gate    my ($self,@p) = self_or_default(@_);
1158*0Sstevel@tonic-gate    my $name = shift(@p);
1159*0Sstevel@tonic-gate    return undef unless exists($ENV{QUERY_STRING});
1160*0Sstevel@tonic-gate    unless (exists($self->{'.url_param'})) {
1161*0Sstevel@tonic-gate	$self->{'.url_param'}={}; # empty hash
1162*0Sstevel@tonic-gate	if ($ENV{QUERY_STRING} =~ /=/) {
1163*0Sstevel@tonic-gate	    my(@pairs) = split(/[&;]/,$ENV{QUERY_STRING});
1164*0Sstevel@tonic-gate	    my($param,$value);
1165*0Sstevel@tonic-gate	    foreach (@pairs) {
1166*0Sstevel@tonic-gate		($param,$value) = split('=',$_,2);
1167*0Sstevel@tonic-gate		$param = unescape($param);
1168*0Sstevel@tonic-gate		$value = unescape($value);
1169*0Sstevel@tonic-gate		push(@{$self->{'.url_param'}->{$param}},$value);
1170*0Sstevel@tonic-gate	    }
1171*0Sstevel@tonic-gate	} else {
1172*0Sstevel@tonic-gate	    $self->{'.url_param'}->{'keywords'} = [$self->parse_keywordlist($ENV{QUERY_STRING})];
1173*0Sstevel@tonic-gate	}
1174*0Sstevel@tonic-gate    }
1175*0Sstevel@tonic-gate    return keys %{$self->{'.url_param'}} unless defined($name);
1176*0Sstevel@tonic-gate    return () unless $self->{'.url_param'}->{$name};
1177*0Sstevel@tonic-gate    return wantarray ? @{$self->{'.url_param'}->{$name}}
1178*0Sstevel@tonic-gate                     : $self->{'.url_param'}->{$name}->[0];
1179*0Sstevel@tonic-gate}
1180*0Sstevel@tonic-gateEND_OF_FUNC
1181*0Sstevel@tonic-gate
1182*0Sstevel@tonic-gate#### Method: Dump
1183*0Sstevel@tonic-gate# Returns a string in which all the known parameter/value
1184*0Sstevel@tonic-gate# pairs are represented as nested lists, mainly for the purposes
1185*0Sstevel@tonic-gate# of debugging.
1186*0Sstevel@tonic-gate####
1187*0Sstevel@tonic-gate'Dump' => <<'END_OF_FUNC',
1188*0Sstevel@tonic-gatesub Dump {
1189*0Sstevel@tonic-gate    my($self) = self_or_default(@_);
1190*0Sstevel@tonic-gate    my($param,$value,@result);
1191*0Sstevel@tonic-gate    return '<ul></ul>' unless $self->param;
1192*0Sstevel@tonic-gate    push(@result,"<ul>");
1193*0Sstevel@tonic-gate    foreach $param ($self->param) {
1194*0Sstevel@tonic-gate	my($name)=$self->escapeHTML($param);
1195*0Sstevel@tonic-gate	push(@result,"<li><strong>$param</strong></li>");
1196*0Sstevel@tonic-gate	push(@result,"<ul>");
1197*0Sstevel@tonic-gate	foreach $value ($self->param($param)) {
1198*0Sstevel@tonic-gate	    $value = $self->escapeHTML($value);
1199*0Sstevel@tonic-gate            $value =~ s/\n/<br \/>\n/g;
1200*0Sstevel@tonic-gate	    push(@result,"<li>$value</li>");
1201*0Sstevel@tonic-gate	}
1202*0Sstevel@tonic-gate	push(@result,"</ul>");
1203*0Sstevel@tonic-gate    }
1204*0Sstevel@tonic-gate    push(@result,"</ul>");
1205*0Sstevel@tonic-gate    return join("\n",@result);
1206*0Sstevel@tonic-gate}
1207*0Sstevel@tonic-gateEND_OF_FUNC
1208*0Sstevel@tonic-gate
1209*0Sstevel@tonic-gate#### Method as_string
1210*0Sstevel@tonic-gate#
1211*0Sstevel@tonic-gate# synonym for "dump"
1212*0Sstevel@tonic-gate####
1213*0Sstevel@tonic-gate'as_string' => <<'END_OF_FUNC',
1214*0Sstevel@tonic-gatesub as_string {
1215*0Sstevel@tonic-gate    &Dump(@_);
1216*0Sstevel@tonic-gate}
1217*0Sstevel@tonic-gateEND_OF_FUNC
1218*0Sstevel@tonic-gate
1219*0Sstevel@tonic-gate#### Method: save
1220*0Sstevel@tonic-gate# Write values out to a filehandle in such a way that they can
1221*0Sstevel@tonic-gate# be reinitialized by the filehandle form of the new() method
1222*0Sstevel@tonic-gate####
1223*0Sstevel@tonic-gate'save' => <<'END_OF_FUNC',
1224*0Sstevel@tonic-gatesub save {
1225*0Sstevel@tonic-gate    my($self,$filehandle) = self_or_default(@_);
1226*0Sstevel@tonic-gate    $filehandle = to_filehandle($filehandle);
1227*0Sstevel@tonic-gate    my($param);
1228*0Sstevel@tonic-gate    local($,) = '';  # set print field separator back to a sane value
1229*0Sstevel@tonic-gate    local($\) = '';  # set output line separator to a sane value
1230*0Sstevel@tonic-gate    foreach $param ($self->param) {
1231*0Sstevel@tonic-gate	my($escaped_param) = escape($param);
1232*0Sstevel@tonic-gate	my($value);
1233*0Sstevel@tonic-gate	foreach $value ($self->param($param)) {
1234*0Sstevel@tonic-gate	    print $filehandle "$escaped_param=",escape("$value"),"\n";
1235*0Sstevel@tonic-gate	}
1236*0Sstevel@tonic-gate    }
1237*0Sstevel@tonic-gate    foreach (keys %{$self->{'.fieldnames'}}) {
1238*0Sstevel@tonic-gate          print $filehandle ".cgifields=",escape("$_"),"\n";
1239*0Sstevel@tonic-gate    }
1240*0Sstevel@tonic-gate    print $filehandle "=\n";    # end of record
1241*0Sstevel@tonic-gate}
1242*0Sstevel@tonic-gateEND_OF_FUNC
1243*0Sstevel@tonic-gate
1244*0Sstevel@tonic-gate
1245*0Sstevel@tonic-gate#### Method: save_parameters
1246*0Sstevel@tonic-gate# An alias for save() that is a better name for exportation.
1247*0Sstevel@tonic-gate# Only intended to be used with the function (non-OO) interface.
1248*0Sstevel@tonic-gate####
1249*0Sstevel@tonic-gate'save_parameters' => <<'END_OF_FUNC',
1250*0Sstevel@tonic-gatesub save_parameters {
1251*0Sstevel@tonic-gate    my $fh = shift;
1252*0Sstevel@tonic-gate    return save(to_filehandle($fh));
1253*0Sstevel@tonic-gate}
1254*0Sstevel@tonic-gateEND_OF_FUNC
1255*0Sstevel@tonic-gate
1256*0Sstevel@tonic-gate#### Method: restore_parameters
1257*0Sstevel@tonic-gate# A way to restore CGI parameters from an initializer.
1258*0Sstevel@tonic-gate# Only intended to be used with the function (non-OO) interface.
1259*0Sstevel@tonic-gate####
1260*0Sstevel@tonic-gate'restore_parameters' => <<'END_OF_FUNC',
1261*0Sstevel@tonic-gatesub restore_parameters {
1262*0Sstevel@tonic-gate    $Q = $CGI::DefaultClass->new(@_);
1263*0Sstevel@tonic-gate}
1264*0Sstevel@tonic-gateEND_OF_FUNC
1265*0Sstevel@tonic-gate
1266*0Sstevel@tonic-gate#### Method: multipart_init
1267*0Sstevel@tonic-gate# Return a Content-Type: style header for server-push
1268*0Sstevel@tonic-gate# This has to be NPH on most web servers, and it is advisable to set $| = 1
1269*0Sstevel@tonic-gate#
1270*0Sstevel@tonic-gate# Many thanks to Ed Jordan <ed@fidalgo.net> for this
1271*0Sstevel@tonic-gate# contribution, updated by Andrew Benham (adsb@bigfoot.com)
1272*0Sstevel@tonic-gate####
1273*0Sstevel@tonic-gate'multipart_init' => <<'END_OF_FUNC',
1274*0Sstevel@tonic-gatesub multipart_init {
1275*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1276*0Sstevel@tonic-gate    my($boundary,@other) = rearrange([BOUNDARY],@p);
1277*0Sstevel@tonic-gate    $boundary = $boundary || '------- =_aaaaaaaaaa0';
1278*0Sstevel@tonic-gate    $self->{'separator'} = "$CRLF--$boundary$CRLF";
1279*0Sstevel@tonic-gate    $self->{'final_separator'} = "$CRLF--$boundary--$CRLF";
1280*0Sstevel@tonic-gate    $type = SERVER_PUSH($boundary);
1281*0Sstevel@tonic-gate    return $self->header(
1282*0Sstevel@tonic-gate	-nph => 1,
1283*0Sstevel@tonic-gate	-type => $type,
1284*0Sstevel@tonic-gate	(map { split "=", $_, 2 } @other),
1285*0Sstevel@tonic-gate    ) . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $self->multipart_end;
1286*0Sstevel@tonic-gate}
1287*0Sstevel@tonic-gateEND_OF_FUNC
1288*0Sstevel@tonic-gate
1289*0Sstevel@tonic-gate
1290*0Sstevel@tonic-gate#### Method: multipart_start
1291*0Sstevel@tonic-gate# Return a Content-Type: style header for server-push, start of section
1292*0Sstevel@tonic-gate#
1293*0Sstevel@tonic-gate# Many thanks to Ed Jordan <ed@fidalgo.net> for this
1294*0Sstevel@tonic-gate# contribution, updated by Andrew Benham (adsb@bigfoot.com)
1295*0Sstevel@tonic-gate####
1296*0Sstevel@tonic-gate'multipart_start' => <<'END_OF_FUNC',
1297*0Sstevel@tonic-gatesub multipart_start {
1298*0Sstevel@tonic-gate    my(@header);
1299*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1300*0Sstevel@tonic-gate    my($type,@other) = rearrange([TYPE],@p);
1301*0Sstevel@tonic-gate    $type = $type || 'text/html';
1302*0Sstevel@tonic-gate    push(@header,"Content-Type: $type");
1303*0Sstevel@tonic-gate
1304*0Sstevel@tonic-gate    # rearrange() was designed for the HTML portion, so we
1305*0Sstevel@tonic-gate    # need to fix it up a little.
1306*0Sstevel@tonic-gate    foreach (@other) {
1307*0Sstevel@tonic-gate        # Don't use \s because of perl bug 21951
1308*0Sstevel@tonic-gate        next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/;
1309*0Sstevel@tonic-gate	($_ = $header) =~ s/^(\w)(.*)/$1 . lc ($2) . ': '.$self->unescapeHTML($value)/e;
1310*0Sstevel@tonic-gate    }
1311*0Sstevel@tonic-gate    push(@header,@other);
1312*0Sstevel@tonic-gate    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
1313*0Sstevel@tonic-gate    return $header;
1314*0Sstevel@tonic-gate}
1315*0Sstevel@tonic-gateEND_OF_FUNC
1316*0Sstevel@tonic-gate
1317*0Sstevel@tonic-gate
1318*0Sstevel@tonic-gate#### Method: multipart_end
1319*0Sstevel@tonic-gate# Return a MIME boundary separator for server-push, end of section
1320*0Sstevel@tonic-gate#
1321*0Sstevel@tonic-gate# Many thanks to Ed Jordan <ed@fidalgo.net> for this
1322*0Sstevel@tonic-gate# contribution
1323*0Sstevel@tonic-gate####
1324*0Sstevel@tonic-gate'multipart_end' => <<'END_OF_FUNC',
1325*0Sstevel@tonic-gatesub multipart_end {
1326*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1327*0Sstevel@tonic-gate    return $self->{'separator'};
1328*0Sstevel@tonic-gate}
1329*0Sstevel@tonic-gateEND_OF_FUNC
1330*0Sstevel@tonic-gate
1331*0Sstevel@tonic-gate
1332*0Sstevel@tonic-gate#### Method: multipart_final
1333*0Sstevel@tonic-gate# Return a MIME boundary separator for server-push, end of all sections
1334*0Sstevel@tonic-gate#
1335*0Sstevel@tonic-gate# Contributed by Andrew Benham (adsb@bigfoot.com)
1336*0Sstevel@tonic-gate####
1337*0Sstevel@tonic-gate'multipart_final' => <<'END_OF_FUNC',
1338*0Sstevel@tonic-gatesub multipart_final {
1339*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1340*0Sstevel@tonic-gate    return $self->{'final_separator'} . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $CRLF;
1341*0Sstevel@tonic-gate}
1342*0Sstevel@tonic-gateEND_OF_FUNC
1343*0Sstevel@tonic-gate
1344*0Sstevel@tonic-gate
1345*0Sstevel@tonic-gate#### Method: header
1346*0Sstevel@tonic-gate# Return a Content-Type: style header
1347*0Sstevel@tonic-gate#
1348*0Sstevel@tonic-gate####
1349*0Sstevel@tonic-gate'header' => <<'END_OF_FUNC',
1350*0Sstevel@tonic-gatesub header {
1351*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1352*0Sstevel@tonic-gate    my(@header);
1353*0Sstevel@tonic-gate
1354*0Sstevel@tonic-gate    return "" if $self->{'.header_printed'}++ and $HEADERS_ONCE;
1355*0Sstevel@tonic-gate
1356*0Sstevel@tonic-gate    my($type,$status,$cookie,$target,$expires,$nph,$charset,$attachment,$p3p,@other) =
1357*0Sstevel@tonic-gate	rearrange([['TYPE','CONTENT_TYPE','CONTENT-TYPE'],
1358*0Sstevel@tonic-gate			    'STATUS',['COOKIE','COOKIES'],'TARGET',
1359*0Sstevel@tonic-gate                            'EXPIRES','NPH','CHARSET',
1360*0Sstevel@tonic-gate                            'ATTACHMENT','P3P'],@p);
1361*0Sstevel@tonic-gate
1362*0Sstevel@tonic-gate    $nph     ||= $NPH;
1363*0Sstevel@tonic-gate    if (defined $charset) {
1364*0Sstevel@tonic-gate      $self->charset($charset);
1365*0Sstevel@tonic-gate    } else {
1366*0Sstevel@tonic-gate      $charset = $self->charset;
1367*0Sstevel@tonic-gate    }
1368*0Sstevel@tonic-gate
1369*0Sstevel@tonic-gate    # rearrange() was designed for the HTML portion, so we
1370*0Sstevel@tonic-gate    # need to fix it up a little.
1371*0Sstevel@tonic-gate    foreach (@other) {
1372*0Sstevel@tonic-gate        # Don't use \s because of perl bug 21951
1373*0Sstevel@tonic-gate        next unless my($header,$value) = /([^ \r\n\t=]+)=\"?(.+?)\"?$/;
1374*0Sstevel@tonic-gate        ($_ = $header) =~ s/^(\w)(.*)/"\u$1\L$2" . ': '.$self->unescapeHTML($value)/e;
1375*0Sstevel@tonic-gate    }
1376*0Sstevel@tonic-gate
1377*0Sstevel@tonic-gate    $type ||= 'text/html' unless defined($type);
1378*0Sstevel@tonic-gate    $type .= "; charset=$charset" if $type ne '' and $type =~ m!^text/! and $type !~ /\bcharset\b/ and $charset ne '';
1379*0Sstevel@tonic-gate
1380*0Sstevel@tonic-gate    # Maybe future compatibility.  Maybe not.
1381*0Sstevel@tonic-gate    my $protocol = $ENV{SERVER_PROTOCOL} || 'HTTP/1.0';
1382*0Sstevel@tonic-gate    push(@header,$protocol . ' ' . ($status || '200 OK')) if $nph;
1383*0Sstevel@tonic-gate    push(@header,"Server: " . &server_software()) if $nph;
1384*0Sstevel@tonic-gate
1385*0Sstevel@tonic-gate    push(@header,"Status: $status") if $status;
1386*0Sstevel@tonic-gate    push(@header,"Window-Target: $target") if $target;
1387*0Sstevel@tonic-gate    if ($p3p) {
1388*0Sstevel@tonic-gate       $p3p = join ' ',@$p3p if ref($p3p) eq 'ARRAY';
1389*0Sstevel@tonic-gate       push(@header,qq(P3P: policyref="/w3c/p3p.xml", CP="$p3p"));
1390*0Sstevel@tonic-gate    }
1391*0Sstevel@tonic-gate    # push all the cookies -- there may be several
1392*0Sstevel@tonic-gate    if ($cookie) {
1393*0Sstevel@tonic-gate	my(@cookie) = ref($cookie) && ref($cookie) eq 'ARRAY' ? @{$cookie} : $cookie;
1394*0Sstevel@tonic-gate	foreach (@cookie) {
1395*0Sstevel@tonic-gate            my $cs = UNIVERSAL::isa($_,'CGI::Cookie') ? $_->as_string : $_;
1396*0Sstevel@tonic-gate	    push(@header,"Set-Cookie: $cs") if $cs ne '';
1397*0Sstevel@tonic-gate	}
1398*0Sstevel@tonic-gate    }
1399*0Sstevel@tonic-gate    # if the user indicates an expiration time, then we need
1400*0Sstevel@tonic-gate    # both an Expires and a Date header (so that the browser is
1401*0Sstevel@tonic-gate    # uses OUR clock)
1402*0Sstevel@tonic-gate    push(@header,"Expires: " . expires($expires,'http'))
1403*0Sstevel@tonic-gate	if $expires;
1404*0Sstevel@tonic-gate    push(@header,"Date: " . expires(0,'http')) if $expires || $cookie || $nph;
1405*0Sstevel@tonic-gate    push(@header,"Pragma: no-cache") if $self->cache();
1406*0Sstevel@tonic-gate    push(@header,"Content-Disposition: attachment; filename=\"$attachment\"") if $attachment;
1407*0Sstevel@tonic-gate    push(@header,map {ucfirst $_} @other);
1408*0Sstevel@tonic-gate    push(@header,"Content-Type: $type") if $type ne '';
1409*0Sstevel@tonic-gate    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
1410*0Sstevel@tonic-gate    if ($MOD_PERL and not $nph) {
1411*0Sstevel@tonic-gate        $self->r->send_cgi_header($header);
1412*0Sstevel@tonic-gate        return '';
1413*0Sstevel@tonic-gate    }
1414*0Sstevel@tonic-gate    return $header;
1415*0Sstevel@tonic-gate}
1416*0Sstevel@tonic-gateEND_OF_FUNC
1417*0Sstevel@tonic-gate
1418*0Sstevel@tonic-gate
1419*0Sstevel@tonic-gate#### Method: cache
1420*0Sstevel@tonic-gate# Control whether header() will produce the no-cache
1421*0Sstevel@tonic-gate# Pragma directive.
1422*0Sstevel@tonic-gate####
1423*0Sstevel@tonic-gate'cache' => <<'END_OF_FUNC',
1424*0Sstevel@tonic-gatesub cache {
1425*0Sstevel@tonic-gate    my($self,$new_value) = self_or_default(@_);
1426*0Sstevel@tonic-gate    $new_value = '' unless $new_value;
1427*0Sstevel@tonic-gate    if ($new_value ne '') {
1428*0Sstevel@tonic-gate	$self->{'cache'} = $new_value;
1429*0Sstevel@tonic-gate    }
1430*0Sstevel@tonic-gate    return $self->{'cache'};
1431*0Sstevel@tonic-gate}
1432*0Sstevel@tonic-gateEND_OF_FUNC
1433*0Sstevel@tonic-gate
1434*0Sstevel@tonic-gate
1435*0Sstevel@tonic-gate#### Method: redirect
1436*0Sstevel@tonic-gate# Return a Location: style header
1437*0Sstevel@tonic-gate#
1438*0Sstevel@tonic-gate####
1439*0Sstevel@tonic-gate'redirect' => <<'END_OF_FUNC',
1440*0Sstevel@tonic-gatesub redirect {
1441*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1442*0Sstevel@tonic-gate    my($url,$target,$cookie,$nph,@other) = rearrange([[LOCATION,URI,URL],TARGET,['COOKIE','COOKIES'],NPH],@p);
1443*0Sstevel@tonic-gate    $url ||= $self->self_url;
1444*0Sstevel@tonic-gate    my(@o);
1445*0Sstevel@tonic-gate    foreach (@other) { tr/\"//d; push(@o,split("=",$_,2)); }
1446*0Sstevel@tonic-gate    unshift(@o,
1447*0Sstevel@tonic-gate	 '-Status'  => '302 Moved',
1448*0Sstevel@tonic-gate	 '-Location'=> $url,
1449*0Sstevel@tonic-gate	 '-nph'     => $nph);
1450*0Sstevel@tonic-gate    unshift(@o,'-Target'=>$target) if $target;
1451*0Sstevel@tonic-gate    unshift(@o,'-Type'=>'');
1452*0Sstevel@tonic-gate    my @unescaped;
1453*0Sstevel@tonic-gate    unshift(@unescaped,'-Cookie'=>$cookie) if $cookie;
1454*0Sstevel@tonic-gate    return $self->header((map {$self->unescapeHTML($_)} @o),@unescaped);
1455*0Sstevel@tonic-gate}
1456*0Sstevel@tonic-gateEND_OF_FUNC
1457*0Sstevel@tonic-gate
1458*0Sstevel@tonic-gate
1459*0Sstevel@tonic-gate#### Method: start_html
1460*0Sstevel@tonic-gate# Canned HTML header
1461*0Sstevel@tonic-gate#
1462*0Sstevel@tonic-gate# Parameters:
1463*0Sstevel@tonic-gate# $title -> (optional) The title for this HTML document (-title)
1464*0Sstevel@tonic-gate# $author -> (optional) e-mail address of the author (-author)
1465*0Sstevel@tonic-gate# $base -> (optional) if set to true, will enter the BASE address of this document
1466*0Sstevel@tonic-gate#          for resolving relative references (-base)
1467*0Sstevel@tonic-gate# $xbase -> (optional) alternative base at some remote location (-xbase)
1468*0Sstevel@tonic-gate# $target -> (optional) target window to load all links into (-target)
1469*0Sstevel@tonic-gate# $script -> (option) Javascript code (-script)
1470*0Sstevel@tonic-gate# $no_script -> (option) Javascript <noscript> tag (-noscript)
1471*0Sstevel@tonic-gate# $meta -> (optional) Meta information tags
1472*0Sstevel@tonic-gate# $head -> (optional) any other elements you'd like to incorporate into the <head> tag
1473*0Sstevel@tonic-gate#           (a scalar or array ref)
1474*0Sstevel@tonic-gate# $style -> (optional) reference to an external style sheet
1475*0Sstevel@tonic-gate# @other -> (optional) any other named parameters you'd like to incorporate into
1476*0Sstevel@tonic-gate#           the <body> tag.
1477*0Sstevel@tonic-gate####
1478*0Sstevel@tonic-gate'start_html' => <<'END_OF_FUNC',
1479*0Sstevel@tonic-gatesub start_html {
1480*0Sstevel@tonic-gate    my($self,@p) = &self_or_default(@_);
1481*0Sstevel@tonic-gate    my($title,$author,$base,$xbase,$script,$noscript,
1482*0Sstevel@tonic-gate        $target,$meta,$head,$style,$dtd,$lang,$encoding,@other) =
1483*0Sstevel@tonic-gate	rearrange([TITLE,AUTHOR,BASE,XBASE,SCRIPT,NOSCRIPT,TARGET,META,HEAD,STYLE,DTD,LANG,ENCODING],@p);
1484*0Sstevel@tonic-gate
1485*0Sstevel@tonic-gate    $encoding = 'iso-8859-1' unless defined $encoding;
1486*0Sstevel@tonic-gate
1487*0Sstevel@tonic-gate    # strangely enough, the title needs to be escaped as HTML
1488*0Sstevel@tonic-gate    # while the author needs to be escaped as a URL
1489*0Sstevel@tonic-gate    $title = $self->escapeHTML($title || 'Untitled Document');
1490*0Sstevel@tonic-gate    $author = $self->escape($author);
1491*0Sstevel@tonic-gate    $lang = 'en-US' unless defined $lang;
1492*0Sstevel@tonic-gate    my(@result,$xml_dtd);
1493*0Sstevel@tonic-gate    if ($dtd) {
1494*0Sstevel@tonic-gate        if (defined(ref($dtd)) and (ref($dtd) eq 'ARRAY')) {
1495*0Sstevel@tonic-gate            $dtd = $DEFAULT_DTD unless $dtd->[0] =~ m|^-//|;
1496*0Sstevel@tonic-gate        } else {
1497*0Sstevel@tonic-gate            $dtd = $DEFAULT_DTD unless $dtd =~ m|^-//|;
1498*0Sstevel@tonic-gate        }
1499*0Sstevel@tonic-gate    } else {
1500*0Sstevel@tonic-gate        $dtd = $XHTML ? XHTML_DTD : $DEFAULT_DTD;
1501*0Sstevel@tonic-gate    }
1502*0Sstevel@tonic-gate
1503*0Sstevel@tonic-gate    $xml_dtd++ if ref($dtd) eq 'ARRAY' && $dtd->[0] =~ /\bXHTML\b/i;
1504*0Sstevel@tonic-gate    $xml_dtd++ if ref($dtd) eq '' && $dtd =~ /\bXHTML\b/i;
1505*0Sstevel@tonic-gate    push @result,qq(<?xml version="1.0" encoding="$encoding"?>) if $xml_dtd;
1506*0Sstevel@tonic-gate
1507*0Sstevel@tonic-gate    if (ref($dtd) && ref($dtd) eq 'ARRAY') {
1508*0Sstevel@tonic-gate        push(@result,qq(<!DOCTYPE html\n\tPUBLIC "$dtd->[0]"\n\t "$dtd->[1]">));
1509*0Sstevel@tonic-gate    } else {
1510*0Sstevel@tonic-gate        push(@result,qq(<!DOCTYPE html\n\tPUBLIC "$dtd">));
1511*0Sstevel@tonic-gate    }
1512*0Sstevel@tonic-gate    push(@result,$XHTML ? qq(<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang" xml:lang="$lang"><head><title>$title</title>)
1513*0Sstevel@tonic-gate                        : ($lang ? qq(<html lang="$lang">) : "<html>")
1514*0Sstevel@tonic-gate	                  . "<head><title>$title</title>");
1515*0Sstevel@tonic-gate	if (defined $author) {
1516*0Sstevel@tonic-gate    push(@result,$XHTML ? "<link rev=\"made\" href=\"mailto:$author\" />"
1517*0Sstevel@tonic-gate								: "<link rev=\"made\" href=\"mailto:$author\">");
1518*0Sstevel@tonic-gate	}
1519*0Sstevel@tonic-gate
1520*0Sstevel@tonic-gate    if ($base || $xbase || $target) {
1521*0Sstevel@tonic-gate	my $href = $xbase || $self->url('-path'=>1);
1522*0Sstevel@tonic-gate	my $t = $target ? qq/ target="$target"/ : '';
1523*0Sstevel@tonic-gate	push(@result,$XHTML ? qq(<base href="$href"$t />) : qq(<base href="$href"$t>));
1524*0Sstevel@tonic-gate    }
1525*0Sstevel@tonic-gate
1526*0Sstevel@tonic-gate    if ($meta && ref($meta) && (ref($meta) eq 'HASH')) {
1527*0Sstevel@tonic-gate	foreach (keys %$meta) { push(@result,$XHTML ? qq(<meta name="$_" content="$meta->{$_}" />)
1528*0Sstevel@tonic-gate			: qq(<meta name="$_" content="$meta->{$_}">)); }
1529*0Sstevel@tonic-gate    }
1530*0Sstevel@tonic-gate
1531*0Sstevel@tonic-gate    push(@result,ref($head) ? @$head : $head) if $head;
1532*0Sstevel@tonic-gate
1533*0Sstevel@tonic-gate    # handle the infrequently-used -style and -script parameters
1534*0Sstevel@tonic-gate    push(@result,$self->_style($style)) if defined $style;
1535*0Sstevel@tonic-gate    push(@result,$self->_script($script)) if defined $script;
1536*0Sstevel@tonic-gate
1537*0Sstevel@tonic-gate    # handle -noscript parameter
1538*0Sstevel@tonic-gate    push(@result,<<END) if $noscript;
1539*0Sstevel@tonic-gate<noscript>
1540*0Sstevel@tonic-gate$noscript
1541*0Sstevel@tonic-gate</noscript>
1542*0Sstevel@tonic-gateEND
1543*0Sstevel@tonic-gate    ;
1544*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1545*0Sstevel@tonic-gate    push(@result,"</head><body$other>");
1546*0Sstevel@tonic-gate    return join("\n",@result);
1547*0Sstevel@tonic-gate}
1548*0Sstevel@tonic-gateEND_OF_FUNC
1549*0Sstevel@tonic-gate
1550*0Sstevel@tonic-gate### Method: _style
1551*0Sstevel@tonic-gate# internal method for generating a CSS style section
1552*0Sstevel@tonic-gate####
1553*0Sstevel@tonic-gate'_style' => <<'END_OF_FUNC',
1554*0Sstevel@tonic-gatesub _style {
1555*0Sstevel@tonic-gate    my ($self,$style) = @_;
1556*0Sstevel@tonic-gate    my (@result);
1557*0Sstevel@tonic-gate    my $type = 'text/css';
1558*0Sstevel@tonic-gate
1559*0Sstevel@tonic-gate    my $cdata_start = $XHTML ? "\n<!--/* <![CDATA[ */" : "\n<!-- ";
1560*0Sstevel@tonic-gate    my $cdata_end   = $XHTML ? "\n/* ]]> */-->\n" : " -->\n";
1561*0Sstevel@tonic-gate
1562*0Sstevel@tonic-gate    if (ref($style)) {
1563*0Sstevel@tonic-gate     my($src,$code,$verbatim,$stype,$foo,@other) =
1564*0Sstevel@tonic-gate         rearrange([SRC,CODE,VERBATIM,TYPE],
1565*0Sstevel@tonic-gate                    '-foo'=>'bar',    # trick to allow dash to be omitted
1566*0Sstevel@tonic-gate                    ref($style) eq 'ARRAY' ? @$style : %$style);
1567*0Sstevel@tonic-gate     $type  = $stype if $stype;
1568*0Sstevel@tonic-gate     my $other = @other ? join ' ',@other : '';
1569*0Sstevel@tonic-gate
1570*0Sstevel@tonic-gate     if (ref($src) eq "ARRAY") # Check to see if the $src variable is an array reference
1571*0Sstevel@tonic-gate     { # If it is, push a LINK tag for each one
1572*0Sstevel@tonic-gate         foreach $src (@$src)
1573*0Sstevel@tonic-gate       {
1574*0Sstevel@tonic-gate         push(@result,$XHTML ? qq(<link rel="stylesheet" type="$type" href="$src" $other/>)
1575*0Sstevel@tonic-gate                             : qq(<link rel="stylesheet" type="$type" href="$src"$other>)) if $src;
1576*0Sstevel@tonic-gate       }
1577*0Sstevel@tonic-gate     }
1578*0Sstevel@tonic-gate     else
1579*0Sstevel@tonic-gate     { # Otherwise, push the single -src, if it exists.
1580*0Sstevel@tonic-gate       push(@result,$XHTML ? qq(<link rel="stylesheet" type="$type" href="$src" $other/>)
1581*0Sstevel@tonic-gate                           : qq(<link rel="stylesheet" type="$type" href="$src"$other>)
1582*0Sstevel@tonic-gate            ) if $src;
1583*0Sstevel@tonic-gate      }
1584*0Sstevel@tonic-gate   if ($verbatim) {
1585*0Sstevel@tonic-gate         push(@result, "<style type=\"text/css\">\n$verbatim\n</style>");
1586*0Sstevel@tonic-gate    }
1587*0Sstevel@tonic-gate      push(@result,style({'type'=>$type},"$cdata_start\n$code\n$cdata_end")) if $code;
1588*0Sstevel@tonic-gate    } else {
1589*0Sstevel@tonic-gate         my $src = $style;
1590*0Sstevel@tonic-gate         push(@result,$XHTML ? qq(<link rel="stylesheet" type="$type" href="$src" $other/>)
1591*0Sstevel@tonic-gate                             : qq(<link rel="stylesheet" type="$type" href="$src"$other>));
1592*0Sstevel@tonic-gate    }
1593*0Sstevel@tonic-gate    @result;
1594*0Sstevel@tonic-gate}
1595*0Sstevel@tonic-gateEND_OF_FUNC
1596*0Sstevel@tonic-gate
1597*0Sstevel@tonic-gate'_script' => <<'END_OF_FUNC',
1598*0Sstevel@tonic-gatesub _script {
1599*0Sstevel@tonic-gate    my ($self,$script) = @_;
1600*0Sstevel@tonic-gate    my (@result);
1601*0Sstevel@tonic-gate
1602*0Sstevel@tonic-gate    my (@scripts) = ref($script) eq 'ARRAY' ? @$script : ($script);
1603*0Sstevel@tonic-gate    foreach $script (@scripts) {
1604*0Sstevel@tonic-gate	my($src,$code,$language);
1605*0Sstevel@tonic-gate	if (ref($script)) { # script is a hash
1606*0Sstevel@tonic-gate	    ($src,$code,$language, $type) =
1607*0Sstevel@tonic-gate		rearrange([SRC,CODE,LANGUAGE,TYPE],
1608*0Sstevel@tonic-gate				 '-foo'=>'bar',	# a trick to allow the '-' to be omitted
1609*0Sstevel@tonic-gate				 ref($script) eq 'ARRAY' ? @$script : %$script);
1610*0Sstevel@tonic-gate            # User may not have specified language
1611*0Sstevel@tonic-gate            $language ||= 'JavaScript';
1612*0Sstevel@tonic-gate            unless (defined $type) {
1613*0Sstevel@tonic-gate                $type = lc $language;
1614*0Sstevel@tonic-gate                # strip '1.2' from 'javascript1.2'
1615*0Sstevel@tonic-gate                $type =~ s/^(\D+).*$/text\/$1/;
1616*0Sstevel@tonic-gate            }
1617*0Sstevel@tonic-gate	} else {
1618*0Sstevel@tonic-gate	    ($src,$code,$language, $type) = ('',$script,'JavaScript', 'text/javascript');
1619*0Sstevel@tonic-gate	}
1620*0Sstevel@tonic-gate
1621*0Sstevel@tonic-gate    my $comment = '//';  # javascript by default
1622*0Sstevel@tonic-gate    $comment = '#' if $type=~/perl|tcl/i;
1623*0Sstevel@tonic-gate    $comment = "'" if $type=~/vbscript/i;
1624*0Sstevel@tonic-gate
1625*0Sstevel@tonic-gate    my ($cdata_start,$cdata_end);
1626*0Sstevel@tonic-gate    if ($XHTML) {
1627*0Sstevel@tonic-gate       $cdata_start    = "$comment<![CDATA[\n";
1628*0Sstevel@tonic-gate       $cdata_end     .= "\n$comment]]>";
1629*0Sstevel@tonic-gate    } else {
1630*0Sstevel@tonic-gate       $cdata_start  =  "\n<!-- Hide script\n";
1631*0Sstevel@tonic-gate       $cdata_end    = $comment;
1632*0Sstevel@tonic-gate       $cdata_end   .= " End script hiding -->\n";
1633*0Sstevel@tonic-gate   }
1634*0Sstevel@tonic-gate     my(@satts);
1635*0Sstevel@tonic-gate     push(@satts,'src'=>$src) if $src;
1636*0Sstevel@tonic-gate     push(@satts,'language'=>$language) unless defined $type;
1637*0Sstevel@tonic-gate     push(@satts,'type'=>$type);
1638*0Sstevel@tonic-gate     $code = "$cdata_start$code$cdata_end" if defined $code;
1639*0Sstevel@tonic-gate     push(@result,script({@satts},$code || ''));
1640*0Sstevel@tonic-gate    }
1641*0Sstevel@tonic-gate    @result;
1642*0Sstevel@tonic-gate}
1643*0Sstevel@tonic-gateEND_OF_FUNC
1644*0Sstevel@tonic-gate
1645*0Sstevel@tonic-gate#### Method: end_html
1646*0Sstevel@tonic-gate# End an HTML document.
1647*0Sstevel@tonic-gate# Trivial method for completeness.  Just returns "</body>"
1648*0Sstevel@tonic-gate####
1649*0Sstevel@tonic-gate'end_html' => <<'END_OF_FUNC',
1650*0Sstevel@tonic-gatesub end_html {
1651*0Sstevel@tonic-gate    return "</body></html>";
1652*0Sstevel@tonic-gate}
1653*0Sstevel@tonic-gateEND_OF_FUNC
1654*0Sstevel@tonic-gate
1655*0Sstevel@tonic-gate
1656*0Sstevel@tonic-gate################################
1657*0Sstevel@tonic-gate# METHODS USED IN BUILDING FORMS
1658*0Sstevel@tonic-gate################################
1659*0Sstevel@tonic-gate
1660*0Sstevel@tonic-gate#### Method: isindex
1661*0Sstevel@tonic-gate# Just prints out the isindex tag.
1662*0Sstevel@tonic-gate# Parameters:
1663*0Sstevel@tonic-gate#  $action -> optional URL of script to run
1664*0Sstevel@tonic-gate# Returns:
1665*0Sstevel@tonic-gate#   A string containing a <isindex> tag
1666*0Sstevel@tonic-gate'isindex' => <<'END_OF_FUNC',
1667*0Sstevel@tonic-gatesub isindex {
1668*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1669*0Sstevel@tonic-gate    my($action,@other) = rearrange([ACTION],@p);
1670*0Sstevel@tonic-gate    $action = qq/ action="$action"/ if $action;
1671*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1672*0Sstevel@tonic-gate    return $XHTML ? "<isindex$action$other />" : "<isindex$action$other>";
1673*0Sstevel@tonic-gate}
1674*0Sstevel@tonic-gateEND_OF_FUNC
1675*0Sstevel@tonic-gate
1676*0Sstevel@tonic-gate
1677*0Sstevel@tonic-gate#### Method: startform
1678*0Sstevel@tonic-gate# Start a form
1679*0Sstevel@tonic-gate# Parameters:
1680*0Sstevel@tonic-gate#   $method -> optional submission method to use (GET or POST)
1681*0Sstevel@tonic-gate#   $action -> optional URL of script to run
1682*0Sstevel@tonic-gate#   $enctype ->encoding to use (URL_ENCODED or MULTIPART)
1683*0Sstevel@tonic-gate'startform' => <<'END_OF_FUNC',
1684*0Sstevel@tonic-gatesub startform {
1685*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1686*0Sstevel@tonic-gate
1687*0Sstevel@tonic-gate    my($method,$action,$enctype,@other) =
1688*0Sstevel@tonic-gate	rearrange([METHOD,ACTION,ENCTYPE],@p);
1689*0Sstevel@tonic-gate
1690*0Sstevel@tonic-gate    $method = lc($method) || 'post';
1691*0Sstevel@tonic-gate    $enctype = $enctype || &URL_ENCODED;
1692*0Sstevel@tonic-gate    unless (defined $action) {
1693*0Sstevel@tonic-gate
1694*0Sstevel@tonic-gate       $action = $self->escapeHTML($self->url(-absolute=>1,-path=>1));
1695*0Sstevel@tonic-gate       if (length($ENV{QUERY_STRING})>0) {
1696*0Sstevel@tonic-gate           $action .= "?".$self->escapeHTML($ENV{QUERY_STRING},1);
1697*0Sstevel@tonic-gate       }
1698*0Sstevel@tonic-gate    }
1699*0Sstevel@tonic-gate    $action = qq(action="$action");
1700*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1701*0Sstevel@tonic-gate    $self->{'.parametersToAdd'}={};
1702*0Sstevel@tonic-gate    return qq/<form method="$method" $action enctype="$enctype"$other>\n/;
1703*0Sstevel@tonic-gate}
1704*0Sstevel@tonic-gateEND_OF_FUNC
1705*0Sstevel@tonic-gate
1706*0Sstevel@tonic-gate
1707*0Sstevel@tonic-gate#### Method: start_form
1708*0Sstevel@tonic-gate# synonym for startform
1709*0Sstevel@tonic-gate'start_form' => <<'END_OF_FUNC',
1710*0Sstevel@tonic-gatesub start_form {
1711*0Sstevel@tonic-gate    &startform;
1712*0Sstevel@tonic-gate}
1713*0Sstevel@tonic-gateEND_OF_FUNC
1714*0Sstevel@tonic-gate
1715*0Sstevel@tonic-gate'end_multipart_form' => <<'END_OF_FUNC',
1716*0Sstevel@tonic-gatesub end_multipart_form {
1717*0Sstevel@tonic-gate    &endform;
1718*0Sstevel@tonic-gate}
1719*0Sstevel@tonic-gateEND_OF_FUNC
1720*0Sstevel@tonic-gate
1721*0Sstevel@tonic-gate#### Method: start_multipart_form
1722*0Sstevel@tonic-gate# synonym for startform
1723*0Sstevel@tonic-gate'start_multipart_form' => <<'END_OF_FUNC',
1724*0Sstevel@tonic-gatesub start_multipart_form {
1725*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1726*0Sstevel@tonic-gate    if (defined($param[0]) && substr($param[0],0,1) eq '-') {
1727*0Sstevel@tonic-gate	my(%p) = @p;
1728*0Sstevel@tonic-gate	$p{'-enctype'}=&MULTIPART;
1729*0Sstevel@tonic-gate	return $self->startform(%p);
1730*0Sstevel@tonic-gate    } else {
1731*0Sstevel@tonic-gate	my($method,$action,@other) =
1732*0Sstevel@tonic-gate	    rearrange([METHOD,ACTION],@p);
1733*0Sstevel@tonic-gate	return $self->startform($method,$action,&MULTIPART,@other);
1734*0Sstevel@tonic-gate    }
1735*0Sstevel@tonic-gate}
1736*0Sstevel@tonic-gateEND_OF_FUNC
1737*0Sstevel@tonic-gate
1738*0Sstevel@tonic-gate
1739*0Sstevel@tonic-gate#### Method: endform
1740*0Sstevel@tonic-gate# End a form
1741*0Sstevel@tonic-gate'endform' => <<'END_OF_FUNC',
1742*0Sstevel@tonic-gatesub endform {
1743*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1744*0Sstevel@tonic-gate    if ( $NOSTICKY ) {
1745*0Sstevel@tonic-gate    return wantarray ? ("</form>") : "\n</form>";
1746*0Sstevel@tonic-gate    } else {
1747*0Sstevel@tonic-gate    return wantarray ? ("<div>",$self->get_fields,"</div>","</form>") :
1748*0Sstevel@tonic-gate                        "<div>".$self->get_fields ."</div>\n</form>";
1749*0Sstevel@tonic-gate    }
1750*0Sstevel@tonic-gate}
1751*0Sstevel@tonic-gateEND_OF_FUNC
1752*0Sstevel@tonic-gate
1753*0Sstevel@tonic-gate
1754*0Sstevel@tonic-gate#### Method: end_form
1755*0Sstevel@tonic-gate# synonym for endform
1756*0Sstevel@tonic-gate'end_form' => <<'END_OF_FUNC',
1757*0Sstevel@tonic-gatesub end_form {
1758*0Sstevel@tonic-gate    &endform;
1759*0Sstevel@tonic-gate}
1760*0Sstevel@tonic-gateEND_OF_FUNC
1761*0Sstevel@tonic-gate
1762*0Sstevel@tonic-gate
1763*0Sstevel@tonic-gate'_textfield' => <<'END_OF_FUNC',
1764*0Sstevel@tonic-gatesub _textfield {
1765*0Sstevel@tonic-gate    my($self,$tag,@p) = self_or_default(@_);
1766*0Sstevel@tonic-gate    my($name,$default,$size,$maxlength,$override,@other) =
1767*0Sstevel@tonic-gate	rearrange([NAME,[DEFAULT,VALUE,VALUES],SIZE,MAXLENGTH,[OVERRIDE,FORCE]],@p);
1768*0Sstevel@tonic-gate
1769*0Sstevel@tonic-gate    my $current = $override ? $default :
1770*0Sstevel@tonic-gate	(defined($self->param($name)) ? $self->param($name) : $default);
1771*0Sstevel@tonic-gate
1772*0Sstevel@tonic-gate    $current = defined($current) ? $self->escapeHTML($current,1) : '';
1773*0Sstevel@tonic-gate    $name = defined($name) ? $self->escapeHTML($name) : '';
1774*0Sstevel@tonic-gate    my($s) = defined($size) ? qq/ size="$size"/ : '';
1775*0Sstevel@tonic-gate    my($m) = defined($maxlength) ? qq/ maxlength="$maxlength"/ : '';
1776*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1777*0Sstevel@tonic-gate    # this entered at cristy's request to fix problems with file upload fields
1778*0Sstevel@tonic-gate    # and WebTV -- not sure it won't break stuff
1779*0Sstevel@tonic-gate    my($value) = $current ne '' ? qq(value="$current") : '';
1780*0Sstevel@tonic-gate    return $XHTML ? qq(<input type="$tag" name="$name" $value$s$m$other />)
1781*0Sstevel@tonic-gate                  : qq(<input type="$tag" name="$name" $value$s$m$other>);
1782*0Sstevel@tonic-gate}
1783*0Sstevel@tonic-gateEND_OF_FUNC
1784*0Sstevel@tonic-gate
1785*0Sstevel@tonic-gate#### Method: textfield
1786*0Sstevel@tonic-gate# Parameters:
1787*0Sstevel@tonic-gate#   $name -> Name of the text field
1788*0Sstevel@tonic-gate#   $default -> Optional default value of the field if not
1789*0Sstevel@tonic-gate#                already defined.
1790*0Sstevel@tonic-gate#   $size ->  Optional width of field in characaters.
1791*0Sstevel@tonic-gate#   $maxlength -> Optional maximum number of characters.
1792*0Sstevel@tonic-gate# Returns:
1793*0Sstevel@tonic-gate#   A string containing a <input type="text"> field
1794*0Sstevel@tonic-gate#
1795*0Sstevel@tonic-gate'textfield' => <<'END_OF_FUNC',
1796*0Sstevel@tonic-gatesub textfield {
1797*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1798*0Sstevel@tonic-gate    $self->_textfield('text',@p);
1799*0Sstevel@tonic-gate}
1800*0Sstevel@tonic-gateEND_OF_FUNC
1801*0Sstevel@tonic-gate
1802*0Sstevel@tonic-gate
1803*0Sstevel@tonic-gate#### Method: filefield
1804*0Sstevel@tonic-gate# Parameters:
1805*0Sstevel@tonic-gate#   $name -> Name of the file upload field
1806*0Sstevel@tonic-gate#   $size ->  Optional width of field in characaters.
1807*0Sstevel@tonic-gate#   $maxlength -> Optional maximum number of characters.
1808*0Sstevel@tonic-gate# Returns:
1809*0Sstevel@tonic-gate#   A string containing a <input type="file"> field
1810*0Sstevel@tonic-gate#
1811*0Sstevel@tonic-gate'filefield' => <<'END_OF_FUNC',
1812*0Sstevel@tonic-gatesub filefield {
1813*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1814*0Sstevel@tonic-gate    $self->_textfield('file',@p);
1815*0Sstevel@tonic-gate}
1816*0Sstevel@tonic-gateEND_OF_FUNC
1817*0Sstevel@tonic-gate
1818*0Sstevel@tonic-gate
1819*0Sstevel@tonic-gate#### Method: password
1820*0Sstevel@tonic-gate# Create a "secret password" entry field
1821*0Sstevel@tonic-gate# Parameters:
1822*0Sstevel@tonic-gate#   $name -> Name of the field
1823*0Sstevel@tonic-gate#   $default -> Optional default value of the field if not
1824*0Sstevel@tonic-gate#                already defined.
1825*0Sstevel@tonic-gate#   $size ->  Optional width of field in characters.
1826*0Sstevel@tonic-gate#   $maxlength -> Optional maximum characters that can be entered.
1827*0Sstevel@tonic-gate# Returns:
1828*0Sstevel@tonic-gate#   A string containing a <input type="password"> field
1829*0Sstevel@tonic-gate#
1830*0Sstevel@tonic-gate'password_field' => <<'END_OF_FUNC',
1831*0Sstevel@tonic-gatesub password_field {
1832*0Sstevel@tonic-gate    my ($self,@p) = self_or_default(@_);
1833*0Sstevel@tonic-gate    $self->_textfield('password',@p);
1834*0Sstevel@tonic-gate}
1835*0Sstevel@tonic-gateEND_OF_FUNC
1836*0Sstevel@tonic-gate
1837*0Sstevel@tonic-gate#### Method: textarea
1838*0Sstevel@tonic-gate# Parameters:
1839*0Sstevel@tonic-gate#   $name -> Name of the text field
1840*0Sstevel@tonic-gate#   $default -> Optional default value of the field if not
1841*0Sstevel@tonic-gate#                already defined.
1842*0Sstevel@tonic-gate#   $rows ->  Optional number of rows in text area
1843*0Sstevel@tonic-gate#   $columns -> Optional number of columns in text area
1844*0Sstevel@tonic-gate# Returns:
1845*0Sstevel@tonic-gate#   A string containing a <textarea></textarea> tag
1846*0Sstevel@tonic-gate#
1847*0Sstevel@tonic-gate'textarea' => <<'END_OF_FUNC',
1848*0Sstevel@tonic-gatesub textarea {
1849*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1850*0Sstevel@tonic-gate
1851*0Sstevel@tonic-gate    my($name,$default,$rows,$cols,$override,@other) =
1852*0Sstevel@tonic-gate	rearrange([NAME,[DEFAULT,VALUE],ROWS,[COLS,COLUMNS],[OVERRIDE,FORCE]],@p);
1853*0Sstevel@tonic-gate
1854*0Sstevel@tonic-gate    my($current)= $override ? $default :
1855*0Sstevel@tonic-gate	(defined($self->param($name)) ? $self->param($name) : $default);
1856*0Sstevel@tonic-gate
1857*0Sstevel@tonic-gate    $name = defined($name) ? $self->escapeHTML($name) : '';
1858*0Sstevel@tonic-gate    $current = defined($current) ? $self->escapeHTML($current) : '';
1859*0Sstevel@tonic-gate    my($r) = $rows ? qq/ rows="$rows"/ : '';
1860*0Sstevel@tonic-gate    my($c) = $cols ? qq/ cols="$cols"/ : '';
1861*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1862*0Sstevel@tonic-gate    return qq{<textarea name="$name"$r$c$other>$current</textarea>};
1863*0Sstevel@tonic-gate}
1864*0Sstevel@tonic-gateEND_OF_FUNC
1865*0Sstevel@tonic-gate
1866*0Sstevel@tonic-gate
1867*0Sstevel@tonic-gate#### Method: button
1868*0Sstevel@tonic-gate# Create a javascript button.
1869*0Sstevel@tonic-gate# Parameters:
1870*0Sstevel@tonic-gate#   $name ->  (optional) Name for the button. (-name)
1871*0Sstevel@tonic-gate#   $value -> (optional) Value of the button when selected (and visible name) (-value)
1872*0Sstevel@tonic-gate#   $onclick -> (optional) Text of the JavaScript to run when the button is
1873*0Sstevel@tonic-gate#                clicked.
1874*0Sstevel@tonic-gate# Returns:
1875*0Sstevel@tonic-gate#   A string containing a <input type="button"> tag
1876*0Sstevel@tonic-gate####
1877*0Sstevel@tonic-gate'button' => <<'END_OF_FUNC',
1878*0Sstevel@tonic-gatesub button {
1879*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1880*0Sstevel@tonic-gate
1881*0Sstevel@tonic-gate    my($label,$value,$script,@other) = rearrange([NAME,[VALUE,LABEL],
1882*0Sstevel@tonic-gate							 [ONCLICK,SCRIPT]],@p);
1883*0Sstevel@tonic-gate
1884*0Sstevel@tonic-gate    $label=$self->escapeHTML($label);
1885*0Sstevel@tonic-gate    $value=$self->escapeHTML($value,1);
1886*0Sstevel@tonic-gate    $script=$self->escapeHTML($script);
1887*0Sstevel@tonic-gate
1888*0Sstevel@tonic-gate    my($name) = '';
1889*0Sstevel@tonic-gate    $name = qq/ name="$label"/ if $label;
1890*0Sstevel@tonic-gate    $value = $value || $label;
1891*0Sstevel@tonic-gate    my($val) = '';
1892*0Sstevel@tonic-gate    $val = qq/ value="$value"/ if $value;
1893*0Sstevel@tonic-gate    $script = qq/ onclick="$script"/ if $script;
1894*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1895*0Sstevel@tonic-gate    return $XHTML ? qq(<input type="button"$name$val$script$other />)
1896*0Sstevel@tonic-gate                  : qq(<input type="button"$name$val$script$other>);
1897*0Sstevel@tonic-gate}
1898*0Sstevel@tonic-gateEND_OF_FUNC
1899*0Sstevel@tonic-gate
1900*0Sstevel@tonic-gate
1901*0Sstevel@tonic-gate#### Method: submit
1902*0Sstevel@tonic-gate# Create a "submit query" button.
1903*0Sstevel@tonic-gate# Parameters:
1904*0Sstevel@tonic-gate#   $name ->  (optional) Name for the button.
1905*0Sstevel@tonic-gate#   $value -> (optional) Value of the button when selected (also doubles as label).
1906*0Sstevel@tonic-gate#   $label -> (optional) Label printed on the button(also doubles as the value).
1907*0Sstevel@tonic-gate# Returns:
1908*0Sstevel@tonic-gate#   A string containing a <input type="submit"> tag
1909*0Sstevel@tonic-gate####
1910*0Sstevel@tonic-gate'submit' => <<'END_OF_FUNC',
1911*0Sstevel@tonic-gatesub submit {
1912*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1913*0Sstevel@tonic-gate
1914*0Sstevel@tonic-gate    my($label,$value,@other) = rearrange([NAME,[VALUE,LABEL]],@p);
1915*0Sstevel@tonic-gate
1916*0Sstevel@tonic-gate    $label=$self->escapeHTML($label);
1917*0Sstevel@tonic-gate    $value=$self->escapeHTML($value,1);
1918*0Sstevel@tonic-gate
1919*0Sstevel@tonic-gate    my $name = $NOSTICKY ? '' : ' name=".submit"';
1920*0Sstevel@tonic-gate    $name = qq/ name="$label"/ if defined($label);
1921*0Sstevel@tonic-gate    $value = defined($value) ? $value : $label;
1922*0Sstevel@tonic-gate    my $val = '';
1923*0Sstevel@tonic-gate    $val = qq/ value="$value"/ if defined($value);
1924*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1925*0Sstevel@tonic-gate    return $XHTML ? qq(<input type="submit"$name$val$other />)
1926*0Sstevel@tonic-gate                  : qq(<input type="submit"$name$val$other>);
1927*0Sstevel@tonic-gate}
1928*0Sstevel@tonic-gateEND_OF_FUNC
1929*0Sstevel@tonic-gate
1930*0Sstevel@tonic-gate
1931*0Sstevel@tonic-gate#### Method: reset
1932*0Sstevel@tonic-gate# Create a "reset" button.
1933*0Sstevel@tonic-gate# Parameters:
1934*0Sstevel@tonic-gate#   $name -> (optional) Name for the button.
1935*0Sstevel@tonic-gate# Returns:
1936*0Sstevel@tonic-gate#   A string containing a <input type="reset"> tag
1937*0Sstevel@tonic-gate####
1938*0Sstevel@tonic-gate'reset' => <<'END_OF_FUNC',
1939*0Sstevel@tonic-gatesub reset {
1940*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1941*0Sstevel@tonic-gate    my($label,$value,@other) = rearrange(['NAME',['VALUE','LABEL']],@p);
1942*0Sstevel@tonic-gate    $label=$self->escapeHTML($label);
1943*0Sstevel@tonic-gate    $value=$self->escapeHTML($value,1);
1944*0Sstevel@tonic-gate    my ($name) = ' name=".reset"';
1945*0Sstevel@tonic-gate    $name = qq/ name="$label"/ if defined($label);
1946*0Sstevel@tonic-gate    $value = defined($value) ? $value : $label;
1947*0Sstevel@tonic-gate    my($val) = '';
1948*0Sstevel@tonic-gate    $val = qq/ value="$value"/ if defined($value);
1949*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1950*0Sstevel@tonic-gate    return $XHTML ? qq(<input type="reset"$name$val$other />)
1951*0Sstevel@tonic-gate                  : qq(<input type="reset"$name$val$other>);
1952*0Sstevel@tonic-gate}
1953*0Sstevel@tonic-gateEND_OF_FUNC
1954*0Sstevel@tonic-gate
1955*0Sstevel@tonic-gate
1956*0Sstevel@tonic-gate#### Method: defaults
1957*0Sstevel@tonic-gate# Create a "defaults" button.
1958*0Sstevel@tonic-gate# Parameters:
1959*0Sstevel@tonic-gate#   $name -> (optional) Name for the button.
1960*0Sstevel@tonic-gate# Returns:
1961*0Sstevel@tonic-gate#   A string containing a <input type="submit" name=".defaults"> tag
1962*0Sstevel@tonic-gate#
1963*0Sstevel@tonic-gate# Note: this button has a special meaning to the initialization script,
1964*0Sstevel@tonic-gate# and tells it to ERASE the current query string so that your defaults
1965*0Sstevel@tonic-gate# are used again!
1966*0Sstevel@tonic-gate####
1967*0Sstevel@tonic-gate'defaults' => <<'END_OF_FUNC',
1968*0Sstevel@tonic-gatesub defaults {
1969*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
1970*0Sstevel@tonic-gate
1971*0Sstevel@tonic-gate    my($label,@other) = rearrange([[NAME,VALUE]],@p);
1972*0Sstevel@tonic-gate
1973*0Sstevel@tonic-gate    $label=$self->escapeHTML($label,1);
1974*0Sstevel@tonic-gate    $label = $label || "Defaults";
1975*0Sstevel@tonic-gate    my($value) = qq/ value="$label"/;
1976*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
1977*0Sstevel@tonic-gate    return $XHTML ? qq(<input type="submit" name=".defaults"$value$other />)
1978*0Sstevel@tonic-gate                  : qq/<input type="submit" NAME=".defaults"$value$other>/;
1979*0Sstevel@tonic-gate}
1980*0Sstevel@tonic-gateEND_OF_FUNC
1981*0Sstevel@tonic-gate
1982*0Sstevel@tonic-gate
1983*0Sstevel@tonic-gate#### Method: comment
1984*0Sstevel@tonic-gate# Create an HTML <!-- comment -->
1985*0Sstevel@tonic-gate# Parameters: a string
1986*0Sstevel@tonic-gate'comment' => <<'END_OF_FUNC',
1987*0Sstevel@tonic-gatesub comment {
1988*0Sstevel@tonic-gate    my($self,@p) = self_or_CGI(@_);
1989*0Sstevel@tonic-gate    return "<!-- @p -->";
1990*0Sstevel@tonic-gate}
1991*0Sstevel@tonic-gateEND_OF_FUNC
1992*0Sstevel@tonic-gate
1993*0Sstevel@tonic-gate#### Method: checkbox
1994*0Sstevel@tonic-gate# Create a checkbox that is not logically linked to any others.
1995*0Sstevel@tonic-gate# The field value is "on" when the button is checked.
1996*0Sstevel@tonic-gate# Parameters:
1997*0Sstevel@tonic-gate#   $name -> Name of the checkbox
1998*0Sstevel@tonic-gate#   $checked -> (optional) turned on by default if true
1999*0Sstevel@tonic-gate#   $value -> (optional) value of the checkbox, 'on' by default
2000*0Sstevel@tonic-gate#   $label -> (optional) a user-readable label printed next to the box.
2001*0Sstevel@tonic-gate#             Otherwise the checkbox name is used.
2002*0Sstevel@tonic-gate# Returns:
2003*0Sstevel@tonic-gate#   A string containing a <input type="checkbox"> field
2004*0Sstevel@tonic-gate####
2005*0Sstevel@tonic-gate'checkbox' => <<'END_OF_FUNC',
2006*0Sstevel@tonic-gatesub checkbox {
2007*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2008*0Sstevel@tonic-gate
2009*0Sstevel@tonic-gate    my($name,$checked,$value,$label,$override,@other) =
2010*0Sstevel@tonic-gate	rearrange([NAME,[CHECKED,SELECTED,ON],VALUE,LABEL,[OVERRIDE,FORCE]],@p);
2011*0Sstevel@tonic-gate
2012*0Sstevel@tonic-gate    $value = defined $value ? $value : 'on';
2013*0Sstevel@tonic-gate
2014*0Sstevel@tonic-gate    if (!$override && ($self->{'.fieldnames'}->{$name} ||
2015*0Sstevel@tonic-gate		       defined $self->param($name))) {
2016*0Sstevel@tonic-gate	$checked = grep($_ eq $value,$self->param($name)) ? $self->_checked(1) : '';
2017*0Sstevel@tonic-gate    } else {
2018*0Sstevel@tonic-gate	$checked = $self->_checked($checked);
2019*0Sstevel@tonic-gate    }
2020*0Sstevel@tonic-gate    my($the_label) = defined $label ? $label : $name;
2021*0Sstevel@tonic-gate    $name = $self->escapeHTML($name);
2022*0Sstevel@tonic-gate    $value = $self->escapeHTML($value,1);
2023*0Sstevel@tonic-gate    $the_label = $self->escapeHTML($the_label);
2024*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2025*0Sstevel@tonic-gate    $self->register_parameter($name);
2026*0Sstevel@tonic-gate    return $XHTML ? qq{<input type="checkbox" name="$name" value="$value"$checked$other />$the_label}
2027*0Sstevel@tonic-gate                  : qq{<input type="checkbox" name="$name" value="$value"$checked$other>$the_label};
2028*0Sstevel@tonic-gate}
2029*0Sstevel@tonic-gateEND_OF_FUNC
2030*0Sstevel@tonic-gate
2031*0Sstevel@tonic-gate
2032*0Sstevel@tonic-gate#### Method: checkbox_group
2033*0Sstevel@tonic-gate# Create a list of logically-linked checkboxes.
2034*0Sstevel@tonic-gate# Parameters:
2035*0Sstevel@tonic-gate#   $name -> Common name for all the check boxes
2036*0Sstevel@tonic-gate#   $values -> A pointer to a regular array containing the
2037*0Sstevel@tonic-gate#             values for each checkbox in the group.
2038*0Sstevel@tonic-gate#   $defaults -> (optional)
2039*0Sstevel@tonic-gate#             1. If a pointer to a regular array of checkbox values,
2040*0Sstevel@tonic-gate#             then this will be used to decide which
2041*0Sstevel@tonic-gate#             checkboxes to turn on by default.
2042*0Sstevel@tonic-gate#             2. If a scalar, will be assumed to hold the
2043*0Sstevel@tonic-gate#             value of a single checkbox in the group to turn on.
2044*0Sstevel@tonic-gate#   $linebreak -> (optional) Set to true to place linebreaks
2045*0Sstevel@tonic-gate#             between the buttons.
2046*0Sstevel@tonic-gate#   $labels -> (optional)
2047*0Sstevel@tonic-gate#             A pointer to an associative array of labels to print next to each checkbox
2048*0Sstevel@tonic-gate#             in the form $label{'value'}="Long explanatory label".
2049*0Sstevel@tonic-gate#             Otherwise the provided values are used as the labels.
2050*0Sstevel@tonic-gate# Returns:
2051*0Sstevel@tonic-gate#   An ARRAY containing a series of <input type="checkbox"> fields
2052*0Sstevel@tonic-gate####
2053*0Sstevel@tonic-gate'checkbox_group' => <<'END_OF_FUNC',
2054*0Sstevel@tonic-gatesub checkbox_group {
2055*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2056*0Sstevel@tonic-gate
2057*0Sstevel@tonic-gate    my($name,$values,$defaults,$linebreak,$labels,$attributes,$rows,$columns,
2058*0Sstevel@tonic-gate       $rowheaders,$colheaders,$override,$nolabels,@other) =
2059*0Sstevel@tonic-gate	rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT],
2060*0Sstevel@tonic-gate            LINEBREAK,LABELS,ATTRIBUTES,ROWS,[COLUMNS,COLS],
2061*0Sstevel@tonic-gate			  ROWHEADERS,COLHEADERS,
2062*0Sstevel@tonic-gate			  [OVERRIDE,FORCE],NOLABELS],@p);
2063*0Sstevel@tonic-gate
2064*0Sstevel@tonic-gate    my($checked,$break,$result,$label);
2065*0Sstevel@tonic-gate
2066*0Sstevel@tonic-gate    my(%checked) = $self->previous_or_default($name,$defaults,$override);
2067*0Sstevel@tonic-gate
2068*0Sstevel@tonic-gate	if ($linebreak) {
2069*0Sstevel@tonic-gate    $break = $XHTML ? "<br />" : "<br>";
2070*0Sstevel@tonic-gate	}
2071*0Sstevel@tonic-gate	else {
2072*0Sstevel@tonic-gate	$break = '';
2073*0Sstevel@tonic-gate	}
2074*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2075*0Sstevel@tonic-gate
2076*0Sstevel@tonic-gate    # Create the elements
2077*0Sstevel@tonic-gate    my(@elements,@values);
2078*0Sstevel@tonic-gate
2079*0Sstevel@tonic-gate    @values = $self->_set_values_and_labels($values,\$labels,$name);
2080*0Sstevel@tonic-gate
2081*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2082*0Sstevel@tonic-gate    foreach (@values) {
2083*0Sstevel@tonic-gate	$checked = $self->_checked($checked{$_});
2084*0Sstevel@tonic-gate	$label = '';
2085*0Sstevel@tonic-gate	unless (defined($nolabels) && $nolabels) {
2086*0Sstevel@tonic-gate	    $label = $_;
2087*0Sstevel@tonic-gate	    $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
2088*0Sstevel@tonic-gate	    $label = $self->escapeHTML($label);
2089*0Sstevel@tonic-gate	}
2090*0Sstevel@tonic-gate        my $attribs = $self->_set_attributes($_, $attributes);
2091*0Sstevel@tonic-gate	$_ = $self->escapeHTML($_,1);
2092*0Sstevel@tonic-gate        push(@elements,$XHTML ? qq(<input type="checkbox" name="$name" value="$_"$checked$other$attribs />${label}${break})
2093*0Sstevel@tonic-gate                              : qq/<input type="checkbox" name="$name" value="$_"$checked$other$attribs>${label}${break}/);
2094*0Sstevel@tonic-gate    }
2095*0Sstevel@tonic-gate    $self->register_parameter($name);
2096*0Sstevel@tonic-gate    return wantarray ? @elements : join(' ',@elements)
2097*0Sstevel@tonic-gate        unless defined($columns) || defined($rows);
2098*0Sstevel@tonic-gate    $rows = 1 if $rows && $rows < 1;
2099*0Sstevel@tonic-gate    $cols = 1 if $cols && $cols < 1;
2100*0Sstevel@tonic-gate    return _tableize($rows,$columns,$rowheaders,$colheaders,@elements);
2101*0Sstevel@tonic-gate}
2102*0Sstevel@tonic-gateEND_OF_FUNC
2103*0Sstevel@tonic-gate
2104*0Sstevel@tonic-gate# Escape HTML -- used internally
2105*0Sstevel@tonic-gate'escapeHTML' => <<'END_OF_FUNC',
2106*0Sstevel@tonic-gatesub escapeHTML {
2107*0Sstevel@tonic-gate         # hack to work around  earlier hacks
2108*0Sstevel@tonic-gate         push @_,$_[0] if @_==1 && $_[0] eq 'CGI';
2109*0Sstevel@tonic-gate         my ($self,$toencode,$newlinestoo) = CGI::self_or_default(@_);
2110*0Sstevel@tonic-gate         return undef unless defined($toencode);
2111*0Sstevel@tonic-gate         return $toencode if ref($self) && !$self->{'escape'};
2112*0Sstevel@tonic-gate         $toencode =~ s{&}{&amp;}gso;
2113*0Sstevel@tonic-gate         $toencode =~ s{<}{&lt;}gso;
2114*0Sstevel@tonic-gate         $toencode =~ s{>}{&gt;}gso;
2115*0Sstevel@tonic-gate         $toencode =~ s{"}{&quot;}gso;
2116*0Sstevel@tonic-gate         my $latin = uc $self->{'.charset'} eq 'ISO-8859-1' ||
2117*0Sstevel@tonic-gate                     uc $self->{'.charset'} eq 'WINDOWS-1252';
2118*0Sstevel@tonic-gate         if ($latin) {  # bug in some browsers
2119*0Sstevel@tonic-gate                $toencode =~ s{'}{&#39;}gso;
2120*0Sstevel@tonic-gate                $toencode =~ s{\x8b}{&#8249;}gso;
2121*0Sstevel@tonic-gate                $toencode =~ s{\x9b}{&#8250;}gso;
2122*0Sstevel@tonic-gate                if (defined $newlinestoo && $newlinestoo) {
2123*0Sstevel@tonic-gate                     $toencode =~ s{\012}{&#10;}gso;
2124*0Sstevel@tonic-gate                     $toencode =~ s{\015}{&#13;}gso;
2125*0Sstevel@tonic-gate                }
2126*0Sstevel@tonic-gate         }
2127*0Sstevel@tonic-gate         return $toencode;
2128*0Sstevel@tonic-gate}
2129*0Sstevel@tonic-gateEND_OF_FUNC
2130*0Sstevel@tonic-gate
2131*0Sstevel@tonic-gate# unescape HTML -- used internally
2132*0Sstevel@tonic-gate'unescapeHTML' => <<'END_OF_FUNC',
2133*0Sstevel@tonic-gatesub unescapeHTML {
2134*0Sstevel@tonic-gate    # hack to work around  earlier hacks
2135*0Sstevel@tonic-gate    push @_,$_[0] if @_==1 && $_[0] eq 'CGI';
2136*0Sstevel@tonic-gate    my ($self,$string) = CGI::self_or_default(@_);
2137*0Sstevel@tonic-gate    return undef unless defined($string);
2138*0Sstevel@tonic-gate    my $latin = defined $self->{'.charset'} ? $self->{'.charset'} =~ /^(ISO-8859-1|WINDOWS-1252)$/i
2139*0Sstevel@tonic-gate                                            : 1;
2140*0Sstevel@tonic-gate    # thanks to Randal Schwartz for the correct solution to this one
2141*0Sstevel@tonic-gate    $string=~ s[&(.*?);]{
2142*0Sstevel@tonic-gate	local $_ = $1;
2143*0Sstevel@tonic-gate	/^amp$/i	? "&" :
2144*0Sstevel@tonic-gate	/^quot$/i	? '"' :
2145*0Sstevel@tonic-gate        /^gt$/i		? ">" :
2146*0Sstevel@tonic-gate	/^lt$/i		? "<" :
2147*0Sstevel@tonic-gate	/^#(\d+)$/ && $latin	     ? chr($1) :
2148*0Sstevel@tonic-gate	/^#x([0-9a-f]+)$/i && $latin ? chr(hex($1)) :
2149*0Sstevel@tonic-gate	$_
2150*0Sstevel@tonic-gate	}gex;
2151*0Sstevel@tonic-gate    return $string;
2152*0Sstevel@tonic-gate}
2153*0Sstevel@tonic-gateEND_OF_FUNC
2154*0Sstevel@tonic-gate
2155*0Sstevel@tonic-gate# Internal procedure - don't use
2156*0Sstevel@tonic-gate'_tableize' => <<'END_OF_FUNC',
2157*0Sstevel@tonic-gatesub _tableize {
2158*0Sstevel@tonic-gate    my($rows,$columns,$rowheaders,$colheaders,@elements) = @_;
2159*0Sstevel@tonic-gate    $rowheaders = [] unless defined $rowheaders;
2160*0Sstevel@tonic-gate    $colheaders = [] unless defined $colheaders;
2161*0Sstevel@tonic-gate    my($result);
2162*0Sstevel@tonic-gate
2163*0Sstevel@tonic-gate    if (defined($columns)) {
2164*0Sstevel@tonic-gate	$rows = int(0.99 + @elements/$columns) unless defined($rows);
2165*0Sstevel@tonic-gate    }
2166*0Sstevel@tonic-gate    if (defined($rows)) {
2167*0Sstevel@tonic-gate	$columns = int(0.99 + @elements/$rows) unless defined($columns);
2168*0Sstevel@tonic-gate    }
2169*0Sstevel@tonic-gate
2170*0Sstevel@tonic-gate    # rearrange into a pretty table
2171*0Sstevel@tonic-gate    $result = "<table>";
2172*0Sstevel@tonic-gate    my($row,$column);
2173*0Sstevel@tonic-gate    unshift(@$colheaders,'') if @$colheaders && @$rowheaders;
2174*0Sstevel@tonic-gate    $result .= "<tr>" if @{$colheaders};
2175*0Sstevel@tonic-gate    foreach (@{$colheaders}) {
2176*0Sstevel@tonic-gate	$result .= "<th>$_</th>";
2177*0Sstevel@tonic-gate    }
2178*0Sstevel@tonic-gate    for ($row=0;$row<$rows;$row++) {
2179*0Sstevel@tonic-gate	$result .= "<tr>";
2180*0Sstevel@tonic-gate	$result .= "<th>$rowheaders->[$row]</th>" if @$rowheaders;
2181*0Sstevel@tonic-gate	for ($column=0;$column<$columns;$column++) {
2182*0Sstevel@tonic-gate	    $result .= "<td>" . $elements[$column*$rows + $row] . "</td>"
2183*0Sstevel@tonic-gate		if defined($elements[$column*$rows + $row]);
2184*0Sstevel@tonic-gate	}
2185*0Sstevel@tonic-gate	$result .= "</tr>";
2186*0Sstevel@tonic-gate    }
2187*0Sstevel@tonic-gate    $result .= "</table>";
2188*0Sstevel@tonic-gate    return $result;
2189*0Sstevel@tonic-gate}
2190*0Sstevel@tonic-gateEND_OF_FUNC
2191*0Sstevel@tonic-gate
2192*0Sstevel@tonic-gate
2193*0Sstevel@tonic-gate#### Method: radio_group
2194*0Sstevel@tonic-gate# Create a list of logically-linked radio buttons.
2195*0Sstevel@tonic-gate# Parameters:
2196*0Sstevel@tonic-gate#   $name -> Common name for all the buttons.
2197*0Sstevel@tonic-gate#   $values -> A pointer to a regular array containing the
2198*0Sstevel@tonic-gate#             values for each button in the group.
2199*0Sstevel@tonic-gate#   $default -> (optional) Value of the button to turn on by default.  Pass '-'
2200*0Sstevel@tonic-gate#               to turn _nothing_ on.
2201*0Sstevel@tonic-gate#   $linebreak -> (optional) Set to true to place linebreaks
2202*0Sstevel@tonic-gate#             between the buttons.
2203*0Sstevel@tonic-gate#   $labels -> (optional)
2204*0Sstevel@tonic-gate#             A pointer to an associative array of labels to print next to each checkbox
2205*0Sstevel@tonic-gate#             in the form $label{'value'}="Long explanatory label".
2206*0Sstevel@tonic-gate#             Otherwise the provided values are used as the labels.
2207*0Sstevel@tonic-gate# Returns:
2208*0Sstevel@tonic-gate#   An ARRAY containing a series of <input type="radio"> fields
2209*0Sstevel@tonic-gate####
2210*0Sstevel@tonic-gate'radio_group' => <<'END_OF_FUNC',
2211*0Sstevel@tonic-gatesub radio_group {
2212*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2213*0Sstevel@tonic-gate
2214*0Sstevel@tonic-gate    my($name,$values,$default,$linebreak,$labels,$attributes,
2215*0Sstevel@tonic-gate       $rows,$columns,$rowheaders,$colheaders,$override,$nolabels,@other) =
2216*0Sstevel@tonic-gate  rearrange([NAME,[VALUES,VALUE],DEFAULT,LINEBREAK,LABELS,ATTRIBUTES,
2217*0Sstevel@tonic-gate			  ROWS,[COLUMNS,COLS],
2218*0Sstevel@tonic-gate			  ROWHEADERS,COLHEADERS,
2219*0Sstevel@tonic-gate			  [OVERRIDE,FORCE],NOLABELS],@p);
2220*0Sstevel@tonic-gate    my($result,$checked);
2221*0Sstevel@tonic-gate
2222*0Sstevel@tonic-gate    if (!$override && defined($self->param($name))) {
2223*0Sstevel@tonic-gate	$checked = $self->param($name);
2224*0Sstevel@tonic-gate    } else {
2225*0Sstevel@tonic-gate	$checked = $default;
2226*0Sstevel@tonic-gate    }
2227*0Sstevel@tonic-gate    my(@elements,@values);
2228*0Sstevel@tonic-gate    @values = $self->_set_values_and_labels($values,\$labels,$name);
2229*0Sstevel@tonic-gate
2230*0Sstevel@tonic-gate    # If no check array is specified, check the first by default
2231*0Sstevel@tonic-gate    $checked = $values[0] unless defined($checked) && $checked ne '';
2232*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2233*0Sstevel@tonic-gate
2234*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2235*0Sstevel@tonic-gate    foreach (@values) {
2236*0Sstevel@tonic-gate	my($checkit) = $checked eq $_ ? qq/ checked="checked"/ : '';
2237*0Sstevel@tonic-gate	my($break);
2238*0Sstevel@tonic-gate	if ($linebreak) {
2239*0Sstevel@tonic-gate          $break = $XHTML ? "<br />" : "<br>";
2240*0Sstevel@tonic-gate	}
2241*0Sstevel@tonic-gate	else {
2242*0Sstevel@tonic-gate	  $break = '';
2243*0Sstevel@tonic-gate	}
2244*0Sstevel@tonic-gate	my($label)='';
2245*0Sstevel@tonic-gate	unless (defined($nolabels) && $nolabels) {
2246*0Sstevel@tonic-gate	    $label = $_;
2247*0Sstevel@tonic-gate	    $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
2248*0Sstevel@tonic-gate	    $label = $self->escapeHTML($label,1);
2249*0Sstevel@tonic-gate	}
2250*0Sstevel@tonic-gate  my $attribs = $self->_set_attributes($_, $attributes);
2251*0Sstevel@tonic-gate	$_=$self->escapeHTML($_);
2252*0Sstevel@tonic-gate  push(@elements,$XHTML ? qq(<input type="radio" name="$name" value="$_"$checkit$other$attribs />${label}${break})
2253*0Sstevel@tonic-gate                              : qq/<input type="radio" name="$name" value="$_"$checkit$other$attribs>${label}${break}/);
2254*0Sstevel@tonic-gate    }
2255*0Sstevel@tonic-gate    $self->register_parameter($name);
2256*0Sstevel@tonic-gate    return wantarray ? @elements : join(' ',@elements)
2257*0Sstevel@tonic-gate           unless defined($columns) || defined($rows);
2258*0Sstevel@tonic-gate    return _tableize($rows,$columns,$rowheaders,$colheaders,@elements);
2259*0Sstevel@tonic-gate}
2260*0Sstevel@tonic-gateEND_OF_FUNC
2261*0Sstevel@tonic-gate
2262*0Sstevel@tonic-gate
2263*0Sstevel@tonic-gate#### Method: popup_menu
2264*0Sstevel@tonic-gate# Create a popup menu.
2265*0Sstevel@tonic-gate# Parameters:
2266*0Sstevel@tonic-gate#   $name -> Name for all the menu
2267*0Sstevel@tonic-gate#   $values -> A pointer to a regular array containing the
2268*0Sstevel@tonic-gate#             text of each menu item.
2269*0Sstevel@tonic-gate#   $default -> (optional) Default item to display
2270*0Sstevel@tonic-gate#   $labels -> (optional)
2271*0Sstevel@tonic-gate#             A pointer to an associative array of labels to print next to each checkbox
2272*0Sstevel@tonic-gate#             in the form $label{'value'}="Long explanatory label".
2273*0Sstevel@tonic-gate#             Otherwise the provided values are used as the labels.
2274*0Sstevel@tonic-gate# Returns:
2275*0Sstevel@tonic-gate#   A string containing the definition of a popup menu.
2276*0Sstevel@tonic-gate####
2277*0Sstevel@tonic-gate'popup_menu' => <<'END_OF_FUNC',
2278*0Sstevel@tonic-gatesub popup_menu {
2279*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2280*0Sstevel@tonic-gate
2281*0Sstevel@tonic-gate    my($name,$values,$default,$labels,$attributes,$override,@other) =
2282*0Sstevel@tonic-gate       rearrange([NAME,[VALUES,VALUE],[DEFAULT,DEFAULTS],LABELS,
2283*0Sstevel@tonic-gate       ATTRIBUTES,[OVERRIDE,FORCE]],@p);
2284*0Sstevel@tonic-gate    my($result,$selected);
2285*0Sstevel@tonic-gate
2286*0Sstevel@tonic-gate    if (!$override && defined($self->param($name))) {
2287*0Sstevel@tonic-gate	$selected = $self->param($name);
2288*0Sstevel@tonic-gate    } else {
2289*0Sstevel@tonic-gate	$selected = $default;
2290*0Sstevel@tonic-gate    }
2291*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2292*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2293*0Sstevel@tonic-gate
2294*0Sstevel@tonic-gate    my(@values);
2295*0Sstevel@tonic-gate    @values = $self->_set_values_and_labels($values,\$labels,$name);
2296*0Sstevel@tonic-gate
2297*0Sstevel@tonic-gate    $result = qq/<select name="$name"$other>\n/;
2298*0Sstevel@tonic-gate    foreach (@values) {
2299*0Sstevel@tonic-gate        if (/<optgroup/) {
2300*0Sstevel@tonic-gate            foreach (split(/\n/)) {
2301*0Sstevel@tonic-gate                my $selectit = $XHTML ? 'selected="selected"' : 'selected';
2302*0Sstevel@tonic-gate                s/(value="$selected")/$selectit $1/ if defined $selected;
2303*0Sstevel@tonic-gate                $result .= "$_\n";
2304*0Sstevel@tonic-gate            }
2305*0Sstevel@tonic-gate        }
2306*0Sstevel@tonic-gate        else {
2307*0Sstevel@tonic-gate            my $attribs = $self->_set_attributes($_, $attributes);
2308*0Sstevel@tonic-gate	my($selectit) = defined($selected) ? $self->_selected($selected eq $_) : '';
2309*0Sstevel@tonic-gate	my($label) = $_;
2310*0Sstevel@tonic-gate	$label = $labels->{$_} if defined($labels) && defined($labels->{$_});
2311*0Sstevel@tonic-gate	my($value) = $self->escapeHTML($_);
2312*0Sstevel@tonic-gate	$label=$self->escapeHTML($label,1);
2313*0Sstevel@tonic-gate            $result .= "<option$selectit$attribs value=\"$value\">$label</option>\n";
2314*0Sstevel@tonic-gate        }
2315*0Sstevel@tonic-gate    }
2316*0Sstevel@tonic-gate
2317*0Sstevel@tonic-gate    $result .= "</select>";
2318*0Sstevel@tonic-gate    return $result;
2319*0Sstevel@tonic-gate}
2320*0Sstevel@tonic-gateEND_OF_FUNC
2321*0Sstevel@tonic-gate
2322*0Sstevel@tonic-gate
2323*0Sstevel@tonic-gate#### Method: optgroup
2324*0Sstevel@tonic-gate# Create a optgroup.
2325*0Sstevel@tonic-gate# Parameters:
2326*0Sstevel@tonic-gate#   $name -> Label for the group
2327*0Sstevel@tonic-gate#   $values -> A pointer to a regular array containing the
2328*0Sstevel@tonic-gate#              values for each option line in the group.
2329*0Sstevel@tonic-gate#   $labels -> (optional)
2330*0Sstevel@tonic-gate#              A pointer to an associative array of labels to print next to each item
2331*0Sstevel@tonic-gate#              in the form $label{'value'}="Long explanatory label".
2332*0Sstevel@tonic-gate#              Otherwise the provided values are used as the labels.
2333*0Sstevel@tonic-gate#   $labeled -> (optional)
2334*0Sstevel@tonic-gate#               A true value indicates the value should be used as the label attribute
2335*0Sstevel@tonic-gate#               in the option elements.
2336*0Sstevel@tonic-gate#               The label attribute specifies the option label presented to the user.
2337*0Sstevel@tonic-gate#               This defaults to the content of the <option> element, but the label
2338*0Sstevel@tonic-gate#               attribute allows authors to more easily use optgroup without sacrificing
2339*0Sstevel@tonic-gate#               compatibility with browsers that do not support option groups.
2340*0Sstevel@tonic-gate#   $novals -> (optional)
2341*0Sstevel@tonic-gate#              A true value indicates to suppress the val attribute in the option elements
2342*0Sstevel@tonic-gate# Returns:
2343*0Sstevel@tonic-gate#   A string containing the definition of an option group.
2344*0Sstevel@tonic-gate####
2345*0Sstevel@tonic-gate'optgroup' => <<'END_OF_FUNC',
2346*0Sstevel@tonic-gatesub optgroup {
2347*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2348*0Sstevel@tonic-gate    my($name,$values,$attributes,$labeled,$noval,$labels,@other)
2349*0Sstevel@tonic-gate        = rearrange([NAME,[VALUES,VALUE],ATTRIBUTES,LABELED,NOVALS,LABELS],@p);
2350*0Sstevel@tonic-gate
2351*0Sstevel@tonic-gate    my($result,@values);
2352*0Sstevel@tonic-gate    @values = $self->_set_values_and_labels($values,\$labels,$name,$labeled,$novals);
2353*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2354*0Sstevel@tonic-gate
2355*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2356*0Sstevel@tonic-gate    $result = qq/<optgroup label="$name"$other>\n/;
2357*0Sstevel@tonic-gate    foreach (@values) {
2358*0Sstevel@tonic-gate        if (/<optgroup/) {
2359*0Sstevel@tonic-gate            foreach (split(/\n/)) {
2360*0Sstevel@tonic-gate                my $selectit = $XHTML ? 'selected="selected"' : 'selected';
2361*0Sstevel@tonic-gate                s/(value="$selected")/$selectit $1/ if defined $selected;
2362*0Sstevel@tonic-gate                $result .= "$_\n";
2363*0Sstevel@tonic-gate            }
2364*0Sstevel@tonic-gate        }
2365*0Sstevel@tonic-gate        else {
2366*0Sstevel@tonic-gate            my $attribs = $self->_set_attributes($_, $attributes);
2367*0Sstevel@tonic-gate            my($label) = $_;
2368*0Sstevel@tonic-gate            $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
2369*0Sstevel@tonic-gate            $label=$self->escapeHTML($label);
2370*0Sstevel@tonic-gate            my($value)=$self->escapeHTML($_,1);
2371*0Sstevel@tonic-gate            $result .= $labeled ? $novals ? "<option$attribs label=\"$value\">$label</option>\n"
2372*0Sstevel@tonic-gate                                          : "<option$attribs label=\"$value\" value=\"$value\">$label</option>\n"
2373*0Sstevel@tonic-gate                                : $novals ? "<option$attribs>$label</option>\n"
2374*0Sstevel@tonic-gate                                          : "<option$attribs value=\"$value\">$label</option>\n";
2375*0Sstevel@tonic-gate        }
2376*0Sstevel@tonic-gate    }
2377*0Sstevel@tonic-gate    $result .= "</optgroup>";
2378*0Sstevel@tonic-gate    return $result;
2379*0Sstevel@tonic-gate}
2380*0Sstevel@tonic-gateEND_OF_FUNC
2381*0Sstevel@tonic-gate
2382*0Sstevel@tonic-gate
2383*0Sstevel@tonic-gate#### Method: scrolling_list
2384*0Sstevel@tonic-gate# Create a scrolling list.
2385*0Sstevel@tonic-gate# Parameters:
2386*0Sstevel@tonic-gate#   $name -> name for the list
2387*0Sstevel@tonic-gate#   $values -> A pointer to a regular array containing the
2388*0Sstevel@tonic-gate#             values for each option line in the list.
2389*0Sstevel@tonic-gate#   $defaults -> (optional)
2390*0Sstevel@tonic-gate#             1. If a pointer to a regular array of options,
2391*0Sstevel@tonic-gate#             then this will be used to decide which
2392*0Sstevel@tonic-gate#             lines to turn on by default.
2393*0Sstevel@tonic-gate#             2. Otherwise holds the value of the single line to turn on.
2394*0Sstevel@tonic-gate#   $size -> (optional) Size of the list.
2395*0Sstevel@tonic-gate#   $multiple -> (optional) If set, allow multiple selections.
2396*0Sstevel@tonic-gate#   $labels -> (optional)
2397*0Sstevel@tonic-gate#             A pointer to an associative array of labels to print next to each checkbox
2398*0Sstevel@tonic-gate#             in the form $label{'value'}="Long explanatory label".
2399*0Sstevel@tonic-gate#             Otherwise the provided values are used as the labels.
2400*0Sstevel@tonic-gate# Returns:
2401*0Sstevel@tonic-gate#   A string containing the definition of a scrolling list.
2402*0Sstevel@tonic-gate####
2403*0Sstevel@tonic-gate'scrolling_list' => <<'END_OF_FUNC',
2404*0Sstevel@tonic-gatesub scrolling_list {
2405*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2406*0Sstevel@tonic-gate    my($name,$values,$defaults,$size,$multiple,$labels,$attributes,$override,@other)
2407*0Sstevel@tonic-gate	= rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT],
2408*0Sstevel@tonic-gate          SIZE,MULTIPLE,LABELS,ATTRIBUTES,[OVERRIDE,FORCE]],@p);
2409*0Sstevel@tonic-gate
2410*0Sstevel@tonic-gate    my($result,@values);
2411*0Sstevel@tonic-gate    @values = $self->_set_values_and_labels($values,\$labels,$name);
2412*0Sstevel@tonic-gate
2413*0Sstevel@tonic-gate    $size = $size || scalar(@values);
2414*0Sstevel@tonic-gate
2415*0Sstevel@tonic-gate    my(%selected) = $self->previous_or_default($name,$defaults,$override);
2416*0Sstevel@tonic-gate    my($is_multiple) = $multiple ? qq/ multiple="multiple"/ : '';
2417*0Sstevel@tonic-gate    my($has_size) = $size ? qq/ size="$size"/: '';
2418*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2419*0Sstevel@tonic-gate
2420*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2421*0Sstevel@tonic-gate    $result = qq/<select name="$name"$has_size$is_multiple$other>\n/;
2422*0Sstevel@tonic-gate    foreach (@values) {
2423*0Sstevel@tonic-gate	my($selectit) = $self->_selected($selected{$_});
2424*0Sstevel@tonic-gate	my($label) = $_;
2425*0Sstevel@tonic-gate	$label = $labels->{$_} if defined($labels) && defined($labels->{$_});
2426*0Sstevel@tonic-gate	$label=$self->escapeHTML($label);
2427*0Sstevel@tonic-gate	my($value)=$self->escapeHTML($_,1);
2428*0Sstevel@tonic-gate        my $attribs = $self->_set_attributes($_, $attributes);
2429*0Sstevel@tonic-gate        $result .= "<option$selectit$attribs value=\"$value\">$label</option>\n";
2430*0Sstevel@tonic-gate    }
2431*0Sstevel@tonic-gate    $result .= "</select>";
2432*0Sstevel@tonic-gate    $self->register_parameter($name);
2433*0Sstevel@tonic-gate    return $result;
2434*0Sstevel@tonic-gate}
2435*0Sstevel@tonic-gateEND_OF_FUNC
2436*0Sstevel@tonic-gate
2437*0Sstevel@tonic-gate
2438*0Sstevel@tonic-gate#### Method: hidden
2439*0Sstevel@tonic-gate# Parameters:
2440*0Sstevel@tonic-gate#   $name -> Name of the hidden field
2441*0Sstevel@tonic-gate#   @default -> (optional) Initial values of field (may be an array)
2442*0Sstevel@tonic-gate#      or
2443*0Sstevel@tonic-gate#   $default->[initial values of field]
2444*0Sstevel@tonic-gate# Returns:
2445*0Sstevel@tonic-gate#   A string containing a <input type="hidden" name="name" value="value">
2446*0Sstevel@tonic-gate####
2447*0Sstevel@tonic-gate'hidden' => <<'END_OF_FUNC',
2448*0Sstevel@tonic-gatesub hidden {
2449*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2450*0Sstevel@tonic-gate
2451*0Sstevel@tonic-gate    # this is the one place where we departed from our standard
2452*0Sstevel@tonic-gate    # calling scheme, so we have to special-case (darn)
2453*0Sstevel@tonic-gate    my(@result,@value);
2454*0Sstevel@tonic-gate    my($name,$default,$override,@other) =
2455*0Sstevel@tonic-gate	rearrange([NAME,[DEFAULT,VALUE,VALUES],[OVERRIDE,FORCE]],@p);
2456*0Sstevel@tonic-gate
2457*0Sstevel@tonic-gate    my $do_override = 0;
2458*0Sstevel@tonic-gate    if ( ref($p[0]) || substr($p[0],0,1) eq '-') {
2459*0Sstevel@tonic-gate	@value = ref($default) ? @{$default} : $default;
2460*0Sstevel@tonic-gate	$do_override = $override;
2461*0Sstevel@tonic-gate    } else {
2462*0Sstevel@tonic-gate	foreach ($default,$override,@other) {
2463*0Sstevel@tonic-gate	    push(@value,$_) if defined($_);
2464*0Sstevel@tonic-gate	}
2465*0Sstevel@tonic-gate    }
2466*0Sstevel@tonic-gate
2467*0Sstevel@tonic-gate    # use previous values if override is not set
2468*0Sstevel@tonic-gate    my @prev = $self->param($name);
2469*0Sstevel@tonic-gate    @value = @prev if !$do_override && @prev;
2470*0Sstevel@tonic-gate
2471*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2472*0Sstevel@tonic-gate    foreach (@value) {
2473*0Sstevel@tonic-gate	$_ = defined($_) ? $self->escapeHTML($_,1) : '';
2474*0Sstevel@tonic-gate	push @result,$XHTML ? qq(<input type="hidden" name="$name" value="$_" />)
2475*0Sstevel@tonic-gate                            : qq(<input type="hidden" name="$name" value="$_">);
2476*0Sstevel@tonic-gate    }
2477*0Sstevel@tonic-gate    return wantarray ? @result : join('',@result);
2478*0Sstevel@tonic-gate}
2479*0Sstevel@tonic-gateEND_OF_FUNC
2480*0Sstevel@tonic-gate
2481*0Sstevel@tonic-gate
2482*0Sstevel@tonic-gate#### Method: image_button
2483*0Sstevel@tonic-gate# Parameters:
2484*0Sstevel@tonic-gate#   $name -> Name of the button
2485*0Sstevel@tonic-gate#   $src ->  URL of the image source
2486*0Sstevel@tonic-gate#   $align -> Alignment style (TOP, BOTTOM or MIDDLE)
2487*0Sstevel@tonic-gate# Returns:
2488*0Sstevel@tonic-gate#   A string containing a <input type="image" name="name" src="url" align="alignment">
2489*0Sstevel@tonic-gate####
2490*0Sstevel@tonic-gate'image_button' => <<'END_OF_FUNC',
2491*0Sstevel@tonic-gatesub image_button {
2492*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2493*0Sstevel@tonic-gate
2494*0Sstevel@tonic-gate    my($name,$src,$alignment,@other) =
2495*0Sstevel@tonic-gate	rearrange([NAME,SRC,ALIGN],@p);
2496*0Sstevel@tonic-gate
2497*0Sstevel@tonic-gate    my($align) = $alignment ? " align=\U\"$alignment\"" : '';
2498*0Sstevel@tonic-gate    my($other) = @other ? " @other" : '';
2499*0Sstevel@tonic-gate    $name=$self->escapeHTML($name);
2500*0Sstevel@tonic-gate    return $XHTML ? qq(<input type="image" name="$name" src="$src"$align$other />)
2501*0Sstevel@tonic-gate                  : qq/<input type="image" name="$name" src="$src"$align$other>/;
2502*0Sstevel@tonic-gate}
2503*0Sstevel@tonic-gateEND_OF_FUNC
2504*0Sstevel@tonic-gate
2505*0Sstevel@tonic-gate
2506*0Sstevel@tonic-gate#### Method: self_url
2507*0Sstevel@tonic-gate# Returns a URL containing the current script and all its
2508*0Sstevel@tonic-gate# param/value pairs arranged as a query.  You can use this
2509*0Sstevel@tonic-gate# to create a link that, when selected, will reinvoke the
2510*0Sstevel@tonic-gate# script with all its state information preserved.
2511*0Sstevel@tonic-gate####
2512*0Sstevel@tonic-gate'self_url' => <<'END_OF_FUNC',
2513*0Sstevel@tonic-gatesub self_url {
2514*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2515*0Sstevel@tonic-gate    return $self->url('-path_info'=>1,'-query'=>1,'-full'=>1,@p);
2516*0Sstevel@tonic-gate}
2517*0Sstevel@tonic-gateEND_OF_FUNC
2518*0Sstevel@tonic-gate
2519*0Sstevel@tonic-gate
2520*0Sstevel@tonic-gate# This is provided as a synonym to self_url() for people unfortunate
2521*0Sstevel@tonic-gate# enough to have incorporated it into their programs already!
2522*0Sstevel@tonic-gate'state' => <<'END_OF_FUNC',
2523*0Sstevel@tonic-gatesub state {
2524*0Sstevel@tonic-gate    &self_url;
2525*0Sstevel@tonic-gate}
2526*0Sstevel@tonic-gateEND_OF_FUNC
2527*0Sstevel@tonic-gate
2528*0Sstevel@tonic-gate
2529*0Sstevel@tonic-gate#### Method: url
2530*0Sstevel@tonic-gate# Like self_url, but doesn't return the query string part of
2531*0Sstevel@tonic-gate# the URL.
2532*0Sstevel@tonic-gate####
2533*0Sstevel@tonic-gate'url' => <<'END_OF_FUNC',
2534*0Sstevel@tonic-gatesub url {
2535*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2536*0Sstevel@tonic-gate    my ($relative,$absolute,$full,$path_info,$query,$base) =
2537*0Sstevel@tonic-gate	rearrange(['RELATIVE','ABSOLUTE','FULL',['PATH','PATH_INFO'],['QUERY','QUERY_STRING'],'BASE'],@p);
2538*0Sstevel@tonic-gate    my $url;
2539*0Sstevel@tonic-gate    $full++      if $base || !($relative || $absolute);
2540*0Sstevel@tonic-gate
2541*0Sstevel@tonic-gate    my $path = $self->path_info;
2542*0Sstevel@tonic-gate    my $script_name = $self->script_name;
2543*0Sstevel@tonic-gate
2544*0Sstevel@tonic-gate    # for compatibility with Apache's MultiViews
2545*0Sstevel@tonic-gate    if (exists($ENV{REQUEST_URI})) {
2546*0Sstevel@tonic-gate        my $index;
2547*0Sstevel@tonic-gate	$script_name = unescape($ENV{REQUEST_URI});
2548*0Sstevel@tonic-gate        $script_name =~ s/\?.+$//;   # strip query string
2549*0Sstevel@tonic-gate        # and path
2550*0Sstevel@tonic-gate        if (exists($ENV{PATH_INFO})) {
2551*0Sstevel@tonic-gate           my $encoded_path = unescape($ENV{PATH_INFO});
2552*0Sstevel@tonic-gate           $script_name      =~ s/\Q$encoded_path\E$//i;
2553*0Sstevel@tonic-gate         }
2554*0Sstevel@tonic-gate    }
2555*0Sstevel@tonic-gate
2556*0Sstevel@tonic-gate    if ($full) {
2557*0Sstevel@tonic-gate	my $protocol = $self->protocol();
2558*0Sstevel@tonic-gate	$url = "$protocol://";
2559*0Sstevel@tonic-gate	my $vh = http('host');
2560*0Sstevel@tonic-gate	if ($vh) {
2561*0Sstevel@tonic-gate	    $url .= $vh;
2562*0Sstevel@tonic-gate	} else {
2563*0Sstevel@tonic-gate	    $url .= server_name();
2564*0Sstevel@tonic-gate	    my $port = $self->server_port;
2565*0Sstevel@tonic-gate	    $url .= ":" . $port
2566*0Sstevel@tonic-gate		unless (lc($protocol) eq 'http'  && $port == 80)
2567*0Sstevel@tonic-gate		    || (lc($protocol) eq 'https' && $port == 443);
2568*0Sstevel@tonic-gate	}
2569*0Sstevel@tonic-gate        return $url if $base;
2570*0Sstevel@tonic-gate	$url .= $script_name;
2571*0Sstevel@tonic-gate    } elsif ($relative) {
2572*0Sstevel@tonic-gate	($url) = $script_name =~ m!([^/]+)$!;
2573*0Sstevel@tonic-gate    } elsif ($absolute) {
2574*0Sstevel@tonic-gate	$url = $script_name;
2575*0Sstevel@tonic-gate    }
2576*0Sstevel@tonic-gate
2577*0Sstevel@tonic-gate    $url .= $path if $path_info and defined $path;
2578*0Sstevel@tonic-gate    $url .= "?" . $self->query_string if $query and $self->query_string;
2579*0Sstevel@tonic-gate    $url = '' unless defined $url;
2580*0Sstevel@tonic-gate    $url =~ s/([^a-zA-Z0-9_.%;&?\/\\:+=~-])/sprintf("%%%02X",ord($1))/eg;
2581*0Sstevel@tonic-gate    return $url;
2582*0Sstevel@tonic-gate}
2583*0Sstevel@tonic-gate
2584*0Sstevel@tonic-gateEND_OF_FUNC
2585*0Sstevel@tonic-gate
2586*0Sstevel@tonic-gate#### Method: cookie
2587*0Sstevel@tonic-gate# Set or read a cookie from the specified name.
2588*0Sstevel@tonic-gate# Cookie can then be passed to header().
2589*0Sstevel@tonic-gate# Usual rules apply to the stickiness of -value.
2590*0Sstevel@tonic-gate#  Parameters:
2591*0Sstevel@tonic-gate#   -name -> name for this cookie (optional)
2592*0Sstevel@tonic-gate#   -value -> value of this cookie (scalar, array or hash)
2593*0Sstevel@tonic-gate#   -path -> paths for which this cookie is valid (optional)
2594*0Sstevel@tonic-gate#   -domain -> internet domain in which this cookie is valid (optional)
2595*0Sstevel@tonic-gate#   -secure -> if true, cookie only passed through secure channel (optional)
2596*0Sstevel@tonic-gate#   -expires -> expiry date in format Wdy, DD-Mon-YYYY HH:MM:SS GMT (optional)
2597*0Sstevel@tonic-gate####
2598*0Sstevel@tonic-gate'cookie' => <<'END_OF_FUNC',
2599*0Sstevel@tonic-gatesub cookie {
2600*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2601*0Sstevel@tonic-gate    my($name,$value,$path,$domain,$secure,$expires) =
2602*0Sstevel@tonic-gate	rearrange([NAME,[VALUE,VALUES],PATH,DOMAIN,SECURE,EXPIRES],@p);
2603*0Sstevel@tonic-gate
2604*0Sstevel@tonic-gate    require CGI::Cookie;
2605*0Sstevel@tonic-gate
2606*0Sstevel@tonic-gate    # if no value is supplied, then we retrieve the
2607*0Sstevel@tonic-gate    # value of the cookie, if any.  For efficiency, we cache the parsed
2608*0Sstevel@tonic-gate    # cookies in our state variables.
2609*0Sstevel@tonic-gate    unless ( defined($value) ) {
2610*0Sstevel@tonic-gate	$self->{'.cookies'} = CGI::Cookie->fetch
2611*0Sstevel@tonic-gate	    unless $self->{'.cookies'};
2612*0Sstevel@tonic-gate
2613*0Sstevel@tonic-gate	# If no name is supplied, then retrieve the names of all our cookies.
2614*0Sstevel@tonic-gate	return () unless $self->{'.cookies'};
2615*0Sstevel@tonic-gate	return keys %{$self->{'.cookies'}} unless $name;
2616*0Sstevel@tonic-gate	return () unless $self->{'.cookies'}->{$name};
2617*0Sstevel@tonic-gate	return $self->{'.cookies'}->{$name}->value if defined($name) && $name ne '';
2618*0Sstevel@tonic-gate    }
2619*0Sstevel@tonic-gate
2620*0Sstevel@tonic-gate    # If we get here, we're creating a new cookie
2621*0Sstevel@tonic-gate    return undef unless defined($name) && $name ne '';	# this is an error
2622*0Sstevel@tonic-gate
2623*0Sstevel@tonic-gate    my @param;
2624*0Sstevel@tonic-gate    push(@param,'-name'=>$name);
2625*0Sstevel@tonic-gate    push(@param,'-value'=>$value);
2626*0Sstevel@tonic-gate    push(@param,'-domain'=>$domain) if $domain;
2627*0Sstevel@tonic-gate    push(@param,'-path'=>$path) if $path;
2628*0Sstevel@tonic-gate    push(@param,'-expires'=>$expires) if $expires;
2629*0Sstevel@tonic-gate    push(@param,'-secure'=>$secure) if $secure;
2630*0Sstevel@tonic-gate
2631*0Sstevel@tonic-gate    return new CGI::Cookie(@param);
2632*0Sstevel@tonic-gate}
2633*0Sstevel@tonic-gateEND_OF_FUNC
2634*0Sstevel@tonic-gate
2635*0Sstevel@tonic-gate'parse_keywordlist' => <<'END_OF_FUNC',
2636*0Sstevel@tonic-gatesub parse_keywordlist {
2637*0Sstevel@tonic-gate    my($self,$tosplit) = @_;
2638*0Sstevel@tonic-gate    $tosplit = unescape($tosplit); # unescape the keywords
2639*0Sstevel@tonic-gate    $tosplit=~tr/+/ /;          # pluses to spaces
2640*0Sstevel@tonic-gate    my(@keywords) = split(/\s+/,$tosplit);
2641*0Sstevel@tonic-gate    return @keywords;
2642*0Sstevel@tonic-gate}
2643*0Sstevel@tonic-gateEND_OF_FUNC
2644*0Sstevel@tonic-gate
2645*0Sstevel@tonic-gate'param_fetch' => <<'END_OF_FUNC',
2646*0Sstevel@tonic-gatesub param_fetch {
2647*0Sstevel@tonic-gate    my($self,@p) = self_or_default(@_);
2648*0Sstevel@tonic-gate    my($name) = rearrange([NAME],@p);
2649*0Sstevel@tonic-gate    unless (exists($self->{$name})) {
2650*0Sstevel@tonic-gate	$self->add_parameter($name);
2651*0Sstevel@tonic-gate	$self->{$name} = [];
2652*0Sstevel@tonic-gate    }
2653*0Sstevel@tonic-gate
2654*0Sstevel@tonic-gate    return $self->{$name};
2655*0Sstevel@tonic-gate}
2656*0Sstevel@tonic-gateEND_OF_FUNC
2657*0Sstevel@tonic-gate
2658*0Sstevel@tonic-gate###############################################
2659*0Sstevel@tonic-gate# OTHER INFORMATION PROVIDED BY THE ENVIRONMENT
2660*0Sstevel@tonic-gate###############################################
2661*0Sstevel@tonic-gate
2662*0Sstevel@tonic-gate#### Method: path_info
2663*0Sstevel@tonic-gate# Return the extra virtual path information provided
2664*0Sstevel@tonic-gate# after the URL (if any)
2665*0Sstevel@tonic-gate####
2666*0Sstevel@tonic-gate'path_info' => <<'END_OF_FUNC',
2667*0Sstevel@tonic-gatesub path_info {
2668*0Sstevel@tonic-gate    my ($self,$info) = self_or_default(@_);
2669*0Sstevel@tonic-gate    if (defined($info)) {
2670*0Sstevel@tonic-gate	$info = "/$info" if $info ne '' &&  substr($info,0,1) ne '/';
2671*0Sstevel@tonic-gate	$self->{'.path_info'} = $info;
2672*0Sstevel@tonic-gate    } elsif (! defined($self->{'.path_info'}) ) {
2673*0Sstevel@tonic-gate	$self->{'.path_info'} = defined($ENV{'PATH_INFO'}) ?
2674*0Sstevel@tonic-gate	    $ENV{'PATH_INFO'} : '';
2675*0Sstevel@tonic-gate
2676*0Sstevel@tonic-gate	# hack to fix broken path info in IIS
2677*0Sstevel@tonic-gate	$self->{'.path_info'} =~ s/^\Q$ENV{'SCRIPT_NAME'}\E// if $IIS;
2678*0Sstevel@tonic-gate
2679*0Sstevel@tonic-gate    }
2680*0Sstevel@tonic-gate    return $self->{'.path_info'};
2681*0Sstevel@tonic-gate}
2682*0Sstevel@tonic-gateEND_OF_FUNC
2683*0Sstevel@tonic-gate
2684*0Sstevel@tonic-gate
2685*0Sstevel@tonic-gate#### Method: request_method
2686*0Sstevel@tonic-gate# Returns 'POST', 'GET', 'PUT' or 'HEAD'
2687*0Sstevel@tonic-gate####
2688*0Sstevel@tonic-gate'request_method' => <<'END_OF_FUNC',
2689*0Sstevel@tonic-gatesub request_method {
2690*0Sstevel@tonic-gate    return $ENV{'REQUEST_METHOD'};
2691*0Sstevel@tonic-gate}
2692*0Sstevel@tonic-gateEND_OF_FUNC
2693*0Sstevel@tonic-gate
2694*0Sstevel@tonic-gate#### Method: content_type
2695*0Sstevel@tonic-gate# Returns the content_type string
2696*0Sstevel@tonic-gate####
2697*0Sstevel@tonic-gate'content_type' => <<'END_OF_FUNC',
2698*0Sstevel@tonic-gatesub content_type {
2699*0Sstevel@tonic-gate    return $ENV{'CONTENT_TYPE'};
2700*0Sstevel@tonic-gate}
2701*0Sstevel@tonic-gateEND_OF_FUNC
2702*0Sstevel@tonic-gate
2703*0Sstevel@tonic-gate#### Method: path_translated
2704*0Sstevel@tonic-gate# Return the physical path information provided
2705*0Sstevel@tonic-gate# by the URL (if any)
2706*0Sstevel@tonic-gate####
2707*0Sstevel@tonic-gate'path_translated' => <<'END_OF_FUNC',
2708*0Sstevel@tonic-gatesub path_translated {
2709*0Sstevel@tonic-gate    return $ENV{'PATH_TRANSLATED'};
2710*0Sstevel@tonic-gate}
2711*0Sstevel@tonic-gateEND_OF_FUNC
2712*0Sstevel@tonic-gate
2713*0Sstevel@tonic-gate
2714*0Sstevel@tonic-gate#### Method: query_string
2715*0Sstevel@tonic-gate# Synthesize a query string from our current
2716*0Sstevel@tonic-gate# parameters
2717*0Sstevel@tonic-gate####
2718*0Sstevel@tonic-gate'query_string' => <<'END_OF_FUNC',
2719*0Sstevel@tonic-gatesub query_string {
2720*0Sstevel@tonic-gate    my($self) = self_or_default(@_);
2721*0Sstevel@tonic-gate    my($param,$value,@pairs);
2722*0Sstevel@tonic-gate    foreach $param ($self->param) {
2723*0Sstevel@tonic-gate	my($eparam) = escape($param);
2724*0Sstevel@tonic-gate	foreach $value ($self->param($param)) {
2725*0Sstevel@tonic-gate	    $value = escape($value);
2726*0Sstevel@tonic-gate            next unless defined $value;
2727*0Sstevel@tonic-gate	    push(@pairs,"$eparam=$value");
2728*0Sstevel@tonic-gate	}
2729*0Sstevel@tonic-gate    }
2730*0Sstevel@tonic-gate    foreach (keys %{$self->{'.fieldnames'}}) {
2731*0Sstevel@tonic-gate      push(@pairs,".cgifields=".escape("$_"));
2732*0Sstevel@tonic-gate    }
2733*0Sstevel@tonic-gate    return join($USE_PARAM_SEMICOLONS ? ';' : '&',@pairs);
2734*0Sstevel@tonic-gate}
2735*0Sstevel@tonic-gateEND_OF_FUNC
2736*0Sstevel@tonic-gate
2737*0Sstevel@tonic-gate
2738*0Sstevel@tonic-gate#### Method: accept
2739*0Sstevel@tonic-gate# Without parameters, returns an array of the
2740*0Sstevel@tonic-gate# MIME types the browser accepts.
2741*0Sstevel@tonic-gate# With a single parameter equal to a MIME
2742*0Sstevel@tonic-gate# type, will return undef if the browser won't
2743*0Sstevel@tonic-gate# accept it, 1 if the browser accepts it but
2744*0Sstevel@tonic-gate# doesn't give a preference, or a floating point
2745*0Sstevel@tonic-gate# value between 0.0 and 1.0 if the browser
2746*0Sstevel@tonic-gate# declares a quantitative score for it.
2747*0Sstevel@tonic-gate# This handles MIME type globs correctly.
2748*0Sstevel@tonic-gate####
2749*0Sstevel@tonic-gate'Accept' => <<'END_OF_FUNC',
2750*0Sstevel@tonic-gatesub Accept {
2751*0Sstevel@tonic-gate    my($self,$search) = self_or_CGI(@_);
2752*0Sstevel@tonic-gate    my(%prefs,$type,$pref,$pat);
2753*0Sstevel@tonic-gate
2754*0Sstevel@tonic-gate    my(@accept) = split(',',$self->http('accept'));
2755*0Sstevel@tonic-gate
2756*0Sstevel@tonic-gate    foreach (@accept) {
2757*0Sstevel@tonic-gate	($pref) = /q=(\d\.\d+|\d+)/;
2758*0Sstevel@tonic-gate	($type) = m#(\S+/[^;]+)#;
2759*0Sstevel@tonic-gate	next unless $type;
2760*0Sstevel@tonic-gate	$prefs{$type}=$pref || 1;
2761*0Sstevel@tonic-gate    }
2762*0Sstevel@tonic-gate
2763*0Sstevel@tonic-gate    return keys %prefs unless $search;
2764*0Sstevel@tonic-gate
2765*0Sstevel@tonic-gate    # if a search type is provided, we may need to
2766*0Sstevel@tonic-gate    # perform a pattern matching operation.
2767*0Sstevel@tonic-gate    # The MIME types use a glob mechanism, which
2768*0Sstevel@tonic-gate    # is easily translated into a perl pattern match
2769*0Sstevel@tonic-gate
2770*0Sstevel@tonic-gate    # First return the preference for directly supported
2771*0Sstevel@tonic-gate    # types:
2772*0Sstevel@tonic-gate    return $prefs{$search} if $prefs{$search};
2773*0Sstevel@tonic-gate
2774*0Sstevel@tonic-gate    # Didn't get it, so try pattern matching.
2775*0Sstevel@tonic-gate    foreach (keys %prefs) {
2776*0Sstevel@tonic-gate	next unless /\*/;       # not a pattern match
2777*0Sstevel@tonic-gate	($pat = $_) =~ s/([^\w*])/\\$1/g; # escape meta characters
2778*0Sstevel@tonic-gate	$pat =~ s/\*/.*/g; # turn it into a pattern
2779*0Sstevel@tonic-gate	return $prefs{$_} if $search=~/$pat/;
2780*0Sstevel@tonic-gate    }
2781*0Sstevel@tonic-gate}
2782*0Sstevel@tonic-gateEND_OF_FUNC
2783*0Sstevel@tonic-gate
2784*0Sstevel@tonic-gate
2785*0Sstevel@tonic-gate#### Method: user_agent
2786*0Sstevel@tonic-gate# If called with no parameters, returns the user agent.
2787*0Sstevel@tonic-gate# If called with one parameter, does a pattern match (case
2788*0Sstevel@tonic-gate# insensitive) on the user agent.
2789*0Sstevel@tonic-gate####
2790*0Sstevel@tonic-gate'user_agent' => <<'END_OF_FUNC',
2791*0Sstevel@tonic-gatesub user_agent {
2792*0Sstevel@tonic-gate    my($self,$match)=self_or_CGI(@_);
2793*0Sstevel@tonic-gate    return $self->http('user_agent') unless $match;
2794*0Sstevel@tonic-gate    return $self->http('user_agent') =~ /$match/i;
2795*0Sstevel@tonic-gate}
2796*0Sstevel@tonic-gateEND_OF_FUNC
2797*0Sstevel@tonic-gate
2798*0Sstevel@tonic-gate
2799*0Sstevel@tonic-gate#### Method: raw_cookie
2800*0Sstevel@tonic-gate# Returns the magic cookies for the session.
2801*0Sstevel@tonic-gate# The cookies are not parsed or altered in any way, i.e.
2802*0Sstevel@tonic-gate# cookies are returned exactly as given in the HTTP
2803*0Sstevel@tonic-gate# headers.  If a cookie name is given, only that cookie's
2804*0Sstevel@tonic-gate# value is returned, otherwise the entire raw cookie
2805*0Sstevel@tonic-gate# is returned.
2806*0Sstevel@tonic-gate####
2807*0Sstevel@tonic-gate'raw_cookie' => <<'END_OF_FUNC',
2808*0Sstevel@tonic-gatesub raw_cookie {
2809*0Sstevel@tonic-gate    my($self,$key) = self_or_CGI(@_);
2810*0Sstevel@tonic-gate
2811*0Sstevel@tonic-gate    require CGI::Cookie;
2812*0Sstevel@tonic-gate
2813*0Sstevel@tonic-gate    if (defined($key)) {
2814*0Sstevel@tonic-gate	$self->{'.raw_cookies'} = CGI::Cookie->raw_fetch
2815*0Sstevel@tonic-gate	    unless $self->{'.raw_cookies'};
2816*0Sstevel@tonic-gate
2817*0Sstevel@tonic-gate	return () unless $self->{'.raw_cookies'};
2818*0Sstevel@tonic-gate	return () unless $self->{'.raw_cookies'}->{$key};
2819*0Sstevel@tonic-gate	return $self->{'.raw_cookies'}->{$key};
2820*0Sstevel@tonic-gate    }
2821*0Sstevel@tonic-gate    return $self->http('cookie') || $ENV{'COOKIE'} || '';
2822*0Sstevel@tonic-gate}
2823*0Sstevel@tonic-gateEND_OF_FUNC
2824*0Sstevel@tonic-gate
2825*0Sstevel@tonic-gate#### Method: virtual_host
2826*0Sstevel@tonic-gate# Return the name of the virtual_host, which
2827*0Sstevel@tonic-gate# is not always the same as the server
2828*0Sstevel@tonic-gate######
2829*0Sstevel@tonic-gate'virtual_host' => <<'END_OF_FUNC',
2830*0Sstevel@tonic-gatesub virtual_host {
2831*0Sstevel@tonic-gate    my $vh = http('host') || server_name();
2832*0Sstevel@tonic-gate    $vh =~ s/:\d+$//;		# get rid of port number
2833*0Sstevel@tonic-gate    return $vh;
2834*0Sstevel@tonic-gate}
2835*0Sstevel@tonic-gateEND_OF_FUNC
2836*0Sstevel@tonic-gate
2837*0Sstevel@tonic-gate#### Method: remote_host
2838*0Sstevel@tonic-gate# Return the name of the remote host, or its IP
2839*0Sstevel@tonic-gate# address if unavailable.  If this variable isn't
2840*0Sstevel@tonic-gate# defined, it returns "localhost" for debugging
2841*0Sstevel@tonic-gate# purposes.
2842*0Sstevel@tonic-gate####
2843*0Sstevel@tonic-gate'remote_host' => <<'END_OF_FUNC',
2844*0Sstevel@tonic-gatesub remote_host {
2845*0Sstevel@tonic-gate    return $ENV{'REMOTE_HOST'} || $ENV{'REMOTE_ADDR'}
2846*0Sstevel@tonic-gate    || 'localhost';
2847*0Sstevel@tonic-gate}
2848*0Sstevel@tonic-gateEND_OF_FUNC
2849*0Sstevel@tonic-gate
2850*0Sstevel@tonic-gate
2851*0Sstevel@tonic-gate#### Method: remote_addr
2852*0Sstevel@tonic-gate# Return the IP addr of the remote host.
2853*0Sstevel@tonic-gate####
2854*0Sstevel@tonic-gate'remote_addr' => <<'END_OF_FUNC',
2855*0Sstevel@tonic-gatesub remote_addr {
2856*0Sstevel@tonic-gate    return $ENV{'REMOTE_ADDR'} || '127.0.0.1';
2857*0Sstevel@tonic-gate}
2858*0Sstevel@tonic-gateEND_OF_FUNC
2859*0Sstevel@tonic-gate
2860*0Sstevel@tonic-gate
2861*0Sstevel@tonic-gate#### Method: script_name
2862*0Sstevel@tonic-gate# Return the partial URL to this script for
2863*0Sstevel@tonic-gate# self-referencing scripts.  Also see
2864*0Sstevel@tonic-gate# self_url(), which returns a URL with all state information
2865*0Sstevel@tonic-gate# preserved.
2866*0Sstevel@tonic-gate####
2867*0Sstevel@tonic-gate'script_name' => <<'END_OF_FUNC',
2868*0Sstevel@tonic-gatesub script_name {
2869*0Sstevel@tonic-gate    return $ENV{'SCRIPT_NAME'} if defined($ENV{'SCRIPT_NAME'});
2870*0Sstevel@tonic-gate    # These are for debugging
2871*0Sstevel@tonic-gate    return "/$0" unless $0=~/^\//;
2872*0Sstevel@tonic-gate    return $0;
2873*0Sstevel@tonic-gate}
2874*0Sstevel@tonic-gateEND_OF_FUNC
2875*0Sstevel@tonic-gate
2876*0Sstevel@tonic-gate
2877*0Sstevel@tonic-gate#### Method: referer
2878*0Sstevel@tonic-gate# Return the HTTP_REFERER: useful for generating
2879*0Sstevel@tonic-gate# a GO BACK button.
2880*0Sstevel@tonic-gate####
2881*0Sstevel@tonic-gate'referer' => <<'END_OF_FUNC',
2882*0Sstevel@tonic-gatesub referer {
2883*0Sstevel@tonic-gate    my($self) = self_or_CGI(@_);
2884*0Sstevel@tonic-gate    return $self->http('referer');
2885*0Sstevel@tonic-gate}
2886*0Sstevel@tonic-gateEND_OF_FUNC
2887*0Sstevel@tonic-gate
2888*0Sstevel@tonic-gate
2889*0Sstevel@tonic-gate#### Method: server_name
2890*0Sstevel@tonic-gate# Return the name of the server
2891*0Sstevel@tonic-gate####
2892*0Sstevel@tonic-gate'server_name' => <<'END_OF_FUNC',
2893*0Sstevel@tonic-gatesub server_name {
2894*0Sstevel@tonic-gate    return $ENV{'SERVER_NAME'} || 'localhost';
2895*0Sstevel@tonic-gate}
2896*0Sstevel@tonic-gateEND_OF_FUNC
2897*0Sstevel@tonic-gate
2898*0Sstevel@tonic-gate#### Method: server_software
2899*0Sstevel@tonic-gate# Return the name of the server software
2900*0Sstevel@tonic-gate####
2901*0Sstevel@tonic-gate'server_software' => <<'END_OF_FUNC',
2902*0Sstevel@tonic-gatesub server_software {
2903*0Sstevel@tonic-gate    return $ENV{'SERVER_SOFTWARE'} || 'cmdline';
2904*0Sstevel@tonic-gate}
2905*0Sstevel@tonic-gateEND_OF_FUNC
2906*0Sstevel@tonic-gate
2907*0Sstevel@tonic-gate#### Method: virtual_port
2908*0Sstevel@tonic-gate# Return the server port, taking virtual hosts into account
2909*0Sstevel@tonic-gate####
2910*0Sstevel@tonic-gate'virtual_port' => <<'END_OF_FUNC',
2911*0Sstevel@tonic-gatesub virtual_port {
2912*0Sstevel@tonic-gate    my($self) = self_or_default(@_);
2913*0Sstevel@tonic-gate    my $vh = $self->http('host');
2914*0Sstevel@tonic-gate    if ($vh) {
2915*0Sstevel@tonic-gate        return ($vh =~ /:(\d+)$/)[0] || '80';
2916*0Sstevel@tonic-gate    } else {
2917*0Sstevel@tonic-gate        return $self->server_port();
2918*0Sstevel@tonic-gate    }
2919*0Sstevel@tonic-gate}
2920*0Sstevel@tonic-gateEND_OF_FUNC
2921*0Sstevel@tonic-gate
2922*0Sstevel@tonic-gate#### Method: server_port
2923*0Sstevel@tonic-gate# Return the tcp/ip port the server is running on
2924*0Sstevel@tonic-gate####
2925*0Sstevel@tonic-gate'server_port' => <<'END_OF_FUNC',
2926*0Sstevel@tonic-gatesub server_port {
2927*0Sstevel@tonic-gate    return $ENV{'SERVER_PORT'} || 80; # for debugging
2928*0Sstevel@tonic-gate}
2929*0Sstevel@tonic-gateEND_OF_FUNC
2930*0Sstevel@tonic-gate
2931*0Sstevel@tonic-gate#### Method: server_protocol
2932*0Sstevel@tonic-gate# Return the protocol (usually HTTP/1.0)
2933*0Sstevel@tonic-gate####
2934*0Sstevel@tonic-gate'server_protocol' => <<'END_OF_FUNC',
2935*0Sstevel@tonic-gatesub server_protocol {
2936*0Sstevel@tonic-gate    return $ENV{'SERVER_PROTOCOL'} || 'HTTP/1.0'; # for debugging
2937*0Sstevel@tonic-gate}
2938*0Sstevel@tonic-gateEND_OF_FUNC
2939*0Sstevel@tonic-gate
2940*0Sstevel@tonic-gate#### Method: http
2941*0Sstevel@tonic-gate# Return the value of an HTTP variable, or
2942*0Sstevel@tonic-gate# the list of variables if none provided
2943*0Sstevel@tonic-gate####
2944*0Sstevel@tonic-gate'http' => <<'END_OF_FUNC',
2945*0Sstevel@tonic-gatesub http {
2946*0Sstevel@tonic-gate    my ($self,$parameter) = self_or_CGI(@_);
2947*0Sstevel@tonic-gate    return $ENV{$parameter} if $parameter=~/^HTTP/;
2948*0Sstevel@tonic-gate    $parameter =~ tr/-/_/;
2949*0Sstevel@tonic-gate    return $ENV{"HTTP_\U$parameter\E"} if $parameter;
2950*0Sstevel@tonic-gate    my(@p);
2951*0Sstevel@tonic-gate    foreach (keys %ENV) {
2952*0Sstevel@tonic-gate	push(@p,$_) if /^HTTP/;
2953*0Sstevel@tonic-gate    }
2954*0Sstevel@tonic-gate    return @p;
2955*0Sstevel@tonic-gate}
2956*0Sstevel@tonic-gateEND_OF_FUNC
2957*0Sstevel@tonic-gate
2958*0Sstevel@tonic-gate#### Method: https
2959*0Sstevel@tonic-gate# Return the value of HTTPS
2960*0Sstevel@tonic-gate####
2961*0Sstevel@tonic-gate'https' => <<'END_OF_FUNC',
2962*0Sstevel@tonic-gatesub https {
2963*0Sstevel@tonic-gate    local($^W)=0;
2964*0Sstevel@tonic-gate    my ($self,$parameter) = self_or_CGI(@_);
2965*0Sstevel@tonic-gate    return $ENV{HTTPS} unless $parameter;
2966*0Sstevel@tonic-gate    return $ENV{$parameter} if $parameter=~/^HTTPS/;
2967*0Sstevel@tonic-gate    $parameter =~ tr/-/_/;
2968*0Sstevel@tonic-gate    return $ENV{"HTTPS_\U$parameter\E"} if $parameter;
2969*0Sstevel@tonic-gate    my(@p);
2970*0Sstevel@tonic-gate    foreach (keys %ENV) {
2971*0Sstevel@tonic-gate	push(@p,$_) if /^HTTPS/;
2972*0Sstevel@tonic-gate    }
2973*0Sstevel@tonic-gate    return @p;
2974*0Sstevel@tonic-gate}
2975*0Sstevel@tonic-gateEND_OF_FUNC
2976*0Sstevel@tonic-gate
2977*0Sstevel@tonic-gate#### Method: protocol
2978*0Sstevel@tonic-gate# Return the protocol (http or https currently)
2979*0Sstevel@tonic-gate####
2980*0Sstevel@tonic-gate'protocol' => <<'END_OF_FUNC',
2981*0Sstevel@tonic-gatesub protocol {
2982*0Sstevel@tonic-gate    local($^W)=0;
2983*0Sstevel@tonic-gate    my $self = shift;
2984*0Sstevel@tonic-gate    return 'https' if uc($self->https()) eq 'ON';
2985*0Sstevel@tonic-gate    return 'https' if $self->server_port == 443;
2986*0Sstevel@tonic-gate    my $prot = $self->server_protocol;
2987*0Sstevel@tonic-gate    my($protocol,$version) = split('/',$prot);
2988*0Sstevel@tonic-gate    return "\L$protocol\E";
2989*0Sstevel@tonic-gate}
2990*0Sstevel@tonic-gateEND_OF_FUNC
2991*0Sstevel@tonic-gate
2992*0Sstevel@tonic-gate#### Method: remote_ident
2993*0Sstevel@tonic-gate# Return the identity of the remote user
2994*0Sstevel@tonic-gate# (but only if his host is running identd)
2995*0Sstevel@tonic-gate####
2996*0Sstevel@tonic-gate'remote_ident' => <<'END_OF_FUNC',
2997*0Sstevel@tonic-gatesub remote_ident {
2998*0Sstevel@tonic-gate    return $ENV{'REMOTE_IDENT'};
2999*0Sstevel@tonic-gate}
3000*0Sstevel@tonic-gateEND_OF_FUNC
3001*0Sstevel@tonic-gate
3002*0Sstevel@tonic-gate
3003*0Sstevel@tonic-gate#### Method: auth_type
3004*0Sstevel@tonic-gate# Return the type of use verification/authorization in use, if any.
3005*0Sstevel@tonic-gate####
3006*0Sstevel@tonic-gate'auth_type' => <<'END_OF_FUNC',
3007*0Sstevel@tonic-gatesub auth_type {
3008*0Sstevel@tonic-gate    return $ENV{'AUTH_TYPE'};
3009*0Sstevel@tonic-gate}
3010*0Sstevel@tonic-gateEND_OF_FUNC
3011*0Sstevel@tonic-gate
3012*0Sstevel@tonic-gate
3013*0Sstevel@tonic-gate#### Method: remote_user
3014*0Sstevel@tonic-gate# Return the authorization name used for user
3015*0Sstevel@tonic-gate# verification.
3016*0Sstevel@tonic-gate####
3017*0Sstevel@tonic-gate'remote_user' => <<'END_OF_FUNC',
3018*0Sstevel@tonic-gatesub remote_user {
3019*0Sstevel@tonic-gate    return $ENV{'REMOTE_USER'};
3020*0Sstevel@tonic-gate}
3021*0Sstevel@tonic-gateEND_OF_FUNC
3022*0Sstevel@tonic-gate
3023*0Sstevel@tonic-gate
3024*0Sstevel@tonic-gate#### Method: user_name
3025*0Sstevel@tonic-gate# Try to return the remote user's name by hook or by
3026*0Sstevel@tonic-gate# crook
3027*0Sstevel@tonic-gate####
3028*0Sstevel@tonic-gate'user_name' => <<'END_OF_FUNC',
3029*0Sstevel@tonic-gatesub user_name {
3030*0Sstevel@tonic-gate    my ($self) = self_or_CGI(@_);
3031*0Sstevel@tonic-gate    return $self->http('from') || $ENV{'REMOTE_IDENT'} || $ENV{'REMOTE_USER'};
3032*0Sstevel@tonic-gate}
3033*0Sstevel@tonic-gateEND_OF_FUNC
3034*0Sstevel@tonic-gate
3035*0Sstevel@tonic-gate#### Method: nosticky
3036*0Sstevel@tonic-gate# Set or return the NOSTICKY global flag
3037*0Sstevel@tonic-gate####
3038*0Sstevel@tonic-gate'nosticky' => <<'END_OF_FUNC',
3039*0Sstevel@tonic-gatesub nosticky {
3040*0Sstevel@tonic-gate    my ($self,$param) = self_or_CGI(@_);
3041*0Sstevel@tonic-gate    $CGI::NOSTICKY = $param if defined($param);
3042*0Sstevel@tonic-gate    return $CGI::NOSTICKY;
3043*0Sstevel@tonic-gate}
3044*0Sstevel@tonic-gateEND_OF_FUNC
3045*0Sstevel@tonic-gate
3046*0Sstevel@tonic-gate#### Method: nph
3047*0Sstevel@tonic-gate# Set or return the NPH global flag
3048*0Sstevel@tonic-gate####
3049*0Sstevel@tonic-gate'nph' => <<'END_OF_FUNC',
3050*0Sstevel@tonic-gatesub nph {
3051*0Sstevel@tonic-gate    my ($self,$param) = self_or_CGI(@_);
3052*0Sstevel@tonic-gate    $CGI::NPH = $param if defined($param);
3053*0Sstevel@tonic-gate    return $CGI::NPH;
3054*0Sstevel@tonic-gate}
3055*0Sstevel@tonic-gateEND_OF_FUNC
3056*0Sstevel@tonic-gate
3057*0Sstevel@tonic-gate#### Method: private_tempfiles
3058*0Sstevel@tonic-gate# Set or return the private_tempfiles global flag
3059*0Sstevel@tonic-gate####
3060*0Sstevel@tonic-gate'private_tempfiles' => <<'END_OF_FUNC',
3061*0Sstevel@tonic-gatesub private_tempfiles {
3062*0Sstevel@tonic-gate    my ($self,$param) = self_or_CGI(@_);
3063*0Sstevel@tonic-gate    $CGI::PRIVATE_TEMPFILES = $param if defined($param);
3064*0Sstevel@tonic-gate    return $CGI::PRIVATE_TEMPFILES;
3065*0Sstevel@tonic-gate}
3066*0Sstevel@tonic-gateEND_OF_FUNC
3067*0Sstevel@tonic-gate#### Method: close_upload_files
3068*0Sstevel@tonic-gate# Set or return the close_upload_files global flag
3069*0Sstevel@tonic-gate####
3070*0Sstevel@tonic-gate'close_upload_files' => <<'END_OF_FUNC',
3071*0Sstevel@tonic-gatesub close_upload_files {
3072*0Sstevel@tonic-gate    my ($self,$param) = self_or_CGI(@_);
3073*0Sstevel@tonic-gate    $CGI::CLOSE_UPLOAD_FILES = $param if defined($param);
3074*0Sstevel@tonic-gate    return $CGI::CLOSE_UPLOAD_FILES;
3075*0Sstevel@tonic-gate}
3076*0Sstevel@tonic-gateEND_OF_FUNC
3077*0Sstevel@tonic-gate
3078*0Sstevel@tonic-gate
3079*0Sstevel@tonic-gate#### Method: default_dtd
3080*0Sstevel@tonic-gate# Set or return the default_dtd global
3081*0Sstevel@tonic-gate####
3082*0Sstevel@tonic-gate'default_dtd' => <<'END_OF_FUNC',
3083*0Sstevel@tonic-gatesub default_dtd {
3084*0Sstevel@tonic-gate    my ($self,$param,$param2) = self_or_CGI(@_);
3085*0Sstevel@tonic-gate    if (defined $param2 && defined $param) {
3086*0Sstevel@tonic-gate        $CGI::DEFAULT_DTD = [ $param, $param2 ];
3087*0Sstevel@tonic-gate    } elsif (defined $param) {
3088*0Sstevel@tonic-gate        $CGI::DEFAULT_DTD = $param;
3089*0Sstevel@tonic-gate    }
3090*0Sstevel@tonic-gate    return $CGI::DEFAULT_DTD;
3091*0Sstevel@tonic-gate}
3092*0Sstevel@tonic-gateEND_OF_FUNC
3093*0Sstevel@tonic-gate
3094*0Sstevel@tonic-gate# -------------- really private subroutines -----------------
3095*0Sstevel@tonic-gate'previous_or_default' => <<'END_OF_FUNC',
3096*0Sstevel@tonic-gatesub previous_or_default {
3097*0Sstevel@tonic-gate    my($self,$name,$defaults,$override) = @_;
3098*0Sstevel@tonic-gate    my(%selected);
3099*0Sstevel@tonic-gate
3100*0Sstevel@tonic-gate    if (!$override && ($self->{'.fieldnames'}->{$name} ||
3101*0Sstevel@tonic-gate		       defined($self->param($name)) ) ) {
3102*0Sstevel@tonic-gate	grep($selected{$_}++,$self->param($name));
3103*0Sstevel@tonic-gate    } elsif (defined($defaults) && ref($defaults) &&
3104*0Sstevel@tonic-gate	     (ref($defaults) eq 'ARRAY')) {
3105*0Sstevel@tonic-gate	grep($selected{$_}++,@{$defaults});
3106*0Sstevel@tonic-gate    } else {
3107*0Sstevel@tonic-gate	$selected{$defaults}++ if defined($defaults);
3108*0Sstevel@tonic-gate    }
3109*0Sstevel@tonic-gate
3110*0Sstevel@tonic-gate    return %selected;
3111*0Sstevel@tonic-gate}
3112*0Sstevel@tonic-gateEND_OF_FUNC
3113*0Sstevel@tonic-gate
3114*0Sstevel@tonic-gate'register_parameter' => <<'END_OF_FUNC',
3115*0Sstevel@tonic-gatesub register_parameter {
3116*0Sstevel@tonic-gate    my($self,$param) = @_;
3117*0Sstevel@tonic-gate    $self->{'.parametersToAdd'}->{$param}++;
3118*0Sstevel@tonic-gate}
3119*0Sstevel@tonic-gateEND_OF_FUNC
3120*0Sstevel@tonic-gate
3121*0Sstevel@tonic-gate'get_fields' => <<'END_OF_FUNC',
3122*0Sstevel@tonic-gatesub get_fields {
3123*0Sstevel@tonic-gate    my($self) = @_;
3124*0Sstevel@tonic-gate    return $self->CGI::hidden('-name'=>'.cgifields',
3125*0Sstevel@tonic-gate			      '-values'=>[keys %{$self->{'.parametersToAdd'}}],
3126*0Sstevel@tonic-gate			      '-override'=>1);
3127*0Sstevel@tonic-gate}
3128*0Sstevel@tonic-gateEND_OF_FUNC
3129*0Sstevel@tonic-gate
3130*0Sstevel@tonic-gate'read_from_cmdline' => <<'END_OF_FUNC',
3131*0Sstevel@tonic-gatesub read_from_cmdline {
3132*0Sstevel@tonic-gate    my($input,@words);
3133*0Sstevel@tonic-gate    my($query_string);
3134*0Sstevel@tonic-gate    my($subpath);
3135*0Sstevel@tonic-gate    if ($DEBUG && @ARGV) {
3136*0Sstevel@tonic-gate	@words = @ARGV;
3137*0Sstevel@tonic-gate    } elsif ($DEBUG > 1) {
3138*0Sstevel@tonic-gate	require "shellwords.pl";
3139*0Sstevel@tonic-gate	print STDERR "(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)\n";
3140*0Sstevel@tonic-gate	chomp(@lines = <STDIN>); # remove newlines
3141*0Sstevel@tonic-gate	$input = join(" ",@lines);
3142*0Sstevel@tonic-gate	@words = &shellwords($input);
3143*0Sstevel@tonic-gate    }
3144*0Sstevel@tonic-gate    foreach (@words) {
3145*0Sstevel@tonic-gate	s/\\=/%3D/g;
3146*0Sstevel@tonic-gate	s/\\&/%26/g;
3147*0Sstevel@tonic-gate    }
3148*0Sstevel@tonic-gate
3149*0Sstevel@tonic-gate    if ("@words"=~/=/) {
3150*0Sstevel@tonic-gate	$query_string = join('&',@words);
3151*0Sstevel@tonic-gate    } else {
3152*0Sstevel@tonic-gate	$query_string = join('+',@words);
3153*0Sstevel@tonic-gate    }
3154*0Sstevel@tonic-gate    if ($query_string =~ /^(.*?)\?(.*)$/)
3155*0Sstevel@tonic-gate    {
3156*0Sstevel@tonic-gate        $query_string = $2;
3157*0Sstevel@tonic-gate        $subpath = $1;
3158*0Sstevel@tonic-gate    }
3159*0Sstevel@tonic-gate    return { 'query_string' => $query_string, 'subpath' => $subpath };
3160*0Sstevel@tonic-gate}
3161*0Sstevel@tonic-gateEND_OF_FUNC
3162*0Sstevel@tonic-gate
3163*0Sstevel@tonic-gate#####
3164*0Sstevel@tonic-gate# subroutine: read_multipart
3165*0Sstevel@tonic-gate#
3166*0Sstevel@tonic-gate# Read multipart data and store it into our parameters.
3167*0Sstevel@tonic-gate# An interesting feature is that if any of the parts is a file, we
3168*0Sstevel@tonic-gate# create a temporary file and open up a filehandle on it so that the
3169*0Sstevel@tonic-gate# caller can read from it if necessary.
3170*0Sstevel@tonic-gate#####
3171*0Sstevel@tonic-gate'read_multipart' => <<'END_OF_FUNC',
3172*0Sstevel@tonic-gatesub read_multipart {
3173*0Sstevel@tonic-gate    my($self,$boundary,$length) = @_;
3174*0Sstevel@tonic-gate    my($buffer) = $self->new_MultipartBuffer($boundary,$length);
3175*0Sstevel@tonic-gate    return unless $buffer;
3176*0Sstevel@tonic-gate    my(%header,$body);
3177*0Sstevel@tonic-gate    my $filenumber = 0;
3178*0Sstevel@tonic-gate    while (!$buffer->eof) {
3179*0Sstevel@tonic-gate	%header = $buffer->readHeader;
3180*0Sstevel@tonic-gate
3181*0Sstevel@tonic-gate	unless (%header) {
3182*0Sstevel@tonic-gate	    $self->cgi_error("400 Bad request (malformed multipart POST)");
3183*0Sstevel@tonic-gate	    return;
3184*0Sstevel@tonic-gate	}
3185*0Sstevel@tonic-gate
3186*0Sstevel@tonic-gate	my($param)= $header{'Content-Disposition'}=~/ name="?([^\";]*)"?/;
3187*0Sstevel@tonic-gate        $param .= $TAINTED;
3188*0Sstevel@tonic-gate
3189*0Sstevel@tonic-gate	# Bug:  Netscape doesn't escape quotation marks in file names!!!
3190*0Sstevel@tonic-gate	my($filename) = $header{'Content-Disposition'}=~/ filename="?([^\"]*)"?/;
3191*0Sstevel@tonic-gate	# Test for Opera's multiple upload feature
3192*0Sstevel@tonic-gate	my($multipart) = ( defined( $header{'Content-Type'} ) &&
3193*0Sstevel@tonic-gate		$header{'Content-Type'} =~ /multipart\/mixed/ ) ?
3194*0Sstevel@tonic-gate		1 : 0;
3195*0Sstevel@tonic-gate
3196*0Sstevel@tonic-gate	# add this parameter to our list
3197*0Sstevel@tonic-gate	$self->add_parameter($param);
3198*0Sstevel@tonic-gate
3199*0Sstevel@tonic-gate	# If no filename specified, then just read the data and assign it
3200*0Sstevel@tonic-gate	# to our parameter list.
3201*0Sstevel@tonic-gate	if ( ( !defined($filename) || $filename eq '' ) && !$multipart ) {
3202*0Sstevel@tonic-gate	    my($value) = $buffer->readBody;
3203*0Sstevel@tonic-gate            $value .= $TAINTED;
3204*0Sstevel@tonic-gate	    push(@{$self->{$param}},$value);
3205*0Sstevel@tonic-gate	    next;
3206*0Sstevel@tonic-gate	}
3207*0Sstevel@tonic-gate
3208*0Sstevel@tonic-gate	my ($tmpfile,$tmp,$filehandle);
3209*0Sstevel@tonic-gate      UPLOADS: {
3210*0Sstevel@tonic-gate	  # If we get here, then we are dealing with a potentially large
3211*0Sstevel@tonic-gate	  # uploaded form.  Save the data to a temporary file, then open
3212*0Sstevel@tonic-gate	  # the file for reading.
3213*0Sstevel@tonic-gate
3214*0Sstevel@tonic-gate	  # skip the file if uploads disabled
3215*0Sstevel@tonic-gate	  if ($DISABLE_UPLOADS) {
3216*0Sstevel@tonic-gate	      while (defined($data = $buffer->read)) { }
3217*0Sstevel@tonic-gate	      last UPLOADS;
3218*0Sstevel@tonic-gate	  }
3219*0Sstevel@tonic-gate
3220*0Sstevel@tonic-gate	  # set the filename to some recognizable value
3221*0Sstevel@tonic-gate          if ( ( !defined($filename) || $filename eq '' ) && $multipart ) {
3222*0Sstevel@tonic-gate              $filename = "multipart/mixed";
3223*0Sstevel@tonic-gate          }
3224*0Sstevel@tonic-gate
3225*0Sstevel@tonic-gate	  # choose a relatively unpredictable tmpfile sequence number
3226*0Sstevel@tonic-gate          my $seqno = unpack("%16C*",join('',localtime,values %ENV));
3227*0Sstevel@tonic-gate          for (my $cnt=10;$cnt>0;$cnt--) {
3228*0Sstevel@tonic-gate	    next unless $tmpfile = new CGITempFile($seqno);
3229*0Sstevel@tonic-gate	    $tmp = $tmpfile->as_string;
3230*0Sstevel@tonic-gate	    last if defined($filehandle = Fh->new($filename,$tmp,$PRIVATE_TEMPFILES));
3231*0Sstevel@tonic-gate            $seqno += int rand(100);
3232*0Sstevel@tonic-gate          }
3233*0Sstevel@tonic-gate          die "CGI open of tmpfile: $!\n" unless defined $filehandle;
3234*0Sstevel@tonic-gate	  $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode
3235*0Sstevel@tonic-gate                     && defined fileno($filehandle);
3236*0Sstevel@tonic-gate
3237*0Sstevel@tonic-gate	  # if this is an multipart/mixed attachment, save the header
3238*0Sstevel@tonic-gate	  # together with the body for later parsing with an external
3239*0Sstevel@tonic-gate	  # MIME parser module
3240*0Sstevel@tonic-gate	  if ( $multipart ) {
3241*0Sstevel@tonic-gate	      foreach ( keys %header ) {
3242*0Sstevel@tonic-gate		  print $filehandle "$_: $header{$_}${CRLF}";
3243*0Sstevel@tonic-gate	      }
3244*0Sstevel@tonic-gate	      print $filehandle "${CRLF}";
3245*0Sstevel@tonic-gate	  }
3246*0Sstevel@tonic-gate
3247*0Sstevel@tonic-gate	  my ($data);
3248*0Sstevel@tonic-gate	  local($\) = '';
3249*0Sstevel@tonic-gate          my $totalbytes;
3250*0Sstevel@tonic-gate          while (defined($data = $buffer->read)) {
3251*0Sstevel@tonic-gate              if (defined $self->{'.upload_hook'})
3252*0Sstevel@tonic-gate               {
3253*0Sstevel@tonic-gate                  $totalbytes += length($data);
3254*0Sstevel@tonic-gate                   &{$self->{'.upload_hook'}}($filename ,$data, $totalbytes, $self->{'.upload_data'});
3255*0Sstevel@tonic-gate              }
3256*0Sstevel@tonic-gate	      print $filehandle $data;
3257*0Sstevel@tonic-gate          }
3258*0Sstevel@tonic-gate
3259*0Sstevel@tonic-gate	  # back up to beginning of file
3260*0Sstevel@tonic-gate	  seek($filehandle,0,0);
3261*0Sstevel@tonic-gate
3262*0Sstevel@tonic-gate      ## Close the filehandle if requested this allows a multipart MIME
3263*0Sstevel@tonic-gate      ## upload to contain many files, and we won't die due to too many
3264*0Sstevel@tonic-gate      ## open file handles. The user can access the files using the hash
3265*0Sstevel@tonic-gate      ## below.
3266*0Sstevel@tonic-gate      close $filehandle if $CLOSE_UPLOAD_FILES;
3267*0Sstevel@tonic-gate	  $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode;
3268*0Sstevel@tonic-gate
3269*0Sstevel@tonic-gate	  # Save some information about the uploaded file where we can get
3270*0Sstevel@tonic-gate	  # at it later.
3271*0Sstevel@tonic-gate	  $self->{'.tmpfiles'}->{fileno($filehandle)}= {
3272*0Sstevel@tonic-gate              hndl => $filehandle,
3273*0Sstevel@tonic-gate	      name => $tmpfile,
3274*0Sstevel@tonic-gate	      info => {%header},
3275*0Sstevel@tonic-gate	  };
3276*0Sstevel@tonic-gate	  push(@{$self->{$param}},$filehandle);
3277*0Sstevel@tonic-gate      }
3278*0Sstevel@tonic-gate    }
3279*0Sstevel@tonic-gate}
3280*0Sstevel@tonic-gateEND_OF_FUNC
3281*0Sstevel@tonic-gate
3282*0Sstevel@tonic-gate'upload' =><<'END_OF_FUNC',
3283*0Sstevel@tonic-gatesub upload {
3284*0Sstevel@tonic-gate    my($self,$param_name) = self_or_default(@_);
3285*0Sstevel@tonic-gate    my @param = grep(ref && fileno($_), $self->param($param_name));
3286*0Sstevel@tonic-gate    return unless @param;
3287*0Sstevel@tonic-gate    return wantarray ? @param : $param[0];
3288*0Sstevel@tonic-gate}
3289*0Sstevel@tonic-gateEND_OF_FUNC
3290*0Sstevel@tonic-gate
3291*0Sstevel@tonic-gate'tmpFileName' => <<'END_OF_FUNC',
3292*0Sstevel@tonic-gatesub tmpFileName {
3293*0Sstevel@tonic-gate    my($self,$filename) = self_or_default(@_);
3294*0Sstevel@tonic-gate    return $self->{'.tmpfiles'}->{fileno($filename)}->{name} ?
3295*0Sstevel@tonic-gate	$self->{'.tmpfiles'}->{fileno($filename)}->{name}->as_string
3296*0Sstevel@tonic-gate	    : '';
3297*0Sstevel@tonic-gate}
3298*0Sstevel@tonic-gateEND_OF_FUNC
3299*0Sstevel@tonic-gate
3300*0Sstevel@tonic-gate'uploadInfo' => <<'END_OF_FUNC',
3301*0Sstevel@tonic-gatesub uploadInfo {
3302*0Sstevel@tonic-gate    my($self,$filename) = self_or_default(@_);
3303*0Sstevel@tonic-gate    return $self->{'.tmpfiles'}->{fileno($filename)}->{info};
3304*0Sstevel@tonic-gate}
3305*0Sstevel@tonic-gateEND_OF_FUNC
3306*0Sstevel@tonic-gate
3307*0Sstevel@tonic-gate# internal routine, don't use
3308*0Sstevel@tonic-gate'_set_values_and_labels' => <<'END_OF_FUNC',
3309*0Sstevel@tonic-gatesub _set_values_and_labels {
3310*0Sstevel@tonic-gate    my $self = shift;
3311*0Sstevel@tonic-gate    my ($v,$l,$n) = @_;
3312*0Sstevel@tonic-gate    $$l = $v if ref($v) eq 'HASH' && !ref($$l);
3313*0Sstevel@tonic-gate    return $self->param($n) if !defined($v);
3314*0Sstevel@tonic-gate    return $v if !ref($v);
3315*0Sstevel@tonic-gate    return ref($v) eq 'HASH' ? keys %$v : @$v;
3316*0Sstevel@tonic-gate}
3317*0Sstevel@tonic-gateEND_OF_FUNC
3318*0Sstevel@tonic-gate
3319*0Sstevel@tonic-gate# internal routine, don't use
3320*0Sstevel@tonic-gate'_set_attributes' => <<'END_OF_FUNC',
3321*0Sstevel@tonic-gatesub _set_attributes {
3322*0Sstevel@tonic-gate    my $self = shift;
3323*0Sstevel@tonic-gate    my($element, $attributes) = @_;
3324*0Sstevel@tonic-gate    return '' unless defined($attributes->{$element});
3325*0Sstevel@tonic-gate    $attribs = ' ';
3326*0Sstevel@tonic-gate    foreach my $attrib (keys %{$attributes->{$element}}) {
3327*0Sstevel@tonic-gate        $attrib =~ s/^-//;
3328*0Sstevel@tonic-gate        $attribs .= "@{[lc($attrib)]}=\"$attributes->{$element}{$attrib}\" ";
3329*0Sstevel@tonic-gate    }
3330*0Sstevel@tonic-gate    $attribs =~ s/ $//;
3331*0Sstevel@tonic-gate    return $attribs;
3332*0Sstevel@tonic-gate}
3333*0Sstevel@tonic-gateEND_OF_FUNC
3334*0Sstevel@tonic-gate
3335*0Sstevel@tonic-gate'_compile_all' => <<'END_OF_FUNC',
3336*0Sstevel@tonic-gatesub _compile_all {
3337*0Sstevel@tonic-gate    foreach (@_) {
3338*0Sstevel@tonic-gate	next if defined(&$_);
3339*0Sstevel@tonic-gate	$AUTOLOAD = "CGI::$_";
3340*0Sstevel@tonic-gate	_compile();
3341*0Sstevel@tonic-gate    }
3342*0Sstevel@tonic-gate}
3343*0Sstevel@tonic-gateEND_OF_FUNC
3344*0Sstevel@tonic-gate
3345*0Sstevel@tonic-gate);
3346*0Sstevel@tonic-gateEND_OF_AUTOLOAD
3347*0Sstevel@tonic-gate;
3348*0Sstevel@tonic-gate
3349*0Sstevel@tonic-gate#########################################################
3350*0Sstevel@tonic-gate# Globals and stubs for other packages that we use.
3351*0Sstevel@tonic-gate#########################################################
3352*0Sstevel@tonic-gate
3353*0Sstevel@tonic-gate################### Fh -- lightweight filehandle ###############
3354*0Sstevel@tonic-gatepackage Fh;
3355*0Sstevel@tonic-gateuse overload
3356*0Sstevel@tonic-gate    '""'  => \&asString,
3357*0Sstevel@tonic-gate    'cmp' => \&compare,
3358*0Sstevel@tonic-gate    'fallback'=>1;
3359*0Sstevel@tonic-gate
3360*0Sstevel@tonic-gate$FH='fh00000';
3361*0Sstevel@tonic-gate
3362*0Sstevel@tonic-gate*Fh::AUTOLOAD = \&CGI::AUTOLOAD;
3363*0Sstevel@tonic-gate
3364*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES = '';      # prevent -w error
3365*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
3366*0Sstevel@tonic-gate%SUBS =  (
3367*0Sstevel@tonic-gate'asString' => <<'END_OF_FUNC',
3368*0Sstevel@tonic-gatesub asString {
3369*0Sstevel@tonic-gate    my $self = shift;
3370*0Sstevel@tonic-gate    # get rid of package name
3371*0Sstevel@tonic-gate    (my $i = $$self) =~ s/^\*(\w+::fh\d{5})+//;
3372*0Sstevel@tonic-gate    $i =~ s/%(..)/ chr(hex($1)) /eg;
3373*0Sstevel@tonic-gate    return $i.$CGI::TAINTED;
3374*0Sstevel@tonic-gate# BEGIN DEAD CODE
3375*0Sstevel@tonic-gate# This was an extremely clever patch that allowed "use strict refs".
3376*0Sstevel@tonic-gate# Unfortunately it relied on another bug that caused leaky file descriptors.
3377*0Sstevel@tonic-gate# The underlying bug has been fixed, so this no longer works.  However
3378*0Sstevel@tonic-gate# "strict refs" still works for some reason.
3379*0Sstevel@tonic-gate#    my $self = shift;
3380*0Sstevel@tonic-gate#    return ${*{$self}{SCALAR}};
3381*0Sstevel@tonic-gate# END DEAD CODE
3382*0Sstevel@tonic-gate}
3383*0Sstevel@tonic-gateEND_OF_FUNC
3384*0Sstevel@tonic-gate
3385*0Sstevel@tonic-gate'compare' => <<'END_OF_FUNC',
3386*0Sstevel@tonic-gatesub compare {
3387*0Sstevel@tonic-gate    my $self = shift;
3388*0Sstevel@tonic-gate    my $value = shift;
3389*0Sstevel@tonic-gate    return "$self" cmp $value;
3390*0Sstevel@tonic-gate}
3391*0Sstevel@tonic-gateEND_OF_FUNC
3392*0Sstevel@tonic-gate
3393*0Sstevel@tonic-gate'new'  => <<'END_OF_FUNC',
3394*0Sstevel@tonic-gatesub new {
3395*0Sstevel@tonic-gate    my($pack,$name,$file,$delete) = @_;
3396*0Sstevel@tonic-gate    _setup_symbols(@SAVED_SYMBOLS) if @SAVED_SYMBOLS;
3397*0Sstevel@tonic-gate    require Fcntl unless defined &Fcntl::O_RDWR;
3398*0Sstevel@tonic-gate    (my $safename = $name) =~ s/([':%])/ sprintf '%%%02X', ord $1 /eg;
3399*0Sstevel@tonic-gate    my $fv = ++$FH . $safename;
3400*0Sstevel@tonic-gate    my $ref = \*{"Fh::$fv"};
3401*0Sstevel@tonic-gate    $file =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$! || return;
3402*0Sstevel@tonic-gate    my $safe = $1;
3403*0Sstevel@tonic-gate    sysopen($ref,$safe,Fcntl::O_RDWR()|Fcntl::O_CREAT()|Fcntl::O_EXCL(),0600) || return;
3404*0Sstevel@tonic-gate    unlink($safe) if $delete;
3405*0Sstevel@tonic-gate    CORE::delete $Fh::{$fv};
3406*0Sstevel@tonic-gate    return bless $ref,$pack;
3407*0Sstevel@tonic-gate}
3408*0Sstevel@tonic-gateEND_OF_FUNC
3409*0Sstevel@tonic-gate
3410*0Sstevel@tonic-gate'DESTROY'  => <<'END_OF_FUNC',
3411*0Sstevel@tonic-gatesub DESTROY {
3412*0Sstevel@tonic-gate    my $self = shift;
3413*0Sstevel@tonic-gate    close $self;
3414*0Sstevel@tonic-gate}
3415*0Sstevel@tonic-gateEND_OF_FUNC
3416*0Sstevel@tonic-gate
3417*0Sstevel@tonic-gate);
3418*0Sstevel@tonic-gateEND_OF_AUTOLOAD
3419*0Sstevel@tonic-gate
3420*0Sstevel@tonic-gate######################## MultipartBuffer ####################
3421*0Sstevel@tonic-gatepackage MultipartBuffer;
3422*0Sstevel@tonic-gate
3423*0Sstevel@tonic-gateuse constant DEBUG => 0;
3424*0Sstevel@tonic-gate
3425*0Sstevel@tonic-gate# how many bytes to read at a time.  We use
3426*0Sstevel@tonic-gate# a 4K buffer by default.
3427*0Sstevel@tonic-gate$INITIAL_FILLUNIT = 1024 * 4;
3428*0Sstevel@tonic-gate$TIMEOUT = 240*60;       # 4 hour timeout for big files
3429*0Sstevel@tonic-gate$SPIN_LOOP_MAX = 2000;  # bug fix for some Netscape servers
3430*0Sstevel@tonic-gate$CRLF=$CGI::CRLF;
3431*0Sstevel@tonic-gate
3432*0Sstevel@tonic-gate#reuse the autoload function
3433*0Sstevel@tonic-gate*MultipartBuffer::AUTOLOAD = \&CGI::AUTOLOAD;
3434*0Sstevel@tonic-gate
3435*0Sstevel@tonic-gate# avoid autoloader warnings
3436*0Sstevel@tonic-gatesub DESTROY {}
3437*0Sstevel@tonic-gate
3438*0Sstevel@tonic-gate###############################################################################
3439*0Sstevel@tonic-gate################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
3440*0Sstevel@tonic-gate###############################################################################
3441*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES = '';      # prevent -w error
3442*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
3443*0Sstevel@tonic-gate%SUBS =  (
3444*0Sstevel@tonic-gate
3445*0Sstevel@tonic-gate'new' => <<'END_OF_FUNC',
3446*0Sstevel@tonic-gatesub new {
3447*0Sstevel@tonic-gate    my($package,$interface,$boundary,$length) = @_;
3448*0Sstevel@tonic-gate    $FILLUNIT = $INITIAL_FILLUNIT;
3449*0Sstevel@tonic-gate    $CGI::DefaultClass->binmode($IN); # if $CGI::needs_binmode;  # just do it always
3450*0Sstevel@tonic-gate
3451*0Sstevel@tonic-gate    # If the user types garbage into the file upload field,
3452*0Sstevel@tonic-gate    # then Netscape passes NOTHING to the server (not good).
3453*0Sstevel@tonic-gate    # We may hang on this read in that case. So we implement
3454*0Sstevel@tonic-gate    # a read timeout.  If nothing is ready to read
3455*0Sstevel@tonic-gate    # by then, we return.
3456*0Sstevel@tonic-gate
3457*0Sstevel@tonic-gate    # Netscape seems to be a little bit unreliable
3458*0Sstevel@tonic-gate    # about providing boundary strings.
3459*0Sstevel@tonic-gate    my $boundary_read = 0;
3460*0Sstevel@tonic-gate    if ($boundary) {
3461*0Sstevel@tonic-gate
3462*0Sstevel@tonic-gate	# Under the MIME spec, the boundary consists of the
3463*0Sstevel@tonic-gate	# characters "--" PLUS the Boundary string
3464*0Sstevel@tonic-gate
3465*0Sstevel@tonic-gate	# BUG: IE 3.01 on the Macintosh uses just the boundary -- not
3466*0Sstevel@tonic-gate	# the two extra hyphens.  We do a special case here on the user-agent!!!!
3467*0Sstevel@tonic-gate	$boundary = "--$boundary" unless CGI::user_agent('MSIE\s+3\.0[12];\s*Mac|DreamPassport');
3468*0Sstevel@tonic-gate
3469*0Sstevel@tonic-gate    } else { # otherwise we find it ourselves
3470*0Sstevel@tonic-gate	my($old);
3471*0Sstevel@tonic-gate	($old,$/) = ($/,$CRLF); # read a CRLF-delimited line
3472*0Sstevel@tonic-gate	$boundary = <STDIN>;      # BUG: This won't work correctly under mod_perl
3473*0Sstevel@tonic-gate	$length -= length($boundary);
3474*0Sstevel@tonic-gate	chomp($boundary);               # remove the CRLF
3475*0Sstevel@tonic-gate	$/ = $old;                      # restore old line separator
3476*0Sstevel@tonic-gate        $boundary_read++;
3477*0Sstevel@tonic-gate    }
3478*0Sstevel@tonic-gate
3479*0Sstevel@tonic-gate    my $self = {LENGTH=>$length,
3480*0Sstevel@tonic-gate		BOUNDARY=>$boundary,
3481*0Sstevel@tonic-gate		INTERFACE=>$interface,
3482*0Sstevel@tonic-gate		BUFFER=>'',
3483*0Sstevel@tonic-gate	    };
3484*0Sstevel@tonic-gate
3485*0Sstevel@tonic-gate    $FILLUNIT = length($boundary)
3486*0Sstevel@tonic-gate	if length($boundary) > $FILLUNIT;
3487*0Sstevel@tonic-gate
3488*0Sstevel@tonic-gate    my $retval = bless $self,ref $package || $package;
3489*0Sstevel@tonic-gate
3490*0Sstevel@tonic-gate    # Read the preamble and the topmost (boundary) line plus the CRLF.
3491*0Sstevel@tonic-gate    unless ($boundary_read) {
3492*0Sstevel@tonic-gate      while ($self->read(0)) { }
3493*0Sstevel@tonic-gate    }
3494*0Sstevel@tonic-gate    die "Malformed multipart POST: data truncated\n" if $self->eof;
3495*0Sstevel@tonic-gate
3496*0Sstevel@tonic-gate    return $retval;
3497*0Sstevel@tonic-gate}
3498*0Sstevel@tonic-gateEND_OF_FUNC
3499*0Sstevel@tonic-gate
3500*0Sstevel@tonic-gate'readHeader' => <<'END_OF_FUNC',
3501*0Sstevel@tonic-gatesub readHeader {
3502*0Sstevel@tonic-gate    my($self) = @_;
3503*0Sstevel@tonic-gate    my($end);
3504*0Sstevel@tonic-gate    my($ok) = 0;
3505*0Sstevel@tonic-gate    my($bad) = 0;
3506*0Sstevel@tonic-gate
3507*0Sstevel@tonic-gate    local($CRLF) = "\015\012" if $CGI::OS eq 'VMS' || $CGI::EBCDIC;
3508*0Sstevel@tonic-gate
3509*0Sstevel@tonic-gate    do {
3510*0Sstevel@tonic-gate	$self->fillBuffer($FILLUNIT);
3511*0Sstevel@tonic-gate	$ok++ if ($end = index($self->{BUFFER},"${CRLF}${CRLF}")) >= 0;
3512*0Sstevel@tonic-gate	$ok++ if $self->{BUFFER} eq '';
3513*0Sstevel@tonic-gate	$bad++ if !$ok && $self->{LENGTH} <= 0;
3514*0Sstevel@tonic-gate	# this was a bad idea
3515*0Sstevel@tonic-gate	# $FILLUNIT *= 2 if length($self->{BUFFER}) >= $FILLUNIT;
3516*0Sstevel@tonic-gate    } until $ok || $bad;
3517*0Sstevel@tonic-gate    return () if $bad;
3518*0Sstevel@tonic-gate
3519*0Sstevel@tonic-gate    #EBCDIC NOTE: translate header into EBCDIC, but watch out for continuation lines!
3520*0Sstevel@tonic-gate
3521*0Sstevel@tonic-gate    my($header) = substr($self->{BUFFER},0,$end+2);
3522*0Sstevel@tonic-gate    substr($self->{BUFFER},0,$end+4) = '';
3523*0Sstevel@tonic-gate    my %return;
3524*0Sstevel@tonic-gate
3525*0Sstevel@tonic-gate    if ($CGI::EBCDIC) {
3526*0Sstevel@tonic-gate      warn "untranslated header=$header\n" if DEBUG;
3527*0Sstevel@tonic-gate      $header = CGI::Util::ascii2ebcdic($header);
3528*0Sstevel@tonic-gate      warn "translated header=$header\n" if DEBUG;
3529*0Sstevel@tonic-gate    }
3530*0Sstevel@tonic-gate
3531*0Sstevel@tonic-gate    # See RFC 2045 Appendix A and RFC 822 sections 3.4.8
3532*0Sstevel@tonic-gate    #   (Folding Long Header Fields), 3.4.3 (Comments)
3533*0Sstevel@tonic-gate    #   and 3.4.5 (Quoted-Strings).
3534*0Sstevel@tonic-gate
3535*0Sstevel@tonic-gate    my $token = '[-\w!\#$%&\'*+.^_\`|{}~]';
3536*0Sstevel@tonic-gate    $header=~s/$CRLF\s+/ /og;		# merge continuation lines
3537*0Sstevel@tonic-gate
3538*0Sstevel@tonic-gate    while ($header=~/($token+):\s+([^$CRLF]*)/mgox) {
3539*0Sstevel@tonic-gate        my ($field_name,$field_value) = ($1,$2);
3540*0Sstevel@tonic-gate	$field_name =~ s/\b(\w)/uc($1)/eg; #canonicalize
3541*0Sstevel@tonic-gate	$return{$field_name}=$field_value;
3542*0Sstevel@tonic-gate    }
3543*0Sstevel@tonic-gate    return %return;
3544*0Sstevel@tonic-gate}
3545*0Sstevel@tonic-gateEND_OF_FUNC
3546*0Sstevel@tonic-gate
3547*0Sstevel@tonic-gate# This reads and returns the body as a single scalar value.
3548*0Sstevel@tonic-gate'readBody' => <<'END_OF_FUNC',
3549*0Sstevel@tonic-gatesub readBody {
3550*0Sstevel@tonic-gate    my($self) = @_;
3551*0Sstevel@tonic-gate    my($data);
3552*0Sstevel@tonic-gate    my($returnval)='';
3553*0Sstevel@tonic-gate
3554*0Sstevel@tonic-gate    #EBCDIC NOTE: want to translate returnval into EBCDIC HERE
3555*0Sstevel@tonic-gate
3556*0Sstevel@tonic-gate    while (defined($data = $self->read)) {
3557*0Sstevel@tonic-gate	$returnval .= $data;
3558*0Sstevel@tonic-gate    }
3559*0Sstevel@tonic-gate
3560*0Sstevel@tonic-gate    if ($CGI::EBCDIC) {
3561*0Sstevel@tonic-gate      warn "untranslated body=$returnval\n" if DEBUG;
3562*0Sstevel@tonic-gate      $returnval = CGI::Util::ascii2ebcdic($returnval);
3563*0Sstevel@tonic-gate      warn "translated body=$returnval\n"   if DEBUG;
3564*0Sstevel@tonic-gate    }
3565*0Sstevel@tonic-gate    return $returnval;
3566*0Sstevel@tonic-gate}
3567*0Sstevel@tonic-gateEND_OF_FUNC
3568*0Sstevel@tonic-gate
3569*0Sstevel@tonic-gate# This will read $bytes or until the boundary is hit, whichever happens
3570*0Sstevel@tonic-gate# first.  After the boundary is hit, we return undef.  The next read will
3571*0Sstevel@tonic-gate# skip over the boundary and begin reading again;
3572*0Sstevel@tonic-gate'read' => <<'END_OF_FUNC',
3573*0Sstevel@tonic-gatesub read {
3574*0Sstevel@tonic-gate    my($self,$bytes) = @_;
3575*0Sstevel@tonic-gate
3576*0Sstevel@tonic-gate    # default number of bytes to read
3577*0Sstevel@tonic-gate    $bytes = $bytes || $FILLUNIT;
3578*0Sstevel@tonic-gate
3579*0Sstevel@tonic-gate    # Fill up our internal buffer in such a way that the boundary
3580*0Sstevel@tonic-gate    # is never split between reads.
3581*0Sstevel@tonic-gate    $self->fillBuffer($bytes);
3582*0Sstevel@tonic-gate
3583*0Sstevel@tonic-gate    my $boundary_start = $CGI::EBCDIC ? CGI::Util::ebcdic2ascii($self->{BOUNDARY})      : $self->{BOUNDARY};
3584*0Sstevel@tonic-gate    my $boundary_end   = $CGI::EBCDIC ? CGI::Util::ebcdic2ascii($self->{BOUNDARY}.'--') : $self->{BOUNDARY}.'--';
3585*0Sstevel@tonic-gate
3586*0Sstevel@tonic-gate    # Find the boundary in the buffer (it may not be there).
3587*0Sstevel@tonic-gate    my $start = index($self->{BUFFER},$boundary_start);
3588*0Sstevel@tonic-gate
3589*0Sstevel@tonic-gate    warn "boundary=$self->{BOUNDARY} length=$self->{LENGTH} start=$start\n" if DEBUG;
3590*0Sstevel@tonic-gate    # protect against malformed multipart POST operations
3591*0Sstevel@tonic-gate    die "Malformed multipart POST\n" unless ($start >= 0) || ($self->{LENGTH} > 0);
3592*0Sstevel@tonic-gate
3593*0Sstevel@tonic-gate
3594*0Sstevel@tonic-gate    #EBCDIC NOTE: want to translate boundary search into ASCII here.
3595*0Sstevel@tonic-gate
3596*0Sstevel@tonic-gate    # If the boundary begins the data, then skip past it
3597*0Sstevel@tonic-gate    # and return undef.
3598*0Sstevel@tonic-gate    if ($start == 0) {
3599*0Sstevel@tonic-gate
3600*0Sstevel@tonic-gate	# clear us out completely if we've hit the last boundary.
3601*0Sstevel@tonic-gate	if (index($self->{BUFFER},$boundary_end)==0) {
3602*0Sstevel@tonic-gate	    $self->{BUFFER}='';
3603*0Sstevel@tonic-gate	    $self->{LENGTH}=0;
3604*0Sstevel@tonic-gate	    return undef;
3605*0Sstevel@tonic-gate	}
3606*0Sstevel@tonic-gate
3607*0Sstevel@tonic-gate	# just remove the boundary.
3608*0Sstevel@tonic-gate	substr($self->{BUFFER},0,length($boundary_start))='';
3609*0Sstevel@tonic-gate        $self->{BUFFER} =~ s/^\012\015?//;
3610*0Sstevel@tonic-gate	return undef;
3611*0Sstevel@tonic-gate    }
3612*0Sstevel@tonic-gate
3613*0Sstevel@tonic-gate    my $bytesToReturn;
3614*0Sstevel@tonic-gate    if ($start > 0) {           # read up to the boundary
3615*0Sstevel@tonic-gate        $bytesToReturn = $start-2 > $bytes ? $bytes : $start;
3616*0Sstevel@tonic-gate    } else {    # read the requested number of bytes
3617*0Sstevel@tonic-gate	# leave enough bytes in the buffer to allow us to read
3618*0Sstevel@tonic-gate	# the boundary.  Thanks to Kevin Hendrick for finding
3619*0Sstevel@tonic-gate	# this one.
3620*0Sstevel@tonic-gate	$bytesToReturn = $bytes - (length($boundary_start)+1);
3621*0Sstevel@tonic-gate    }
3622*0Sstevel@tonic-gate
3623*0Sstevel@tonic-gate    my $returnval=substr($self->{BUFFER},0,$bytesToReturn);
3624*0Sstevel@tonic-gate    substr($self->{BUFFER},0,$bytesToReturn)='';
3625*0Sstevel@tonic-gate
3626*0Sstevel@tonic-gate    # If we hit the boundary, remove the CRLF from the end.
3627*0Sstevel@tonic-gate    return ($bytesToReturn==$start)
3628*0Sstevel@tonic-gate           ? substr($returnval,0,-2) : $returnval;
3629*0Sstevel@tonic-gate}
3630*0Sstevel@tonic-gateEND_OF_FUNC
3631*0Sstevel@tonic-gate
3632*0Sstevel@tonic-gate
3633*0Sstevel@tonic-gate# This fills up our internal buffer in such a way that the
3634*0Sstevel@tonic-gate# boundary is never split between reads
3635*0Sstevel@tonic-gate'fillBuffer' => <<'END_OF_FUNC',
3636*0Sstevel@tonic-gatesub fillBuffer {
3637*0Sstevel@tonic-gate    my($self,$bytes) = @_;
3638*0Sstevel@tonic-gate    return unless $self->{LENGTH};
3639*0Sstevel@tonic-gate
3640*0Sstevel@tonic-gate    my($boundaryLength) = length($self->{BOUNDARY});
3641*0Sstevel@tonic-gate    my($bufferLength) = length($self->{BUFFER});
3642*0Sstevel@tonic-gate    my($bytesToRead) = $bytes - $bufferLength + $boundaryLength + 2;
3643*0Sstevel@tonic-gate    $bytesToRead = $self->{LENGTH} if $self->{LENGTH} < $bytesToRead;
3644*0Sstevel@tonic-gate
3645*0Sstevel@tonic-gate    # Try to read some data.  We may hang here if the browser is screwed up.
3646*0Sstevel@tonic-gate    my $bytesRead = $self->{INTERFACE}->read_from_client(\$self->{BUFFER},
3647*0Sstevel@tonic-gate							 $bytesToRead,
3648*0Sstevel@tonic-gate							 $bufferLength);
3649*0Sstevel@tonic-gate    warn "bytesToRead=$bytesToRead, bufferLength=$bufferLength, buffer=$self->{BUFFER}\n" if DEBUG;
3650*0Sstevel@tonic-gate    $self->{BUFFER} = '' unless defined $self->{BUFFER};
3651*0Sstevel@tonic-gate
3652*0Sstevel@tonic-gate    # An apparent bug in the Apache server causes the read()
3653*0Sstevel@tonic-gate    # to return zero bytes repeatedly without blocking if the
3654*0Sstevel@tonic-gate    # remote user aborts during a file transfer.  I don't know how
3655*0Sstevel@tonic-gate    # they manage this, but the workaround is to abort if we get
3656*0Sstevel@tonic-gate    # more than SPIN_LOOP_MAX consecutive zero reads.
3657*0Sstevel@tonic-gate    if ($bytesRead == 0) {
3658*0Sstevel@tonic-gate	die  "CGI.pm: Server closed socket during multipart read (client aborted?).\n"
3659*0Sstevel@tonic-gate	    if ($self->{ZERO_LOOP_COUNTER}++ >= $SPIN_LOOP_MAX);
3660*0Sstevel@tonic-gate    } else {
3661*0Sstevel@tonic-gate	$self->{ZERO_LOOP_COUNTER}=0;
3662*0Sstevel@tonic-gate    }
3663*0Sstevel@tonic-gate
3664*0Sstevel@tonic-gate    $self->{LENGTH} -= $bytesRead;
3665*0Sstevel@tonic-gate}
3666*0Sstevel@tonic-gateEND_OF_FUNC
3667*0Sstevel@tonic-gate
3668*0Sstevel@tonic-gate
3669*0Sstevel@tonic-gate# Return true when we've finished reading
3670*0Sstevel@tonic-gate'eof' => <<'END_OF_FUNC'
3671*0Sstevel@tonic-gatesub eof {
3672*0Sstevel@tonic-gate    my($self) = @_;
3673*0Sstevel@tonic-gate    return 1 if (length($self->{BUFFER}) == 0)
3674*0Sstevel@tonic-gate		 && ($self->{LENGTH} <= 0);
3675*0Sstevel@tonic-gate    undef;
3676*0Sstevel@tonic-gate}
3677*0Sstevel@tonic-gateEND_OF_FUNC
3678*0Sstevel@tonic-gate
3679*0Sstevel@tonic-gate);
3680*0Sstevel@tonic-gateEND_OF_AUTOLOAD
3681*0Sstevel@tonic-gate
3682*0Sstevel@tonic-gate####################################################################################
3683*0Sstevel@tonic-gate################################## TEMPORARY FILES #################################
3684*0Sstevel@tonic-gate####################################################################################
3685*0Sstevel@tonic-gatepackage CGITempFile;
3686*0Sstevel@tonic-gate
3687*0Sstevel@tonic-gatesub find_tempdir {
3688*0Sstevel@tonic-gate  undef $TMPDIRECTORY;
3689*0Sstevel@tonic-gate  $SL = $CGI::SL;
3690*0Sstevel@tonic-gate  $MAC = $CGI::OS eq 'MACINTOSH';
3691*0Sstevel@tonic-gate  my ($vol) = $MAC ? MacPerl::Volumes() =~ /:(.*)/ : "";
3692*0Sstevel@tonic-gate  unless ($TMPDIRECTORY) {
3693*0Sstevel@tonic-gate    @TEMP=("${SL}usr${SL}tmp","${SL}var${SL}tmp",
3694*0Sstevel@tonic-gate	   "C:${SL}temp","${SL}tmp","${SL}temp",
3695*0Sstevel@tonic-gate	   "${vol}${SL}Temporary Items",
3696*0Sstevel@tonic-gate           "${SL}WWW_ROOT", "${SL}SYS\$SCRATCH",
3697*0Sstevel@tonic-gate	   "C:${SL}system${SL}temp");
3698*0Sstevel@tonic-gate    unshift(@TEMP,$ENV{'TMPDIR'}) if defined $ENV{'TMPDIR'};
3699*0Sstevel@tonic-gate
3700*0Sstevel@tonic-gate    # this feature was supposed to provide per-user tmpfiles, but
3701*0Sstevel@tonic-gate    # it is problematic.
3702*0Sstevel@tonic-gate    #    unshift(@TEMP,(getpwuid($<))[7].'/tmp') if $CGI::OS eq 'UNIX';
3703*0Sstevel@tonic-gate    # Rob: getpwuid() is unfortunately UNIX specific. On brain dead OS'es this
3704*0Sstevel@tonic-gate    #    : can generate a 'getpwuid() not implemented' exception, even though
3705*0Sstevel@tonic-gate    #    : it's never called.  Found under DOS/Win with the DJGPP perl port.
3706*0Sstevel@tonic-gate    #    : Refer to getpwuid() only at run-time if we're fortunate and have  UNIX.
3707*0Sstevel@tonic-gate    # unshift(@TEMP,(eval {(getpwuid($>))[7]}).'/tmp') if $CGI::OS eq 'UNIX' and $> != 0;
3708*0Sstevel@tonic-gate
3709*0Sstevel@tonic-gate    foreach (@TEMP) {
3710*0Sstevel@tonic-gate      do {$TMPDIRECTORY = $_; last} if -d $_ && -w _;
3711*0Sstevel@tonic-gate    }
3712*0Sstevel@tonic-gate  }
3713*0Sstevel@tonic-gate  $TMPDIRECTORY  = $MAC ? "" : "." unless $TMPDIRECTORY;
3714*0Sstevel@tonic-gate}
3715*0Sstevel@tonic-gate
3716*0Sstevel@tonic-gatefind_tempdir();
3717*0Sstevel@tonic-gate
3718*0Sstevel@tonic-gate$MAXTRIES = 5000;
3719*0Sstevel@tonic-gate
3720*0Sstevel@tonic-gate# cute feature, but overload implementation broke it
3721*0Sstevel@tonic-gate# %OVERLOAD = ('""'=>'as_string');
3722*0Sstevel@tonic-gate*CGITempFile::AUTOLOAD = \&CGI::AUTOLOAD;
3723*0Sstevel@tonic-gate
3724*0Sstevel@tonic-gatesub DESTROY {
3725*0Sstevel@tonic-gate    my($self) = @_;
3726*0Sstevel@tonic-gate    $$self =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$! || return;
3727*0Sstevel@tonic-gate    my $safe = $1;             # untaint operation
3728*0Sstevel@tonic-gate    unlink $safe;              # get rid of the file
3729*0Sstevel@tonic-gate}
3730*0Sstevel@tonic-gate
3731*0Sstevel@tonic-gate###############################################################################
3732*0Sstevel@tonic-gate################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
3733*0Sstevel@tonic-gate###############################################################################
3734*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES = '';      # prevent -w error
3735*0Sstevel@tonic-gate$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
3736*0Sstevel@tonic-gate%SUBS = (
3737*0Sstevel@tonic-gate
3738*0Sstevel@tonic-gate'new' => <<'END_OF_FUNC',
3739*0Sstevel@tonic-gatesub new {
3740*0Sstevel@tonic-gate    my($package,$sequence) = @_;
3741*0Sstevel@tonic-gate    my $filename;
3742*0Sstevel@tonic-gate    find_tempdir() unless -w $TMPDIRECTORY;
3743*0Sstevel@tonic-gate    for (my $i = 0; $i < $MAXTRIES; $i++) {
3744*0Sstevel@tonic-gate	last if ! -f ($filename = sprintf("${TMPDIRECTORY}${SL}CGItemp%d",$sequence++));
3745*0Sstevel@tonic-gate    }
3746*0Sstevel@tonic-gate    # check that it is a more-or-less valid filename
3747*0Sstevel@tonic-gate    return unless $filename =~ m!^([a-zA-Z0-9_ \'\":/.\$\\-]+)$!;
3748*0Sstevel@tonic-gate    # this used to untaint, now it doesn't
3749*0Sstevel@tonic-gate    # $filename = $1;
3750*0Sstevel@tonic-gate    return bless \$filename;
3751*0Sstevel@tonic-gate}
3752*0Sstevel@tonic-gateEND_OF_FUNC
3753*0Sstevel@tonic-gate
3754*0Sstevel@tonic-gate'as_string' => <<'END_OF_FUNC'
3755*0Sstevel@tonic-gatesub as_string {
3756*0Sstevel@tonic-gate    my($self) = @_;
3757*0Sstevel@tonic-gate    return $$self;
3758*0Sstevel@tonic-gate}
3759*0Sstevel@tonic-gateEND_OF_FUNC
3760*0Sstevel@tonic-gate
3761*0Sstevel@tonic-gate);
3762*0Sstevel@tonic-gateEND_OF_AUTOLOAD
3763*0Sstevel@tonic-gate
3764*0Sstevel@tonic-gatepackage CGI;
3765*0Sstevel@tonic-gate
3766*0Sstevel@tonic-gate# We get a whole bunch of warnings about "possibly uninitialized variables"
3767*0Sstevel@tonic-gate# when running with the -w switch.  Touch them all once to get rid of the
3768*0Sstevel@tonic-gate# warnings.  This is ugly and I hate it.
3769*0Sstevel@tonic-gateif ($^W) {
3770*0Sstevel@tonic-gate    $CGI::CGI = '';
3771*0Sstevel@tonic-gate    $CGI::CGI=<<EOF;
3772*0Sstevel@tonic-gate    $CGI::VERSION;
3773*0Sstevel@tonic-gate    $MultipartBuffer::SPIN_LOOP_MAX;
3774*0Sstevel@tonic-gate    $MultipartBuffer::CRLF;
3775*0Sstevel@tonic-gate    $MultipartBuffer::TIMEOUT;
3776*0Sstevel@tonic-gate    $MultipartBuffer::INITIAL_FILLUNIT;
3777*0Sstevel@tonic-gateEOF
3778*0Sstevel@tonic-gate    ;
3779*0Sstevel@tonic-gate}
3780*0Sstevel@tonic-gate
3781*0Sstevel@tonic-gate1;
3782*0Sstevel@tonic-gate
3783*0Sstevel@tonic-gate__END__
3784*0Sstevel@tonic-gate
3785*0Sstevel@tonic-gate=head1 NAME
3786*0Sstevel@tonic-gate
3787*0Sstevel@tonic-gateCGI - Simple Common Gateway Interface Class
3788*0Sstevel@tonic-gate
3789*0Sstevel@tonic-gate=head1 SYNOPSIS
3790*0Sstevel@tonic-gate
3791*0Sstevel@tonic-gate  # CGI script that creates a fill-out form
3792*0Sstevel@tonic-gate  # and echoes back its values.
3793*0Sstevel@tonic-gate
3794*0Sstevel@tonic-gate  use CGI qw/:standard/;
3795*0Sstevel@tonic-gate  print header,
3796*0Sstevel@tonic-gate        start_html('A Simple Example'),
3797*0Sstevel@tonic-gate        h1('A Simple Example'),
3798*0Sstevel@tonic-gate        start_form,
3799*0Sstevel@tonic-gate        "What's your name? ",textfield('name'),p,
3800*0Sstevel@tonic-gate        "What's the combination?", p,
3801*0Sstevel@tonic-gate        checkbox_group(-name=>'words',
3802*0Sstevel@tonic-gate		       -values=>['eenie','meenie','minie','moe'],
3803*0Sstevel@tonic-gate		       -defaults=>['eenie','minie']), p,
3804*0Sstevel@tonic-gate        "What's your favorite color? ",
3805*0Sstevel@tonic-gate        popup_menu(-name=>'color',
3806*0Sstevel@tonic-gate	           -values=>['red','green','blue','chartreuse']),p,
3807*0Sstevel@tonic-gate        submit,
3808*0Sstevel@tonic-gate        end_form,
3809*0Sstevel@tonic-gate        hr;
3810*0Sstevel@tonic-gate
3811*0Sstevel@tonic-gate   if (param()) {
3812*0Sstevel@tonic-gate       print "Your name is",em(param('name')),p,
3813*0Sstevel@tonic-gate	     "The keywords are: ",em(join(", ",param('words'))),p,
3814*0Sstevel@tonic-gate	     "Your favorite color is ",em(param('color')),
3815*0Sstevel@tonic-gate	     hr;
3816*0Sstevel@tonic-gate   }
3817*0Sstevel@tonic-gate
3818*0Sstevel@tonic-gate=head1 ABSTRACT
3819*0Sstevel@tonic-gate
3820*0Sstevel@tonic-gateThis perl library uses perl5 objects to make it easy to create Web
3821*0Sstevel@tonic-gatefill-out forms and parse their contents.  This package defines CGI
3822*0Sstevel@tonic-gateobjects, entities that contain the values of the current query string
3823*0Sstevel@tonic-gateand other state variables.  Using a CGI object's methods, you can
3824*0Sstevel@tonic-gateexamine keywords and parameters passed to your script, and create
3825*0Sstevel@tonic-gateforms whose initial values are taken from the current query (thereby
3826*0Sstevel@tonic-gatepreserving state information).  The module provides shortcut functions
3827*0Sstevel@tonic-gatethat produce boilerplate HTML, reducing typing and coding errors. It
3828*0Sstevel@tonic-gatealso provides functionality for some of the more advanced features of
3829*0Sstevel@tonic-gateCGI scripting, including support for file uploads, cookies, cascading
3830*0Sstevel@tonic-gatestyle sheets, server push, and frames.
3831*0Sstevel@tonic-gate
3832*0Sstevel@tonic-gateCGI.pm also provides a simple function-oriented programming style for
3833*0Sstevel@tonic-gatethose who don't need its object-oriented features.
3834*0Sstevel@tonic-gate
3835*0Sstevel@tonic-gateThe current version of CGI.pm is available at
3836*0Sstevel@tonic-gate
3837*0Sstevel@tonic-gate  http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html
3838*0Sstevel@tonic-gate  ftp://ftp-genome.wi.mit.edu/pub/software/WWW/
3839*0Sstevel@tonic-gate
3840*0Sstevel@tonic-gate=head1 DESCRIPTION
3841*0Sstevel@tonic-gate
3842*0Sstevel@tonic-gate=head2 PROGRAMMING STYLE
3843*0Sstevel@tonic-gate
3844*0Sstevel@tonic-gateThere are two styles of programming with CGI.pm, an object-oriented
3845*0Sstevel@tonic-gatestyle and a function-oriented style.  In the object-oriented style you
3846*0Sstevel@tonic-gatecreate one or more CGI objects and then use object methods to create
3847*0Sstevel@tonic-gatethe various elements of the page.  Each CGI object starts out with the
3848*0Sstevel@tonic-gatelist of named parameters that were passed to your CGI script by the
3849*0Sstevel@tonic-gateserver.  You can modify the objects, save them to a file or database
3850*0Sstevel@tonic-gateand recreate them.  Because each object corresponds to the "state" of
3851*0Sstevel@tonic-gatethe CGI script, and because each object's parameter list is
3852*0Sstevel@tonic-gateindependent of the others, this allows you to save the state of the
3853*0Sstevel@tonic-gatescript and restore it later.
3854*0Sstevel@tonic-gate
3855*0Sstevel@tonic-gateFor example, using the object oriented style, here is how you create
3856*0Sstevel@tonic-gatea simple "Hello World" HTML page:
3857*0Sstevel@tonic-gate
3858*0Sstevel@tonic-gate   #!/usr/local/bin/perl -w
3859*0Sstevel@tonic-gate   use CGI;                             # load CGI routines
3860*0Sstevel@tonic-gate   $q = new CGI;                        # create new CGI object
3861*0Sstevel@tonic-gate   print $q->header,                    # create the HTTP header
3862*0Sstevel@tonic-gate         $q->start_html('hello world'), # start the HTML
3863*0Sstevel@tonic-gate         $q->h1('hello world'),         # level 1 header
3864*0Sstevel@tonic-gate         $q->end_html;                  # end the HTML
3865*0Sstevel@tonic-gate
3866*0Sstevel@tonic-gateIn the function-oriented style, there is one default CGI object that
3867*0Sstevel@tonic-gateyou rarely deal with directly.  Instead you just call functions to
3868*0Sstevel@tonic-gateretrieve CGI parameters, create HTML tags, manage cookies, and so
3869*0Sstevel@tonic-gateon.  This provides you with a cleaner programming interface, but
3870*0Sstevel@tonic-gatelimits you to using one CGI object at a time.  The following example
3871*0Sstevel@tonic-gateprints the same page, but uses the function-oriented interface.
3872*0Sstevel@tonic-gateThe main differences are that we now need to import a set of functions
3873*0Sstevel@tonic-gateinto our name space (usually the "standard" functions), and we don't
3874*0Sstevel@tonic-gateneed to create the CGI object.
3875*0Sstevel@tonic-gate
3876*0Sstevel@tonic-gate   #!/usr/local/bin/perl
3877*0Sstevel@tonic-gate   use CGI qw/:standard/;           # load standard CGI routines
3878*0Sstevel@tonic-gate   print header,                    # create the HTTP header
3879*0Sstevel@tonic-gate         start_html('hello world'), # start the HTML
3880*0Sstevel@tonic-gate         h1('hello world'),         # level 1 header
3881*0Sstevel@tonic-gate         end_html;                  # end the HTML
3882*0Sstevel@tonic-gate
3883*0Sstevel@tonic-gateThe examples in this document mainly use the object-oriented style.
3884*0Sstevel@tonic-gateSee HOW TO IMPORT FUNCTIONS for important information on
3885*0Sstevel@tonic-gatefunction-oriented programming in CGI.pm
3886*0Sstevel@tonic-gate
3887*0Sstevel@tonic-gate=head2 CALLING CGI.PM ROUTINES
3888*0Sstevel@tonic-gate
3889*0Sstevel@tonic-gateMost CGI.pm routines accept several arguments, sometimes as many as 20
3890*0Sstevel@tonic-gateoptional ones!  To simplify this interface, all routines use a named
3891*0Sstevel@tonic-gateargument calling style that looks like this:
3892*0Sstevel@tonic-gate
3893*0Sstevel@tonic-gate   print $q->header(-type=>'image/gif',-expires=>'+3d');
3894*0Sstevel@tonic-gate
3895*0Sstevel@tonic-gateEach argument name is preceded by a dash.  Neither case nor order
3896*0Sstevel@tonic-gatematters in the argument list.  -type, -Type, and -TYPE are all
3897*0Sstevel@tonic-gateacceptable.  In fact, only the first argument needs to begin with a
3898*0Sstevel@tonic-gatedash.  If a dash is present in the first argument, CGI.pm assumes
3899*0Sstevel@tonic-gatedashes for the subsequent ones.
3900*0Sstevel@tonic-gate
3901*0Sstevel@tonic-gateSeveral routines are commonly called with just one argument.  In the
3902*0Sstevel@tonic-gatecase of these routines you can provide the single argument without an
3903*0Sstevel@tonic-gateargument name.  header() happens to be one of these routines.  In this
3904*0Sstevel@tonic-gatecase, the single argument is the document type.
3905*0Sstevel@tonic-gate
3906*0Sstevel@tonic-gate   print $q->header('text/html');
3907*0Sstevel@tonic-gate
3908*0Sstevel@tonic-gateOther such routines are documented below.
3909*0Sstevel@tonic-gate
3910*0Sstevel@tonic-gateSometimes named arguments expect a scalar, sometimes a reference to an
3911*0Sstevel@tonic-gatearray, and sometimes a reference to a hash.  Often, you can pass any
3912*0Sstevel@tonic-gatetype of argument and the routine will do whatever is most appropriate.
3913*0Sstevel@tonic-gateFor example, the param() routine is used to set a CGI parameter to a
3914*0Sstevel@tonic-gatesingle or a multi-valued value.  The two cases are shown below:
3915*0Sstevel@tonic-gate
3916*0Sstevel@tonic-gate   $q->param(-name=>'veggie',-value=>'tomato');
3917*0Sstevel@tonic-gate   $q->param(-name=>'veggie',-value=>['tomato','tomahto','potato','potahto']);
3918*0Sstevel@tonic-gate
3919*0Sstevel@tonic-gateA large number of routines in CGI.pm actually aren't specifically
3920*0Sstevel@tonic-gatedefined in the module, but are generated automatically as needed.
3921*0Sstevel@tonic-gateThese are the "HTML shortcuts," routines that generate HTML tags for
3922*0Sstevel@tonic-gateuse in dynamically-generated pages.  HTML tags have both attributes
3923*0Sstevel@tonic-gate(the attribute="value" pairs within the tag itself) and contents (the
3924*0Sstevel@tonic-gatepart between the opening and closing pairs.)  To distinguish between
3925*0Sstevel@tonic-gateattributes and contents, CGI.pm uses the convention of passing HTML
3926*0Sstevel@tonic-gateattributes as a hash reference as the first argument, and the
3927*0Sstevel@tonic-gatecontents, if any, as any subsequent arguments.  It works out like
3928*0Sstevel@tonic-gatethis:
3929*0Sstevel@tonic-gate
3930*0Sstevel@tonic-gate   Code                           Generated HTML
3931*0Sstevel@tonic-gate   ----                           --------------
3932*0Sstevel@tonic-gate   h1()                           <h1>
3933*0Sstevel@tonic-gate   h1('some','contents');         <h1>some contents</h1>
3934*0Sstevel@tonic-gate   h1({-align=>left});            <h1 align="LEFT">
3935*0Sstevel@tonic-gate   h1({-align=>left},'contents'); <h1 align="LEFT">contents</h1>
3936*0Sstevel@tonic-gate
3937*0Sstevel@tonic-gateHTML tags are described in more detail later.
3938*0Sstevel@tonic-gate
3939*0Sstevel@tonic-gateMany newcomers to CGI.pm are puzzled by the difference between the
3940*0Sstevel@tonic-gatecalling conventions for the HTML shortcuts, which require curly braces
3941*0Sstevel@tonic-gatearound the HTML tag attributes, and the calling conventions for other
3942*0Sstevel@tonic-gateroutines, which manage to generate attributes without the curly
3943*0Sstevel@tonic-gatebrackets.  Don't be confused.  As a convenience the curly braces are
3944*0Sstevel@tonic-gateoptional in all but the HTML shortcuts.  If you like, you can use
3945*0Sstevel@tonic-gatecurly braces when calling any routine that takes named arguments.  For
3946*0Sstevel@tonic-gateexample:
3947*0Sstevel@tonic-gate
3948*0Sstevel@tonic-gate   print $q->header( {-type=>'image/gif',-expires=>'+3d'} );
3949*0Sstevel@tonic-gate
3950*0Sstevel@tonic-gateIf you use the B<-w> switch, you will be warned that some CGI.pm argument
3951*0Sstevel@tonic-gatenames conflict with built-in Perl functions.  The most frequent of
3952*0Sstevel@tonic-gatethese is the -values argument, used to create multi-valued menus,
3953*0Sstevel@tonic-gateradio button clusters and the like.  To get around this warning, you
3954*0Sstevel@tonic-gatehave several choices:
3955*0Sstevel@tonic-gate
3956*0Sstevel@tonic-gate=over 4
3957*0Sstevel@tonic-gate
3958*0Sstevel@tonic-gate=item 1.
3959*0Sstevel@tonic-gate
3960*0Sstevel@tonic-gateUse another name for the argument, if one is available.
3961*0Sstevel@tonic-gateFor example, -value is an alias for -values.
3962*0Sstevel@tonic-gate
3963*0Sstevel@tonic-gate=item 2.
3964*0Sstevel@tonic-gate
3965*0Sstevel@tonic-gateChange the capitalization, e.g. -Values
3966*0Sstevel@tonic-gate
3967*0Sstevel@tonic-gate=item 3.
3968*0Sstevel@tonic-gate
3969*0Sstevel@tonic-gatePut quotes around the argument name, e.g. '-values'
3970*0Sstevel@tonic-gate
3971*0Sstevel@tonic-gate=back
3972*0Sstevel@tonic-gate
3973*0Sstevel@tonic-gateMany routines will do something useful with a named argument that it
3974*0Sstevel@tonic-gatedoesn't recognize.  For example, you can produce non-standard HTTP
3975*0Sstevel@tonic-gateheader fields by providing them as named arguments:
3976*0Sstevel@tonic-gate
3977*0Sstevel@tonic-gate  print $q->header(-type  =>  'text/html',
3978*0Sstevel@tonic-gate                   -cost  =>  'Three smackers',
3979*0Sstevel@tonic-gate                   -annoyance_level => 'high',
3980*0Sstevel@tonic-gate                   -complaints_to   => 'bit bucket');
3981*0Sstevel@tonic-gate
3982*0Sstevel@tonic-gateThis will produce the following nonstandard HTTP header:
3983*0Sstevel@tonic-gate
3984*0Sstevel@tonic-gate   HTTP/1.0 200 OK
3985*0Sstevel@tonic-gate   Cost: Three smackers
3986*0Sstevel@tonic-gate   Annoyance-level: high
3987*0Sstevel@tonic-gate   Complaints-to: bit bucket
3988*0Sstevel@tonic-gate   Content-type: text/html
3989*0Sstevel@tonic-gate
3990*0Sstevel@tonic-gateNotice the way that underscores are translated automatically into
3991*0Sstevel@tonic-gatehyphens.  HTML-generating routines perform a different type of
3992*0Sstevel@tonic-gatetranslation.
3993*0Sstevel@tonic-gate
3994*0Sstevel@tonic-gateThis feature allows you to keep up with the rapidly changing HTTP and
3995*0Sstevel@tonic-gateHTML "standards".
3996*0Sstevel@tonic-gate
3997*0Sstevel@tonic-gate=head2 CREATING A NEW QUERY OBJECT (OBJECT-ORIENTED STYLE):
3998*0Sstevel@tonic-gate
3999*0Sstevel@tonic-gate     $query = new CGI;
4000*0Sstevel@tonic-gate
4001*0Sstevel@tonic-gateThis will parse the input (from both POST and GET methods) and store
4002*0Sstevel@tonic-gateit into a perl5 object called $query.
4003*0Sstevel@tonic-gate
4004*0Sstevel@tonic-gate=head2 CREATING A NEW QUERY OBJECT FROM AN INPUT FILE
4005*0Sstevel@tonic-gate
4006*0Sstevel@tonic-gate     $query = new CGI(INPUTFILE);
4007*0Sstevel@tonic-gate
4008*0Sstevel@tonic-gateIf you provide a file handle to the new() method, it will read
4009*0Sstevel@tonic-gateparameters from the file (or STDIN, or whatever).  The file can be in
4010*0Sstevel@tonic-gateany of the forms describing below under debugging (i.e. a series of
4011*0Sstevel@tonic-gatenewline delimited TAG=VALUE pairs will work).  Conveniently, this type
4012*0Sstevel@tonic-gateof file is created by the save() method (see below).  Multiple records
4013*0Sstevel@tonic-gatecan be saved and restored.
4014*0Sstevel@tonic-gate
4015*0Sstevel@tonic-gatePerl purists will be pleased to know that this syntax accepts
4016*0Sstevel@tonic-gatereferences to file handles, or even references to filehandle globs,
4017*0Sstevel@tonic-gatewhich is the "official" way to pass a filehandle:
4018*0Sstevel@tonic-gate
4019*0Sstevel@tonic-gate    $query = new CGI(\*STDIN);
4020*0Sstevel@tonic-gate
4021*0Sstevel@tonic-gateYou can also initialize the CGI object with a FileHandle or IO::File
4022*0Sstevel@tonic-gateobject.
4023*0Sstevel@tonic-gate
4024*0Sstevel@tonic-gateIf you are using the function-oriented interface and want to
4025*0Sstevel@tonic-gateinitialize CGI state from a file handle, the way to do this is with
4026*0Sstevel@tonic-gateB<restore_parameters()>.  This will (re)initialize the
4027*0Sstevel@tonic-gatedefault CGI object from the indicated file handle.
4028*0Sstevel@tonic-gate
4029*0Sstevel@tonic-gate    open (IN,"test.in") || die;
4030*0Sstevel@tonic-gate    restore_parameters(IN);
4031*0Sstevel@tonic-gate    close IN;
4032*0Sstevel@tonic-gate
4033*0Sstevel@tonic-gateYou can also initialize the query object from an associative array
4034*0Sstevel@tonic-gatereference:
4035*0Sstevel@tonic-gate
4036*0Sstevel@tonic-gate    $query = new CGI( {'dinosaur'=>'barney',
4037*0Sstevel@tonic-gate		       'song'=>'I love you',
4038*0Sstevel@tonic-gate		       'friends'=>[qw/Jessica George Nancy/]}
4039*0Sstevel@tonic-gate		    );
4040*0Sstevel@tonic-gate
4041*0Sstevel@tonic-gateor from a properly formatted, URL-escaped query string:
4042*0Sstevel@tonic-gate
4043*0Sstevel@tonic-gate    $query = new CGI('dinosaur=barney&color=purple');
4044*0Sstevel@tonic-gate
4045*0Sstevel@tonic-gateor from a previously existing CGI object (currently this clones the
4046*0Sstevel@tonic-gateparameter list, but none of the other object-specific fields, such as
4047*0Sstevel@tonic-gateautoescaping):
4048*0Sstevel@tonic-gate
4049*0Sstevel@tonic-gate    $old_query = new CGI;
4050*0Sstevel@tonic-gate    $new_query = new CGI($old_query);
4051*0Sstevel@tonic-gate
4052*0Sstevel@tonic-gateTo create an empty query, initialize it from an empty string or hash:
4053*0Sstevel@tonic-gate
4054*0Sstevel@tonic-gate   $empty_query = new CGI("");
4055*0Sstevel@tonic-gate
4056*0Sstevel@tonic-gate       -or-
4057*0Sstevel@tonic-gate
4058*0Sstevel@tonic-gate   $empty_query = new CGI({});
4059*0Sstevel@tonic-gate
4060*0Sstevel@tonic-gate=head2 FETCHING A LIST OF KEYWORDS FROM THE QUERY:
4061*0Sstevel@tonic-gate
4062*0Sstevel@tonic-gate     @keywords = $query->keywords
4063*0Sstevel@tonic-gate
4064*0Sstevel@tonic-gateIf the script was invoked as the result of an <ISINDEX> search, the
4065*0Sstevel@tonic-gateparsed keywords can be obtained as an array using the keywords() method.
4066*0Sstevel@tonic-gate
4067*0Sstevel@tonic-gate=head2 FETCHING THE NAMES OF ALL THE PARAMETERS PASSED TO YOUR SCRIPT:
4068*0Sstevel@tonic-gate
4069*0Sstevel@tonic-gate     @names = $query->param
4070*0Sstevel@tonic-gate
4071*0Sstevel@tonic-gateIf the script was invoked with a parameter list
4072*0Sstevel@tonic-gate(e.g. "name1=value1&name2=value2&name3=value3"), the param() method
4073*0Sstevel@tonic-gatewill return the parameter names as a list.  If the script was invoked
4074*0Sstevel@tonic-gateas an <ISINDEX> script and contains a string without ampersands
4075*0Sstevel@tonic-gate(e.g. "value1+value2+value3") , there will be a single parameter named
4076*0Sstevel@tonic-gate"keywords" containing the "+"-delimited keywords.
4077*0Sstevel@tonic-gate
4078*0Sstevel@tonic-gateNOTE: As of version 1.5, the array of parameter names returned will
4079*0Sstevel@tonic-gatebe in the same order as they were submitted by the browser.
4080*0Sstevel@tonic-gateUsually this order is the same as the order in which the
4081*0Sstevel@tonic-gateparameters are defined in the form (however, this isn't part
4082*0Sstevel@tonic-gateof the spec, and so isn't guaranteed).
4083*0Sstevel@tonic-gate
4084*0Sstevel@tonic-gate=head2 FETCHING THE VALUE OR VALUES OF A SINGLE NAMED PARAMETER:
4085*0Sstevel@tonic-gate
4086*0Sstevel@tonic-gate    @values = $query->param('foo');
4087*0Sstevel@tonic-gate
4088*0Sstevel@tonic-gate	      -or-
4089*0Sstevel@tonic-gate
4090*0Sstevel@tonic-gate    $value = $query->param('foo');
4091*0Sstevel@tonic-gate
4092*0Sstevel@tonic-gatePass the param() method a single argument to fetch the value of the
4093*0Sstevel@tonic-gatenamed parameter. If the parameter is multivalued (e.g. from multiple
4094*0Sstevel@tonic-gateselections in a scrolling list), you can ask to receive an array.  Otherwise
4095*0Sstevel@tonic-gatethe method will return a single value.
4096*0Sstevel@tonic-gate
4097*0Sstevel@tonic-gateIf a value is not given in the query string, as in the queries
4098*0Sstevel@tonic-gate"name1=&name2=" or "name1&name2", it will be returned as an empty
4099*0Sstevel@tonic-gatestring.  This feature is new in 2.63.
4100*0Sstevel@tonic-gate
4101*0Sstevel@tonic-gate
4102*0Sstevel@tonic-gateIf the parameter does not exist at all, then param() will return undef
4103*0Sstevel@tonic-gatein a scalar context, and the empty list in a list context.
4104*0Sstevel@tonic-gate
4105*0Sstevel@tonic-gate
4106*0Sstevel@tonic-gate=head2 SETTING THE VALUE(S) OF A NAMED PARAMETER:
4107*0Sstevel@tonic-gate
4108*0Sstevel@tonic-gate    $query->param('foo','an','array','of','values');
4109*0Sstevel@tonic-gate
4110*0Sstevel@tonic-gateThis sets the value for the named parameter 'foo' to an array of
4111*0Sstevel@tonic-gatevalues.  This is one way to change the value of a field AFTER
4112*0Sstevel@tonic-gatethe script has been invoked once before.  (Another way is with
4113*0Sstevel@tonic-gatethe -override parameter accepted by all methods that generate
4114*0Sstevel@tonic-gateform elements.)
4115*0Sstevel@tonic-gate
4116*0Sstevel@tonic-gateparam() also recognizes a named parameter style of calling described
4117*0Sstevel@tonic-gatein more detail later:
4118*0Sstevel@tonic-gate
4119*0Sstevel@tonic-gate    $query->param(-name=>'foo',-values=>['an','array','of','values']);
4120*0Sstevel@tonic-gate
4121*0Sstevel@tonic-gate			      -or-
4122*0Sstevel@tonic-gate
4123*0Sstevel@tonic-gate    $query->param(-name=>'foo',-value=>'the value');
4124*0Sstevel@tonic-gate
4125*0Sstevel@tonic-gate=head2 APPENDING ADDITIONAL VALUES TO A NAMED PARAMETER:
4126*0Sstevel@tonic-gate
4127*0Sstevel@tonic-gate   $query->append(-name=>'foo',-values=>['yet','more','values']);
4128*0Sstevel@tonic-gate
4129*0Sstevel@tonic-gateThis adds a value or list of values to the named parameter.  The
4130*0Sstevel@tonic-gatevalues are appended to the end of the parameter if it already exists.
4131*0Sstevel@tonic-gateOtherwise the parameter is created.  Note that this method only
4132*0Sstevel@tonic-gaterecognizes the named argument calling syntax.
4133*0Sstevel@tonic-gate
4134*0Sstevel@tonic-gate=head2 IMPORTING ALL PARAMETERS INTO A NAMESPACE:
4135*0Sstevel@tonic-gate
4136*0Sstevel@tonic-gate   $query->import_names('R');
4137*0Sstevel@tonic-gate
4138*0Sstevel@tonic-gateThis creates a series of variables in the 'R' namespace.  For example,
4139*0Sstevel@tonic-gate$R::foo, @R:foo.  For keyword lists, a variable @R::keywords will appear.
4140*0Sstevel@tonic-gateIf no namespace is given, this method will assume 'Q'.
4141*0Sstevel@tonic-gateWARNING:  don't import anything into 'main'; this is a major security
4142*0Sstevel@tonic-gaterisk!!!!
4143*0Sstevel@tonic-gate
4144*0Sstevel@tonic-gateNOTE 1: Variable names are transformed as necessary into legal Perl
4145*0Sstevel@tonic-gatevariable names.  All non-legal characters are transformed into
4146*0Sstevel@tonic-gateunderscores.  If you need to keep the original names, you should use
4147*0Sstevel@tonic-gatethe param() method instead to access CGI variables by name.
4148*0Sstevel@tonic-gate
4149*0Sstevel@tonic-gateNOTE 2: In older versions, this method was called B<import()>.  As of version 2.20,
4150*0Sstevel@tonic-gatethis name has been removed completely to avoid conflict with the built-in
4151*0Sstevel@tonic-gatePerl module B<import> operator.
4152*0Sstevel@tonic-gate
4153*0Sstevel@tonic-gate=head2 DELETING A PARAMETER COMPLETELY:
4154*0Sstevel@tonic-gate
4155*0Sstevel@tonic-gate    $query->delete('foo','bar','baz');
4156*0Sstevel@tonic-gate
4157*0Sstevel@tonic-gateThis completely clears a list of parameters.  It sometimes useful for
4158*0Sstevel@tonic-gateresetting parameters that you don't want passed down between script
4159*0Sstevel@tonic-gateinvocations.
4160*0Sstevel@tonic-gate
4161*0Sstevel@tonic-gateIf you are using the function call interface, use "Delete()" instead
4162*0Sstevel@tonic-gateto avoid conflicts with Perl's built-in delete operator.
4163*0Sstevel@tonic-gate
4164*0Sstevel@tonic-gate=head2 DELETING ALL PARAMETERS:
4165*0Sstevel@tonic-gate
4166*0Sstevel@tonic-gate   $query->delete_all();
4167*0Sstevel@tonic-gate
4168*0Sstevel@tonic-gateThis clears the CGI object completely.  It might be useful to ensure
4169*0Sstevel@tonic-gatethat all the defaults are taken when you create a fill-out form.
4170*0Sstevel@tonic-gate
4171*0Sstevel@tonic-gateUse Delete_all() instead if you are using the function call interface.
4172*0Sstevel@tonic-gate
4173*0Sstevel@tonic-gate=head2 DIRECT ACCESS TO THE PARAMETER LIST:
4174*0Sstevel@tonic-gate
4175*0Sstevel@tonic-gate   $q->param_fetch('address')->[1] = '1313 Mockingbird Lane';
4176*0Sstevel@tonic-gate   unshift @{$q->param_fetch(-name=>'address')},'George Munster';
4177*0Sstevel@tonic-gate
4178*0Sstevel@tonic-gateIf you need access to the parameter list in a way that isn't covered
4179*0Sstevel@tonic-gateby the methods above, you can obtain a direct reference to it by
4180*0Sstevel@tonic-gatecalling the B<param_fetch()> method with the name of the .  This
4181*0Sstevel@tonic-gatewill return an array reference to the named parameters, which you then
4182*0Sstevel@tonic-gatecan manipulate in any way you like.
4183*0Sstevel@tonic-gate
4184*0Sstevel@tonic-gateYou can also use a named argument style using the B<-name> argument.
4185*0Sstevel@tonic-gate
4186*0Sstevel@tonic-gate=head2 FETCHING THE PARAMETER LIST AS A HASH:
4187*0Sstevel@tonic-gate
4188*0Sstevel@tonic-gate    $params = $q->Vars;
4189*0Sstevel@tonic-gate    print $params->{'address'};
4190*0Sstevel@tonic-gate    @foo = split("\0",$params->{'foo'});
4191*0Sstevel@tonic-gate    %params = $q->Vars;
4192*0Sstevel@tonic-gate
4193*0Sstevel@tonic-gate    use CGI ':cgi-lib';
4194*0Sstevel@tonic-gate    $params = Vars;
4195*0Sstevel@tonic-gate
4196*0Sstevel@tonic-gateMany people want to fetch the entire parameter list as a hash in which
4197*0Sstevel@tonic-gatethe keys are the names of the CGI parameters, and the values are the
4198*0Sstevel@tonic-gateparameters' values.  The Vars() method does this.  Called in a scalar
4199*0Sstevel@tonic-gatecontext, it returns the parameter list as a tied hash reference.
4200*0Sstevel@tonic-gateChanging a key changes the value of the parameter in the underlying
4201*0Sstevel@tonic-gateCGI parameter list.  Called in a list context, it returns the
4202*0Sstevel@tonic-gateparameter list as an ordinary hash.  This allows you to read the
4203*0Sstevel@tonic-gatecontents of the parameter list, but not to change it.
4204*0Sstevel@tonic-gate
4205*0Sstevel@tonic-gateWhen using this, the thing you must watch out for are multivalued CGI
4206*0Sstevel@tonic-gateparameters.  Because a hash cannot distinguish between scalar and
4207*0Sstevel@tonic-gatelist context, multivalued parameters will be returned as a packed
4208*0Sstevel@tonic-gatestring, separated by the "\0" (null) character.  You must split this
4209*0Sstevel@tonic-gatepacked string in order to get at the individual values.  This is the
4210*0Sstevel@tonic-gateconvention introduced long ago by Steve Brenner in his cgi-lib.pl
4211*0Sstevel@tonic-gatemodule for Perl version 4.
4212*0Sstevel@tonic-gate
4213*0Sstevel@tonic-gateIf you wish to use Vars() as a function, import the I<:cgi-lib> set of
4214*0Sstevel@tonic-gatefunction calls (also see the section on CGI-LIB compatibility).
4215*0Sstevel@tonic-gate
4216*0Sstevel@tonic-gate=head2 SAVING THE STATE OF THE SCRIPT TO A FILE:
4217*0Sstevel@tonic-gate
4218*0Sstevel@tonic-gate    $query->save(FILEHANDLE)
4219*0Sstevel@tonic-gate
4220*0Sstevel@tonic-gateThis will write the current state of the form to the provided
4221*0Sstevel@tonic-gatefilehandle.  You can read it back in by providing a filehandle
4222*0Sstevel@tonic-gateto the new() method.  Note that the filehandle can be a file, a pipe,
4223*0Sstevel@tonic-gateor whatever!
4224*0Sstevel@tonic-gate
4225*0Sstevel@tonic-gateThe format of the saved file is:
4226*0Sstevel@tonic-gate
4227*0Sstevel@tonic-gate	NAME1=VALUE1
4228*0Sstevel@tonic-gate	NAME1=VALUE1'
4229*0Sstevel@tonic-gate	NAME2=VALUE2
4230*0Sstevel@tonic-gate	NAME3=VALUE3
4231*0Sstevel@tonic-gate	=
4232*0Sstevel@tonic-gate
4233*0Sstevel@tonic-gateBoth name and value are URL escaped.  Multi-valued CGI parameters are
4234*0Sstevel@tonic-gaterepresented as repeated names.  A session record is delimited by a
4235*0Sstevel@tonic-gatesingle = symbol.  You can write out multiple records and read them
4236*0Sstevel@tonic-gateback in with several calls to B<new>.  You can do this across several
4237*0Sstevel@tonic-gatesessions by opening the file in append mode, allowing you to create
4238*0Sstevel@tonic-gateprimitive guest books, or to keep a history of users' queries.  Here's
4239*0Sstevel@tonic-gatea short example of creating multiple session records:
4240*0Sstevel@tonic-gate
4241*0Sstevel@tonic-gate   use CGI;
4242*0Sstevel@tonic-gate
4243*0Sstevel@tonic-gate   open (OUT,">>test.out") || die;
4244*0Sstevel@tonic-gate   $records = 5;
4245*0Sstevel@tonic-gate   foreach (0..$records) {
4246*0Sstevel@tonic-gate       my $q = new CGI;
4247*0Sstevel@tonic-gate       $q->param(-name=>'counter',-value=>$_);
4248*0Sstevel@tonic-gate       $q->save(OUT);
4249*0Sstevel@tonic-gate   }
4250*0Sstevel@tonic-gate   close OUT;
4251*0Sstevel@tonic-gate
4252*0Sstevel@tonic-gate   # reopen for reading
4253*0Sstevel@tonic-gate   open (IN,"test.out") || die;
4254*0Sstevel@tonic-gate   while (!eof(IN)) {
4255*0Sstevel@tonic-gate       my $q = new CGI(IN);
4256*0Sstevel@tonic-gate       print $q->param('counter'),"\n";
4257*0Sstevel@tonic-gate   }
4258*0Sstevel@tonic-gate
4259*0Sstevel@tonic-gateThe file format used for save/restore is identical to that used by the
4260*0Sstevel@tonic-gateWhitehead Genome Center's data exchange format "Boulderio", and can be
4261*0Sstevel@tonic-gatemanipulated and even databased using Boulderio utilities.  See
4262*0Sstevel@tonic-gate
4263*0Sstevel@tonic-gate  http://stein.cshl.org/boulder/
4264*0Sstevel@tonic-gate
4265*0Sstevel@tonic-gatefor further details.
4266*0Sstevel@tonic-gate
4267*0Sstevel@tonic-gateIf you wish to use this method from the function-oriented (non-OO)
4268*0Sstevel@tonic-gateinterface, the exported name for this method is B<save_parameters()>.
4269*0Sstevel@tonic-gate
4270*0Sstevel@tonic-gate=head2 RETRIEVING CGI ERRORS
4271*0Sstevel@tonic-gate
4272*0Sstevel@tonic-gateErrors can occur while processing user input, particularly when
4273*0Sstevel@tonic-gateprocessing uploaded files.  When these errors occur, CGI will stop
4274*0Sstevel@tonic-gateprocessing and return an empty parameter list.  You can test for
4275*0Sstevel@tonic-gatethe existence and nature of errors using the I<cgi_error()> function.
4276*0Sstevel@tonic-gateThe error messages are formatted as HTTP status codes. You can either
4277*0Sstevel@tonic-gateincorporate the error text into an HTML page, or use it as the value
4278*0Sstevel@tonic-gateof the HTTP status:
4279*0Sstevel@tonic-gate
4280*0Sstevel@tonic-gate    my $error = $q->cgi_error;
4281*0Sstevel@tonic-gate    if ($error) {
4282*0Sstevel@tonic-gate	print $q->header(-status=>$error),
4283*0Sstevel@tonic-gate	      $q->start_html('Problems'),
4284*0Sstevel@tonic-gate              $q->h2('Request not processed'),
4285*0Sstevel@tonic-gate	      $q->strong($error);
4286*0Sstevel@tonic-gate        exit 0;
4287*0Sstevel@tonic-gate    }
4288*0Sstevel@tonic-gate
4289*0Sstevel@tonic-gateWhen using the function-oriented interface (see the next section),
4290*0Sstevel@tonic-gateerrors may only occur the first time you call I<param()>. Be ready
4291*0Sstevel@tonic-gatefor this!
4292*0Sstevel@tonic-gate
4293*0Sstevel@tonic-gate=head2 USING THE FUNCTION-ORIENTED INTERFACE
4294*0Sstevel@tonic-gate
4295*0Sstevel@tonic-gateTo use the function-oriented interface, you must specify which CGI.pm
4296*0Sstevel@tonic-gateroutines or sets of routines to import into your script's namespace.
4297*0Sstevel@tonic-gateThere is a small overhead associated with this importation, but it
4298*0Sstevel@tonic-gateisn't much.
4299*0Sstevel@tonic-gate
4300*0Sstevel@tonic-gate   use CGI <list of methods>;
4301*0Sstevel@tonic-gate
4302*0Sstevel@tonic-gateThe listed methods will be imported into the current package; you can
4303*0Sstevel@tonic-gatecall them directly without creating a CGI object first.  This example
4304*0Sstevel@tonic-gateshows how to import the B<param()> and B<header()>
4305*0Sstevel@tonic-gatemethods, and then use them directly:
4306*0Sstevel@tonic-gate
4307*0Sstevel@tonic-gate   use CGI 'param','header';
4308*0Sstevel@tonic-gate   print header('text/plain');
4309*0Sstevel@tonic-gate   $zipcode = param('zipcode');
4310*0Sstevel@tonic-gate
4311*0Sstevel@tonic-gateMore frequently, you'll import common sets of functions by referring
4312*0Sstevel@tonic-gateto the groups by name.  All function sets are preceded with a ":"
4313*0Sstevel@tonic-gatecharacter as in ":html3" (for tags defined in the HTML 3 standard).
4314*0Sstevel@tonic-gate
4315*0Sstevel@tonic-gateHere is a list of the function sets you can import:
4316*0Sstevel@tonic-gate
4317*0Sstevel@tonic-gate=over 4
4318*0Sstevel@tonic-gate
4319*0Sstevel@tonic-gate=item B<:cgi>
4320*0Sstevel@tonic-gate
4321*0Sstevel@tonic-gateImport all CGI-handling methods, such as B<param()>, B<path_info()>
4322*0Sstevel@tonic-gateand the like.
4323*0Sstevel@tonic-gate
4324*0Sstevel@tonic-gate=item B<:form>
4325*0Sstevel@tonic-gate
4326*0Sstevel@tonic-gateImport all fill-out form generating methods, such as B<textfield()>.
4327*0Sstevel@tonic-gate
4328*0Sstevel@tonic-gate=item B<:html2>
4329*0Sstevel@tonic-gate
4330*0Sstevel@tonic-gateImport all methods that generate HTML 2.0 standard elements.
4331*0Sstevel@tonic-gate
4332*0Sstevel@tonic-gate=item B<:html3>
4333*0Sstevel@tonic-gate
4334*0Sstevel@tonic-gateImport all methods that generate HTML 3.0 elements (such as
4335*0Sstevel@tonic-gate<table>, <super> and <sub>).
4336*0Sstevel@tonic-gate
4337*0Sstevel@tonic-gate=item B<:html4>
4338*0Sstevel@tonic-gate
4339*0Sstevel@tonic-gateImport all methods that generate HTML 4 elements (such as
4340*0Sstevel@tonic-gate<abbrev>, <acronym> and <thead>).
4341*0Sstevel@tonic-gate
4342*0Sstevel@tonic-gate=item B<:netscape>
4343*0Sstevel@tonic-gate
4344*0Sstevel@tonic-gateImport all methods that generate Netscape-specific HTML extensions.
4345*0Sstevel@tonic-gate
4346*0Sstevel@tonic-gate=item B<:html>
4347*0Sstevel@tonic-gate
4348*0Sstevel@tonic-gateImport all HTML-generating shortcuts (i.e. 'html2' + 'html3' +
4349*0Sstevel@tonic-gate'netscape')...
4350*0Sstevel@tonic-gate
4351*0Sstevel@tonic-gate=item B<:standard>
4352*0Sstevel@tonic-gate
4353*0Sstevel@tonic-gateImport "standard" features, 'html2', 'html3', 'html4', 'form' and 'cgi'.
4354*0Sstevel@tonic-gate
4355*0Sstevel@tonic-gate=item B<:all>
4356*0Sstevel@tonic-gate
4357*0Sstevel@tonic-gateImport all the available methods.  For the full list, see the CGI.pm
4358*0Sstevel@tonic-gatecode, where the variable %EXPORT_TAGS is defined.
4359*0Sstevel@tonic-gate
4360*0Sstevel@tonic-gate=back
4361*0Sstevel@tonic-gate
4362*0Sstevel@tonic-gateIf you import a function name that is not part of CGI.pm, the module
4363*0Sstevel@tonic-gatewill treat it as a new HTML tag and generate the appropriate
4364*0Sstevel@tonic-gatesubroutine.  You can then use it like any other HTML tag.  This is to
4365*0Sstevel@tonic-gateprovide for the rapidly-evolving HTML "standard."  For example, say
4366*0Sstevel@tonic-gateMicrosoft comes out with a new tag called <gradient> (which causes the
4367*0Sstevel@tonic-gateuser's desktop to be flooded with a rotating gradient fill until his
4368*0Sstevel@tonic-gatemachine reboots).  You don't need to wait for a new version of CGI.pm
4369*0Sstevel@tonic-gateto start using it immediately:
4370*0Sstevel@tonic-gate
4371*0Sstevel@tonic-gate   use CGI qw/:standard :html3 gradient/;
4372*0Sstevel@tonic-gate   print gradient({-start=>'red',-end=>'blue'});
4373*0Sstevel@tonic-gate
4374*0Sstevel@tonic-gateNote that in the interests of execution speed CGI.pm does B<not> use
4375*0Sstevel@tonic-gatethe standard L<Exporter> syntax for specifying load symbols.  This may
4376*0Sstevel@tonic-gatechange in the future.
4377*0Sstevel@tonic-gate
4378*0Sstevel@tonic-gateIf you import any of the state-maintaining CGI or form-generating
4379*0Sstevel@tonic-gatemethods, a default CGI object will be created and initialized
4380*0Sstevel@tonic-gateautomatically the first time you use any of the methods that require
4381*0Sstevel@tonic-gateone to be present.  This includes B<param()>, B<textfield()>,
4382*0Sstevel@tonic-gateB<submit()> and the like.  (If you need direct access to the CGI
4383*0Sstevel@tonic-gateobject, you can find it in the global variable B<$CGI::Q>).  By
4384*0Sstevel@tonic-gateimporting CGI.pm methods, you can create visually elegant scripts:
4385*0Sstevel@tonic-gate
4386*0Sstevel@tonic-gate   use CGI qw/:standard/;
4387*0Sstevel@tonic-gate   print
4388*0Sstevel@tonic-gate       header,
4389*0Sstevel@tonic-gate       start_html('Simple Script'),
4390*0Sstevel@tonic-gate       h1('Simple Script'),
4391*0Sstevel@tonic-gate       start_form,
4392*0Sstevel@tonic-gate       "What's your name? ",textfield('name'),p,
4393*0Sstevel@tonic-gate       "What's the combination?",
4394*0Sstevel@tonic-gate       checkbox_group(-name=>'words',
4395*0Sstevel@tonic-gate		      -values=>['eenie','meenie','minie','moe'],
4396*0Sstevel@tonic-gate		      -defaults=>['eenie','moe']),p,
4397*0Sstevel@tonic-gate       "What's your favorite color?",
4398*0Sstevel@tonic-gate       popup_menu(-name=>'color',
4399*0Sstevel@tonic-gate		  -values=>['red','green','blue','chartreuse']),p,
4400*0Sstevel@tonic-gate       submit,
4401*0Sstevel@tonic-gate       end_form,
4402*0Sstevel@tonic-gate       hr,"\n";
4403*0Sstevel@tonic-gate
4404*0Sstevel@tonic-gate    if (param) {
4405*0Sstevel@tonic-gate       print
4406*0Sstevel@tonic-gate	   "Your name is ",em(param('name')),p,
4407*0Sstevel@tonic-gate	   "The keywords are: ",em(join(", ",param('words'))),p,
4408*0Sstevel@tonic-gate	   "Your favorite color is ",em(param('color')),".\n";
4409*0Sstevel@tonic-gate    }
4410*0Sstevel@tonic-gate    print end_html;
4411*0Sstevel@tonic-gate
4412*0Sstevel@tonic-gate=head2 PRAGMAS
4413*0Sstevel@tonic-gate
4414*0Sstevel@tonic-gateIn addition to the function sets, there are a number of pragmas that
4415*0Sstevel@tonic-gateyou can import.  Pragmas, which are always preceded by a hyphen,
4416*0Sstevel@tonic-gatechange the way that CGI.pm functions in various ways.  Pragmas,
4417*0Sstevel@tonic-gatefunction sets, and individual functions can all be imported in the
4418*0Sstevel@tonic-gatesame use() line.  For example, the following use statement imports the
4419*0Sstevel@tonic-gatestandard set of functions and enables debugging mode (pragma
4420*0Sstevel@tonic-gate-debug):
4421*0Sstevel@tonic-gate
4422*0Sstevel@tonic-gate   use CGI qw/:standard -debug/;
4423*0Sstevel@tonic-gate
4424*0Sstevel@tonic-gateThe current list of pragmas is as follows:
4425*0Sstevel@tonic-gate
4426*0Sstevel@tonic-gate=over 4
4427*0Sstevel@tonic-gate
4428*0Sstevel@tonic-gate=item -any
4429*0Sstevel@tonic-gate
4430*0Sstevel@tonic-gateWhen you I<use CGI -any>, then any method that the query object
4431*0Sstevel@tonic-gatedoesn't recognize will be interpreted as a new HTML tag.  This allows
4432*0Sstevel@tonic-gateyou to support the next I<ad hoc> Netscape or Microsoft HTML
4433*0Sstevel@tonic-gateextension.  This lets you go wild with new and unsupported tags:
4434*0Sstevel@tonic-gate
4435*0Sstevel@tonic-gate   use CGI qw(-any);
4436*0Sstevel@tonic-gate   $q=new CGI;
4437*0Sstevel@tonic-gate   print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
4438*0Sstevel@tonic-gate
4439*0Sstevel@tonic-gateSince using <cite>any</cite> causes any mistyped method name
4440*0Sstevel@tonic-gateto be interpreted as an HTML tag, use it with care or not at
4441*0Sstevel@tonic-gateall.
4442*0Sstevel@tonic-gate
4443*0Sstevel@tonic-gate=item -compile
4444*0Sstevel@tonic-gate
4445*0Sstevel@tonic-gateThis causes the indicated autoloaded methods to be compiled up front,
4446*0Sstevel@tonic-gaterather than deferred to later.  This is useful for scripts that run
4447*0Sstevel@tonic-gatefor an extended period of time under FastCGI or mod_perl, and for
4448*0Sstevel@tonic-gatethose destined to be crunched by Malcom Beattie's Perl compiler.  Use
4449*0Sstevel@tonic-gateit in conjunction with the methods or method families you plan to use.
4450*0Sstevel@tonic-gate
4451*0Sstevel@tonic-gate   use CGI qw(-compile :standard :html3);
4452*0Sstevel@tonic-gate
4453*0Sstevel@tonic-gateor even
4454*0Sstevel@tonic-gate
4455*0Sstevel@tonic-gate   use CGI qw(-compile :all);
4456*0Sstevel@tonic-gate
4457*0Sstevel@tonic-gateNote that using the -compile pragma in this way will always have
4458*0Sstevel@tonic-gatethe effect of importing the compiled functions into the current
4459*0Sstevel@tonic-gatenamespace.  If you want to compile without importing use the
4460*0Sstevel@tonic-gatecompile() method instead:
4461*0Sstevel@tonic-gate
4462*0Sstevel@tonic-gate   use CGI();
4463*0Sstevel@tonic-gate   CGI->compile();
4464*0Sstevel@tonic-gate
4465*0Sstevel@tonic-gateThis is particularly useful in a mod_perl environment, in which you
4466*0Sstevel@tonic-gatemight want to precompile all CGI routines in a startup script, and
4467*0Sstevel@tonic-gatethen import the functions individually in each mod_perl script.
4468*0Sstevel@tonic-gate
4469*0Sstevel@tonic-gate=item -nosticky
4470*0Sstevel@tonic-gate
4471*0Sstevel@tonic-gateThis makes CGI.pm not generating the hidden fields .submit
4472*0Sstevel@tonic-gateand .cgifields. It is very useful if you don't want to
4473*0Sstevel@tonic-gatehave the hidden fields appear in the querystring in a GET method.
4474*0Sstevel@tonic-gateFor example, a search script generated this way will have
4475*0Sstevel@tonic-gatea very nice url with search parameters for bookmarking.
4476*0Sstevel@tonic-gate
4477*0Sstevel@tonic-gate=item -no_undef_params
4478*0Sstevel@tonic-gate
4479*0Sstevel@tonic-gateThis keeps CGI.pm from including undef params in the parameter list.
4480*0Sstevel@tonic-gate
4481*0Sstevel@tonic-gate=item -no_xhtml
4482*0Sstevel@tonic-gate
4483*0Sstevel@tonic-gateBy default, CGI.pm versions 2.69 and higher emit XHTML
4484*0Sstevel@tonic-gate(http://www.w3.org/TR/xhtml1/).  The -no_xhtml pragma disables this
4485*0Sstevel@tonic-gatefeature.  Thanks to Michalis Kabrianis <kabrianis@hellug.gr> for this
4486*0Sstevel@tonic-gatefeature.
4487*0Sstevel@tonic-gate
4488*0Sstevel@tonic-gate=item -nph
4489*0Sstevel@tonic-gate
4490*0Sstevel@tonic-gateThis makes CGI.pm produce a header appropriate for an NPH (no
4491*0Sstevel@tonic-gateparsed header) script.  You may need to do other things as well
4492*0Sstevel@tonic-gateto tell the server that the script is NPH.  See the discussion
4493*0Sstevel@tonic-gateof NPH scripts below.
4494*0Sstevel@tonic-gate
4495*0Sstevel@tonic-gate=item -newstyle_urls
4496*0Sstevel@tonic-gate
4497*0Sstevel@tonic-gateSeparate the name=value pairs in CGI parameter query strings with
4498*0Sstevel@tonic-gatesemicolons rather than ampersands.  For example:
4499*0Sstevel@tonic-gate
4500*0Sstevel@tonic-gate   ?name=fred;age=24;favorite_color=3
4501*0Sstevel@tonic-gate
4502*0Sstevel@tonic-gateSemicolon-delimited query strings are always accepted, but will not be
4503*0Sstevel@tonic-gateemitted by self_url() and query_string() unless the -newstyle_urls
4504*0Sstevel@tonic-gatepragma is specified.
4505*0Sstevel@tonic-gate
4506*0Sstevel@tonic-gateThis became the default in version 2.64.
4507*0Sstevel@tonic-gate
4508*0Sstevel@tonic-gate=item -oldstyle_urls
4509*0Sstevel@tonic-gate
4510*0Sstevel@tonic-gateSeparate the name=value pairs in CGI parameter query strings with
4511*0Sstevel@tonic-gateampersands rather than semicolons.  This is no longer the default.
4512*0Sstevel@tonic-gate
4513*0Sstevel@tonic-gate=item -autoload
4514*0Sstevel@tonic-gate
4515*0Sstevel@tonic-gateThis overrides the autoloader so that any function in your program
4516*0Sstevel@tonic-gatethat is not recognized is referred to CGI.pm for possible evaluation.
4517*0Sstevel@tonic-gateThis allows you to use all the CGI.pm functions without adding them to
4518*0Sstevel@tonic-gateyour symbol table, which is of concern for mod_perl users who are
4519*0Sstevel@tonic-gateworried about memory consumption.  I<Warning:> when
4520*0Sstevel@tonic-gateI<-autoload> is in effect, you cannot use "poetry mode"
4521*0Sstevel@tonic-gate(functions without the parenthesis).  Use I<hr()> rather
4522*0Sstevel@tonic-gatethan I<hr>, or add something like I<use subs qw/hr p header/>
4523*0Sstevel@tonic-gateto the top of your script.
4524*0Sstevel@tonic-gate
4525*0Sstevel@tonic-gate=item -no_debug
4526*0Sstevel@tonic-gate
4527*0Sstevel@tonic-gateThis turns off the command-line processing features.  If you want to
4528*0Sstevel@tonic-gaterun a CGI.pm script from the command line to produce HTML, and you
4529*0Sstevel@tonic-gatedon't want it to read CGI parameters from the command line or STDIN,
4530*0Sstevel@tonic-gatethen use this pragma:
4531*0Sstevel@tonic-gate
4532*0Sstevel@tonic-gate   use CGI qw(-no_debug :standard);
4533*0Sstevel@tonic-gate
4534*0Sstevel@tonic-gate=item -debug
4535*0Sstevel@tonic-gate
4536*0Sstevel@tonic-gateThis turns on full debugging.  In addition to reading CGI arguments
4537*0Sstevel@tonic-gatefrom the command-line processing, CGI.pm will pause and try to read
4538*0Sstevel@tonic-gatearguments from STDIN, producing the message "(offline mode: enter
4539*0Sstevel@tonic-gatename=value pairs on standard input)" features.
4540*0Sstevel@tonic-gate
4541*0Sstevel@tonic-gateSee the section on debugging for more details.
4542*0Sstevel@tonic-gate
4543*0Sstevel@tonic-gate=item -private_tempfiles
4544*0Sstevel@tonic-gate
4545*0Sstevel@tonic-gateCGI.pm can process uploaded file. Ordinarily it spools the uploaded
4546*0Sstevel@tonic-gatefile to a temporary directory, then deletes the file when done.
4547*0Sstevel@tonic-gateHowever, this opens the risk of eavesdropping as described in the file
4548*0Sstevel@tonic-gateupload section.  Another CGI script author could peek at this data
4549*0Sstevel@tonic-gateduring the upload, even if it is confidential information. On Unix
4550*0Sstevel@tonic-gatesystems, the -private_tempfiles pragma will cause the temporary file
4551*0Sstevel@tonic-gateto be unlinked as soon as it is opened and before any data is written
4552*0Sstevel@tonic-gateinto it, reducing, but not eliminating the risk of eavesdropping
4553*0Sstevel@tonic-gate(there is still a potential race condition).  To make life harder for
4554*0Sstevel@tonic-gatethe attacker, the program chooses tempfile names by calculating a 32
4555*0Sstevel@tonic-gatebit checksum of the incoming HTTP headers.
4556*0Sstevel@tonic-gate
4557*0Sstevel@tonic-gateTo ensure that the temporary file cannot be read by other CGI scripts,
4558*0Sstevel@tonic-gateuse suEXEC or a CGI wrapper program to run your script.  The temporary
4559*0Sstevel@tonic-gatefile is created with mode 0600 (neither world nor group readable).
4560*0Sstevel@tonic-gate
4561*0Sstevel@tonic-gateThe temporary directory is selected using the following algorithm:
4562*0Sstevel@tonic-gate
4563*0Sstevel@tonic-gate    1. if the current user (e.g. "nobody") has a directory named
4564*0Sstevel@tonic-gate    "tmp" in its home directory, use that (Unix systems only).
4565*0Sstevel@tonic-gate
4566*0Sstevel@tonic-gate    2. if the environment variable TMPDIR exists, use the location
4567*0Sstevel@tonic-gate    indicated.
4568*0Sstevel@tonic-gate
4569*0Sstevel@tonic-gate    3. Otherwise try the locations /usr/tmp, /var/tmp, C:\temp,
4570*0Sstevel@tonic-gate    /tmp, /temp, ::Temporary Items, and \WWW_ROOT.
4571*0Sstevel@tonic-gate
4572*0Sstevel@tonic-gateEach of these locations is checked that it is a directory and is
4573*0Sstevel@tonic-gatewritable.  If not, the algorithm tries the next choice.
4574*0Sstevel@tonic-gate
4575*0Sstevel@tonic-gate=back
4576*0Sstevel@tonic-gate
4577*0Sstevel@tonic-gate=head2 SPECIAL FORMS FOR IMPORTING HTML-TAG FUNCTIONS
4578*0Sstevel@tonic-gate
4579*0Sstevel@tonic-gateMany of the methods generate HTML tags.  As described below, tag
4580*0Sstevel@tonic-gatefunctions automatically generate both the opening and closing tags.
4581*0Sstevel@tonic-gateFor example:
4582*0Sstevel@tonic-gate
4583*0Sstevel@tonic-gate  print h1('Level 1 Header');
4584*0Sstevel@tonic-gate
4585*0Sstevel@tonic-gateproduces
4586*0Sstevel@tonic-gate
4587*0Sstevel@tonic-gate  <h1>Level 1 Header</h1>
4588*0Sstevel@tonic-gate
4589*0Sstevel@tonic-gateThere will be some times when you want to produce the start and end
4590*0Sstevel@tonic-gatetags yourself.  In this case, you can use the form start_I<tag_name>
4591*0Sstevel@tonic-gateand end_I<tag_name>, as in:
4592*0Sstevel@tonic-gate
4593*0Sstevel@tonic-gate  print start_h1,'Level 1 Header',end_h1;
4594*0Sstevel@tonic-gate
4595*0Sstevel@tonic-gateWith a few exceptions (described below), start_I<tag_name> and
4596*0Sstevel@tonic-gateend_I<tag_name> functions are not generated automatically when you
4597*0Sstevel@tonic-gateI<use CGI>.  However, you can specify the tags you want to generate
4598*0Sstevel@tonic-gateI<start/end> functions for by putting an asterisk in front of their
4599*0Sstevel@tonic-gatename, or, alternatively, requesting either "start_I<tag_name>" or
4600*0Sstevel@tonic-gate"end_I<tag_name>" in the import list.
4601*0Sstevel@tonic-gate
4602*0Sstevel@tonic-gateExample:
4603*0Sstevel@tonic-gate
4604*0Sstevel@tonic-gate  use CGI qw/:standard *table start_ul/;
4605*0Sstevel@tonic-gate
4606*0Sstevel@tonic-gateIn this example, the following functions are generated in addition to
4607*0Sstevel@tonic-gatethe standard ones:
4608*0Sstevel@tonic-gate
4609*0Sstevel@tonic-gate=over 4
4610*0Sstevel@tonic-gate
4611*0Sstevel@tonic-gate=item 1. start_table() (generates a <table> tag)
4612*0Sstevel@tonic-gate
4613*0Sstevel@tonic-gate=item 2. end_table() (generates a </table> tag)
4614*0Sstevel@tonic-gate
4615*0Sstevel@tonic-gate=item 3. start_ul() (generates a <ul> tag)
4616*0Sstevel@tonic-gate
4617*0Sstevel@tonic-gate=item 4. end_ul() (generates a </ul> tag)
4618*0Sstevel@tonic-gate
4619*0Sstevel@tonic-gate=back
4620*0Sstevel@tonic-gate
4621*0Sstevel@tonic-gate=head1 GENERATING DYNAMIC DOCUMENTS
4622*0Sstevel@tonic-gate
4623*0Sstevel@tonic-gateMost of CGI.pm's functions deal with creating documents on the fly.
4624*0Sstevel@tonic-gateGenerally you will produce the HTTP header first, followed by the
4625*0Sstevel@tonic-gatedocument itself.  CGI.pm provides functions for generating HTTP
4626*0Sstevel@tonic-gateheaders of various types as well as for generating HTML.  For creating
4627*0Sstevel@tonic-gateGIF images, see the GD.pm module.
4628*0Sstevel@tonic-gate
4629*0Sstevel@tonic-gateEach of these functions produces a fragment of HTML or HTTP which you
4630*0Sstevel@tonic-gatecan print out directly so that it displays in the browser window,
4631*0Sstevel@tonic-gateappend to a string, or save to a file for later use.
4632*0Sstevel@tonic-gate
4633*0Sstevel@tonic-gate=head2 CREATING A STANDARD HTTP HEADER:
4634*0Sstevel@tonic-gate
4635*0Sstevel@tonic-gateNormally the first thing you will do in any CGI script is print out an
4636*0Sstevel@tonic-gateHTTP header.  This tells the browser what type of document to expect,
4637*0Sstevel@tonic-gateand gives other optional information, such as the language, expiration
4638*0Sstevel@tonic-gatedate, and whether to cache the document.  The header can also be
4639*0Sstevel@tonic-gatemanipulated for special purposes, such as server push and pay per view
4640*0Sstevel@tonic-gatepages.
4641*0Sstevel@tonic-gate
4642*0Sstevel@tonic-gate	print $query->header;
4643*0Sstevel@tonic-gate
4644*0Sstevel@tonic-gate	     -or-
4645*0Sstevel@tonic-gate
4646*0Sstevel@tonic-gate	print $query->header('image/gif');
4647*0Sstevel@tonic-gate
4648*0Sstevel@tonic-gate	     -or-
4649*0Sstevel@tonic-gate
4650*0Sstevel@tonic-gate	print $query->header('text/html','204 No response');
4651*0Sstevel@tonic-gate
4652*0Sstevel@tonic-gate	     -or-
4653*0Sstevel@tonic-gate
4654*0Sstevel@tonic-gate	print $query->header(-type=>'image/gif',
4655*0Sstevel@tonic-gate			     -nph=>1,
4656*0Sstevel@tonic-gate			     -status=>'402 Payment required',
4657*0Sstevel@tonic-gate			     -expires=>'+3d',
4658*0Sstevel@tonic-gate			     -cookie=>$cookie,
4659*0Sstevel@tonic-gate                             -charset=>'utf-7',
4660*0Sstevel@tonic-gate                             -attachment=>'foo.gif',
4661*0Sstevel@tonic-gate			     -Cost=>'$2.00');
4662*0Sstevel@tonic-gate
4663*0Sstevel@tonic-gateheader() returns the Content-type: header.  You can provide your own
4664*0Sstevel@tonic-gateMIME type if you choose, otherwise it defaults to text/html.  An
4665*0Sstevel@tonic-gateoptional second parameter specifies the status code and a human-readable
4666*0Sstevel@tonic-gatemessage.  For example, you can specify 204, "No response" to create a
4667*0Sstevel@tonic-gatescript that tells the browser to do nothing at all.
4668*0Sstevel@tonic-gate
4669*0Sstevel@tonic-gateThe last example shows the named argument style for passing arguments
4670*0Sstevel@tonic-gateto the CGI methods using named parameters.  Recognized parameters are
4671*0Sstevel@tonic-gateB<-type>, B<-status>, B<-expires>, and B<-cookie>.  Any other named
4672*0Sstevel@tonic-gateparameters will be stripped of their initial hyphens and turned into
4673*0Sstevel@tonic-gateheader fields, allowing you to specify any HTTP header you desire.
4674*0Sstevel@tonic-gateInternal underscores will be turned into hyphens:
4675*0Sstevel@tonic-gate
4676*0Sstevel@tonic-gate    print $query->header(-Content_length=>3002);
4677*0Sstevel@tonic-gate
4678*0Sstevel@tonic-gateMost browsers will not cache the output from CGI scripts.  Every time
4679*0Sstevel@tonic-gatethe browser reloads the page, the script is invoked anew.  You can
4680*0Sstevel@tonic-gatechange this behavior with the B<-expires> parameter.  When you specify
4681*0Sstevel@tonic-gatean absolute or relative expiration interval with this parameter, some
4682*0Sstevel@tonic-gatebrowsers and proxy servers will cache the script's output until the
4683*0Sstevel@tonic-gateindicated expiration date.  The following forms are all valid for the
4684*0Sstevel@tonic-gate-expires field:
4685*0Sstevel@tonic-gate
4686*0Sstevel@tonic-gate	+30s                              30 seconds from now
4687*0Sstevel@tonic-gate	+10m                              ten minutes from now
4688*0Sstevel@tonic-gate	+1h                               one hour from now
4689*0Sstevel@tonic-gate	-1d                               yesterday (i.e. "ASAP!")
4690*0Sstevel@tonic-gate	now                               immediately
4691*0Sstevel@tonic-gate	+3M                               in three months
4692*0Sstevel@tonic-gate	+10y                              in ten years time
4693*0Sstevel@tonic-gate	Thursday, 25-Apr-1999 00:40:33 GMT  at the indicated time & date
4694*0Sstevel@tonic-gate
4695*0Sstevel@tonic-gateThe B<-cookie> parameter generates a header that tells the browser to provide
4696*0Sstevel@tonic-gatea "magic cookie" during all subsequent transactions with your script.
4697*0Sstevel@tonic-gateNetscape cookies have a special format that includes interesting attributes
4698*0Sstevel@tonic-gatesuch as expiration time.  Use the cookie() method to create and retrieve
4699*0Sstevel@tonic-gatesession cookies.
4700*0Sstevel@tonic-gate
4701*0Sstevel@tonic-gateThe B<-nph> parameter, if set to a true value, will issue the correct
4702*0Sstevel@tonic-gateheaders to work with a NPH (no-parse-header) script.  This is important
4703*0Sstevel@tonic-gateto use with certain servers that expect all their scripts to be NPH.
4704*0Sstevel@tonic-gate
4705*0Sstevel@tonic-gateThe B<-charset> parameter can be used to control the character set
4706*0Sstevel@tonic-gatesent to the browser.  If not provided, defaults to ISO-8859-1.  As a
4707*0Sstevel@tonic-gateside effect, this sets the charset() method as well.
4708*0Sstevel@tonic-gate
4709*0Sstevel@tonic-gateThe B<-attachment> parameter can be used to turn the page into an
4710*0Sstevel@tonic-gateattachment.  Instead of displaying the page, some browsers will prompt
4711*0Sstevel@tonic-gatethe user to save it to disk.  The value of the argument is the
4712*0Sstevel@tonic-gatesuggested name for the saved file.  In order for this to work, you may
4713*0Sstevel@tonic-gatehave to set the B<-type> to "application/octet-stream".
4714*0Sstevel@tonic-gate
4715*0Sstevel@tonic-gateThe B<-p3p> parameter will add a P3P tag to the outgoing header.  The
4716*0Sstevel@tonic-gateparameter can be an arrayref or a space-delimited string of P3P tags.
4717*0Sstevel@tonic-gateFor example:
4718*0Sstevel@tonic-gate
4719*0Sstevel@tonic-gate   print header(-p3p=>[qw(CAO DSP LAW CURa)]);
4720*0Sstevel@tonic-gate   print header(-p3p=>'CAO DSP LAW CURa');
4721*0Sstevel@tonic-gate
4722*0Sstevel@tonic-gateIn either case, the outgoing header will be formatted as:
4723*0Sstevel@tonic-gate
4724*0Sstevel@tonic-gate  P3P: policyref="/w3c/p3p.xml" cp="CAO DSP LAW CURa"
4725*0Sstevel@tonic-gate
4726*0Sstevel@tonic-gate=head2 GENERATING A REDIRECTION HEADER
4727*0Sstevel@tonic-gate
4728*0Sstevel@tonic-gate   print $query->redirect('http://somewhere.else/in/movie/land');
4729*0Sstevel@tonic-gate
4730*0Sstevel@tonic-gateSometimes you don't want to produce a document yourself, but simply
4731*0Sstevel@tonic-gateredirect the browser elsewhere, perhaps choosing a URL based on the
4732*0Sstevel@tonic-gatetime of day or the identity of the user.
4733*0Sstevel@tonic-gate
4734*0Sstevel@tonic-gateThe redirect() function redirects the browser to a different URL.  If
4735*0Sstevel@tonic-gateyou use redirection like this, you should B<not> print out a header as
4736*0Sstevel@tonic-gatewell.
4737*0Sstevel@tonic-gate
4738*0Sstevel@tonic-gateYou should always use full URLs (including the http: or ftp: part) in
4739*0Sstevel@tonic-gateredirection requests.  Relative URLs will not work correctly.
4740*0Sstevel@tonic-gate
4741*0Sstevel@tonic-gateYou can also use named arguments:
4742*0Sstevel@tonic-gate
4743*0Sstevel@tonic-gate    print $query->redirect(-uri=>'http://somewhere.else/in/movie/land',
4744*0Sstevel@tonic-gate			   -nph=>1);
4745*0Sstevel@tonic-gate
4746*0Sstevel@tonic-gateThe B<-nph> parameter, if set to a true value, will issue the correct
4747*0Sstevel@tonic-gateheaders to work with a NPH (no-parse-header) script.  This is important
4748*0Sstevel@tonic-gateto use with certain servers, such as Microsoft IIS, which
4749*0Sstevel@tonic-gateexpect all their scripts to be NPH.
4750*0Sstevel@tonic-gate
4751*0Sstevel@tonic-gate=head2 CREATING THE HTML DOCUMENT HEADER
4752*0Sstevel@tonic-gate
4753*0Sstevel@tonic-gate   print $query->start_html(-title=>'Secrets of the Pyramids',
4754*0Sstevel@tonic-gate			    -author=>'fred@capricorn.org',
4755*0Sstevel@tonic-gate			    -base=>'true',
4756*0Sstevel@tonic-gate			    -target=>'_blank',
4757*0Sstevel@tonic-gate			    -meta=>{'keywords'=>'pharaoh secret mummy',
4758*0Sstevel@tonic-gate				    'copyright'=>'copyright 1996 King Tut'},
4759*0Sstevel@tonic-gate			    -style=>{'src'=>'/styles/style1.css'},
4760*0Sstevel@tonic-gate			    -BGCOLOR=>'blue');
4761*0Sstevel@tonic-gate
4762*0Sstevel@tonic-gateAfter creating the HTTP header, most CGI scripts will start writing
4763*0Sstevel@tonic-gateout an HTML document.  The start_html() routine creates the top of the
4764*0Sstevel@tonic-gatepage, along with a lot of optional information that controls the
4765*0Sstevel@tonic-gatepage's appearance and behavior.
4766*0Sstevel@tonic-gate
4767*0Sstevel@tonic-gateThis method returns a canned HTML header and the opening <body> tag.
4768*0Sstevel@tonic-gateAll parameters are optional.  In the named parameter form, recognized
4769*0Sstevel@tonic-gateparameters are -title, -author, -base, -xbase, -dtd, -lang and -target
4770*0Sstevel@tonic-gate(see below for the explanation).  Any additional parameters you
4771*0Sstevel@tonic-gateprovide, such as the Netscape unofficial BGCOLOR attribute, are added
4772*0Sstevel@tonic-gateto the <body> tag.  Additional parameters must be proceeded by a
4773*0Sstevel@tonic-gatehyphen.
4774*0Sstevel@tonic-gate
4775*0Sstevel@tonic-gateThe argument B<-xbase> allows you to provide an HREF for the <base> tag
4776*0Sstevel@tonic-gatedifferent from the current location, as in
4777*0Sstevel@tonic-gate
4778*0Sstevel@tonic-gate    -xbase=>"http://home.mcom.com/"
4779*0Sstevel@tonic-gate
4780*0Sstevel@tonic-gateAll relative links will be interpreted relative to this tag.
4781*0Sstevel@tonic-gate
4782*0Sstevel@tonic-gateThe argument B<-target> allows you to provide a default target frame
4783*0Sstevel@tonic-gatefor all the links and fill-out forms on the page.  B<This is a
4784*0Sstevel@tonic-gatenon-standard HTTP feature which only works with Netscape browsers!>
4785*0Sstevel@tonic-gateSee the Netscape documentation on frames for details of how to
4786*0Sstevel@tonic-gatemanipulate this.
4787*0Sstevel@tonic-gate
4788*0Sstevel@tonic-gate    -target=>"answer_window"
4789*0Sstevel@tonic-gate
4790*0Sstevel@tonic-gateAll relative links will be interpreted relative to this tag.
4791*0Sstevel@tonic-gateYou add arbitrary meta information to the header with the B<-meta>
4792*0Sstevel@tonic-gateargument.  This argument expects a reference to an associative array
4793*0Sstevel@tonic-gatecontaining name/value pairs of meta information.  These will be turned
4794*0Sstevel@tonic-gateinto a series of header <meta> tags that look something like this:
4795*0Sstevel@tonic-gate
4796*0Sstevel@tonic-gate    <meta name="keywords" content="pharaoh secret mummy">
4797*0Sstevel@tonic-gate    <meta name="description" content="copyright 1996 King Tut">
4798*0Sstevel@tonic-gate
4799*0Sstevel@tonic-gateTo create an HTTP-EQUIV type of <meta> tag, use B<-head>, described
4800*0Sstevel@tonic-gatebelow.
4801*0Sstevel@tonic-gate
4802*0Sstevel@tonic-gateThe B<-style> argument is used to incorporate cascading stylesheets
4803*0Sstevel@tonic-gateinto your code.  See the section on CASCADING STYLESHEETS for more
4804*0Sstevel@tonic-gateinformation.
4805*0Sstevel@tonic-gate
4806*0Sstevel@tonic-gateThe B<-lang> argument is used to incorporate a language attribute into
4807*0Sstevel@tonic-gatethe <html> tag.  The default if not specified is "en-US" for US
4808*0Sstevel@tonic-gateEnglish.  For example:
4809*0Sstevel@tonic-gate
4810*0Sstevel@tonic-gate    print $q->start_html(-lang=>'fr-CA');
4811*0Sstevel@tonic-gate
4812*0Sstevel@tonic-gateTo leave off the lang attribute, as you must do if you want to generate
4813*0Sstevel@tonic-gatelegal HTML 3.2 or earlier, pass the empty string (-lang=>'').
4814*0Sstevel@tonic-gate
4815*0Sstevel@tonic-gateThe B<-encoding> argument can be used to specify the character set for
4816*0Sstevel@tonic-gateXHTML.  It defaults to iso-8859-1 if not specified.
4817*0Sstevel@tonic-gate
4818*0Sstevel@tonic-gateYou can place other arbitrary HTML elements to the <head> section with the
4819*0Sstevel@tonic-gateB<-head> tag.  For example, to place the rarely-used <link> element in the
4820*0Sstevel@tonic-gatehead section, use this:
4821*0Sstevel@tonic-gate
4822*0Sstevel@tonic-gate    print start_html(-head=>Link({-rel=>'next',
4823*0Sstevel@tonic-gate		                  -href=>'http://www.capricorn.com/s2.html'}));
4824*0Sstevel@tonic-gate
4825*0Sstevel@tonic-gateTo incorporate multiple HTML elements into the <head> section, just pass an
4826*0Sstevel@tonic-gatearray reference:
4827*0Sstevel@tonic-gate
4828*0Sstevel@tonic-gate    print start_html(-head=>[
4829*0Sstevel@tonic-gate                             Link({-rel=>'next',
4830*0Sstevel@tonic-gate				   -href=>'http://www.capricorn.com/s2.html'}),
4831*0Sstevel@tonic-gate		             Link({-rel=>'previous',
4832*0Sstevel@tonic-gate				   -href=>'http://www.capricorn.com/s1.html'})
4833*0Sstevel@tonic-gate			     ]
4834*0Sstevel@tonic-gate		     );
4835*0Sstevel@tonic-gate
4836*0Sstevel@tonic-gateAnd here's how to create an HTTP-EQUIV <meta> tag:
4837*0Sstevel@tonic-gate
4838*0Sstevel@tonic-gate      print start_html(-head=>meta({-http_equiv => 'Content-Type',
4839*0Sstevel@tonic-gate                                    -content    => 'text/html'}))
4840*0Sstevel@tonic-gate
4841*0Sstevel@tonic-gate
4842*0Sstevel@tonic-gateJAVASCRIPTING: The B<-script>, B<-noScript>, B<-onLoad>,
4843*0Sstevel@tonic-gateB<-onMouseOver>, B<-onMouseOut> and B<-onUnload> parameters are used
4844*0Sstevel@tonic-gateto add Netscape JavaScript calls to your pages.  B<-script> should
4845*0Sstevel@tonic-gatepoint to a block of text containing JavaScript function definitions.
4846*0Sstevel@tonic-gateThis block will be placed within a <script> block inside the HTML (not
4847*0Sstevel@tonic-gateHTTP) header.  The block is placed in the header in order to give your
4848*0Sstevel@tonic-gatepage a fighting chance of having all its JavaScript functions in place
4849*0Sstevel@tonic-gateeven if the user presses the stop button before the page has loaded
4850*0Sstevel@tonic-gatecompletely.  CGI.pm attempts to format the script in such a way that
4851*0Sstevel@tonic-gateJavaScript-naive browsers will not choke on the code: unfortunately
4852*0Sstevel@tonic-gatethere are some browsers, such as Chimera for Unix, that get confused
4853*0Sstevel@tonic-gateby it nevertheless.
4854*0Sstevel@tonic-gate
4855*0Sstevel@tonic-gateThe B<-onLoad> and B<-onUnload> parameters point to fragments of JavaScript
4856*0Sstevel@tonic-gatecode to execute when the page is respectively opened and closed by the
4857*0Sstevel@tonic-gatebrowser.  Usually these parameters are calls to functions defined in the
4858*0Sstevel@tonic-gateB<-script> field:
4859*0Sstevel@tonic-gate
4860*0Sstevel@tonic-gate      $query = new CGI;
4861*0Sstevel@tonic-gate      print $query->header;
4862*0Sstevel@tonic-gate      $JSCRIPT=<<END;
4863*0Sstevel@tonic-gate      // Ask a silly question
4864*0Sstevel@tonic-gate      function riddle_me_this() {
4865*0Sstevel@tonic-gate	 var r = prompt("What walks on four legs in the morning, " +
4866*0Sstevel@tonic-gate		       "two legs in the afternoon, " +
4867*0Sstevel@tonic-gate		       "and three legs in the evening?");
4868*0Sstevel@tonic-gate	 response(r);
4869*0Sstevel@tonic-gate      }
4870*0Sstevel@tonic-gate      // Get a silly answer
4871*0Sstevel@tonic-gate      function response(answer) {
4872*0Sstevel@tonic-gate	 if (answer == "man")
4873*0Sstevel@tonic-gate	    alert("Right you are!");
4874*0Sstevel@tonic-gate	 else
4875*0Sstevel@tonic-gate	    alert("Wrong!  Guess again.");
4876*0Sstevel@tonic-gate      }
4877*0Sstevel@tonic-gate      END
4878*0Sstevel@tonic-gate      print $query->start_html(-title=>'The Riddle of the Sphinx',
4879*0Sstevel@tonic-gate			       -script=>$JSCRIPT);
4880*0Sstevel@tonic-gate
4881*0Sstevel@tonic-gateUse the B<-noScript> parameter to pass some HTML text that will be displayed on
4882*0Sstevel@tonic-gatebrowsers that do not have JavaScript (or browsers where JavaScript is turned
4883*0Sstevel@tonic-gateoff).
4884*0Sstevel@tonic-gate
4885*0Sstevel@tonic-gateNetscape 3.0 recognizes several attributes of the <script> tag,
4886*0Sstevel@tonic-gateincluding LANGUAGE and SRC.  The latter is particularly interesting,
4887*0Sstevel@tonic-gateas it allows you to keep the JavaScript code in a file or CGI script
4888*0Sstevel@tonic-gaterather than cluttering up each page with the source.  To use these
4889*0Sstevel@tonic-gateattributes pass a HASH reference in the B<-script> parameter containing
4890*0Sstevel@tonic-gateone or more of -language, -src, or -code:
4891*0Sstevel@tonic-gate
4892*0Sstevel@tonic-gate    print $q->start_html(-title=>'The Riddle of the Sphinx',
4893*0Sstevel@tonic-gate			 -script=>{-language=>'JAVASCRIPT',
4894*0Sstevel@tonic-gate                                   -src=>'/javascript/sphinx.js'}
4895*0Sstevel@tonic-gate			 );
4896*0Sstevel@tonic-gate
4897*0Sstevel@tonic-gate    print $q->(-title=>'The Riddle of the Sphinx',
4898*0Sstevel@tonic-gate	       -script=>{-language=>'PERLSCRIPT',
4899*0Sstevel@tonic-gate			 -code=>'print "hello world!\n;"'}
4900*0Sstevel@tonic-gate	       );
4901*0Sstevel@tonic-gate
4902*0Sstevel@tonic-gate
4903*0Sstevel@tonic-gateA final feature allows you to incorporate multiple <script> sections into the
4904*0Sstevel@tonic-gateheader.  Just pass the list of script sections as an array reference.
4905*0Sstevel@tonic-gatethis allows you to specify different source files for different dialects
4906*0Sstevel@tonic-gateof JavaScript.  Example:
4907*0Sstevel@tonic-gate
4908*0Sstevel@tonic-gate     print $q->start_html(-title=>'The Riddle of the Sphinx',
4909*0Sstevel@tonic-gate                          -script=>[
4910*0Sstevel@tonic-gate                                    { -language => 'JavaScript1.0',
4911*0Sstevel@tonic-gate                                      -src      => '/javascript/utilities10.js'
4912*0Sstevel@tonic-gate                                    },
4913*0Sstevel@tonic-gate                                    { -language => 'JavaScript1.1',
4914*0Sstevel@tonic-gate                                      -src      => '/javascript/utilities11.js'
4915*0Sstevel@tonic-gate                                    },
4916*0Sstevel@tonic-gate                                    { -language => 'JavaScript1.2',
4917*0Sstevel@tonic-gate                                      -src      => '/javascript/utilities12.js'
4918*0Sstevel@tonic-gate                                    },
4919*0Sstevel@tonic-gate                                    { -language => 'JavaScript28.2',
4920*0Sstevel@tonic-gate                                      -src      => '/javascript/utilities219.js'
4921*0Sstevel@tonic-gate                                    }
4922*0Sstevel@tonic-gate                                 ]
4923*0Sstevel@tonic-gate                             );
4924*0Sstevel@tonic-gate
4925*0Sstevel@tonic-gateIf this looks a bit extreme, take my advice and stick with straight CGI scripting.
4926*0Sstevel@tonic-gate
4927*0Sstevel@tonic-gateSee
4928*0Sstevel@tonic-gate
4929*0Sstevel@tonic-gate   http://home.netscape.com/eng/mozilla/2.0/handbook/javascript/
4930*0Sstevel@tonic-gate
4931*0Sstevel@tonic-gatefor more information about JavaScript.
4932*0Sstevel@tonic-gate
4933*0Sstevel@tonic-gateThe old-style positional parameters are as follows:
4934*0Sstevel@tonic-gate
4935*0Sstevel@tonic-gate=over 4
4936*0Sstevel@tonic-gate
4937*0Sstevel@tonic-gate=item B<Parameters:>
4938*0Sstevel@tonic-gate
4939*0Sstevel@tonic-gate=item 1.
4940*0Sstevel@tonic-gate
4941*0Sstevel@tonic-gateThe title
4942*0Sstevel@tonic-gate
4943*0Sstevel@tonic-gate=item 2.
4944*0Sstevel@tonic-gate
4945*0Sstevel@tonic-gateThe author's e-mail address (will create a <link rev="MADE"> tag if present
4946*0Sstevel@tonic-gate
4947*0Sstevel@tonic-gate=item 3.
4948*0Sstevel@tonic-gate
4949*0Sstevel@tonic-gateA 'true' flag if you want to include a <base> tag in the header.  This
4950*0Sstevel@tonic-gatehelps resolve relative addresses to absolute ones when the document is moved,
4951*0Sstevel@tonic-gatebut makes the document hierarchy non-portable.  Use with care!
4952*0Sstevel@tonic-gate
4953*0Sstevel@tonic-gate=item 4, 5, 6...
4954*0Sstevel@tonic-gate
4955*0Sstevel@tonic-gateAny other parameters you want to include in the <body> tag.  This is a good
4956*0Sstevel@tonic-gateplace to put Netscape extensions, such as colors and wallpaper patterns.
4957*0Sstevel@tonic-gate
4958*0Sstevel@tonic-gate=back
4959*0Sstevel@tonic-gate
4960*0Sstevel@tonic-gate=head2 ENDING THE HTML DOCUMENT:
4961*0Sstevel@tonic-gate
4962*0Sstevel@tonic-gate	print $query->end_html
4963*0Sstevel@tonic-gate
4964*0Sstevel@tonic-gateThis ends an HTML document by printing the </body></html> tags.
4965*0Sstevel@tonic-gate
4966*0Sstevel@tonic-gate=head2 CREATING A SELF-REFERENCING URL THAT PRESERVES STATE INFORMATION:
4967*0Sstevel@tonic-gate
4968*0Sstevel@tonic-gate    $myself = $query->self_url;
4969*0Sstevel@tonic-gate    print q(<a href="$myself">I'm talking to myself.</a>);
4970*0Sstevel@tonic-gate
4971*0Sstevel@tonic-gateself_url() will return a URL, that, when selected, will reinvoke
4972*0Sstevel@tonic-gatethis script with all its state information intact.  This is most
4973*0Sstevel@tonic-gateuseful when you want to jump around within the document using
4974*0Sstevel@tonic-gateinternal anchors but you don't want to disrupt the current contents
4975*0Sstevel@tonic-gateof the form(s).  Something like this will do the trick.
4976*0Sstevel@tonic-gate
4977*0Sstevel@tonic-gate     $myself = $query->self_url;
4978*0Sstevel@tonic-gate     print "<a href=\"$myself#table1\">See table 1</a>";
4979*0Sstevel@tonic-gate     print "<a href=\"$myself#table2\">See table 2</a>";
4980*0Sstevel@tonic-gate     print "<a href=\"$myself#yourself\">See for yourself</a>";
4981*0Sstevel@tonic-gate
4982*0Sstevel@tonic-gateIf you want more control over what's returned, using the B<url()>
4983*0Sstevel@tonic-gatemethod instead.
4984*0Sstevel@tonic-gate
4985*0Sstevel@tonic-gateYou can also retrieve the unprocessed query string with query_string():
4986*0Sstevel@tonic-gate
4987*0Sstevel@tonic-gate    $the_string = $query->query_string;
4988*0Sstevel@tonic-gate
4989*0Sstevel@tonic-gate=head2 OBTAINING THE SCRIPT'S URL
4990*0Sstevel@tonic-gate
4991*0Sstevel@tonic-gate    $full_url      = $query->url();
4992*0Sstevel@tonic-gate    $full_url      = $query->url(-full=>1);  #alternative syntax
4993*0Sstevel@tonic-gate    $relative_url  = $query->url(-relative=>1);
4994*0Sstevel@tonic-gate    $absolute_url  = $query->url(-absolute=>1);
4995*0Sstevel@tonic-gate    $url_with_path = $query->url(-path_info=>1);
4996*0Sstevel@tonic-gate    $url_with_path_and_query = $query->url(-path_info=>1,-query=>1);
4997*0Sstevel@tonic-gate    $netloc        = $query->url(-base => 1);
4998*0Sstevel@tonic-gate
4999*0Sstevel@tonic-gateB<url()> returns the script's URL in a variety of formats.  Called
5000*0Sstevel@tonic-gatewithout any arguments, it returns the full form of the URL, including
5001*0Sstevel@tonic-gatehost name and port number
5002*0Sstevel@tonic-gate
5003*0Sstevel@tonic-gate    http://your.host.com/path/to/script.cgi
5004*0Sstevel@tonic-gate
5005*0Sstevel@tonic-gateYou can modify this format with the following named arguments:
5006*0Sstevel@tonic-gate
5007*0Sstevel@tonic-gate=over 4
5008*0Sstevel@tonic-gate
5009*0Sstevel@tonic-gate=item B<-absolute>
5010*0Sstevel@tonic-gate
5011*0Sstevel@tonic-gateIf true, produce an absolute URL, e.g.
5012*0Sstevel@tonic-gate
5013*0Sstevel@tonic-gate    /path/to/script.cgi
5014*0Sstevel@tonic-gate
5015*0Sstevel@tonic-gate=item B<-relative>
5016*0Sstevel@tonic-gate
5017*0Sstevel@tonic-gateProduce a relative URL.  This is useful if you want to reinvoke your
5018*0Sstevel@tonic-gatescript with different parameters. For example:
5019*0Sstevel@tonic-gate
5020*0Sstevel@tonic-gate    script.cgi
5021*0Sstevel@tonic-gate
5022*0Sstevel@tonic-gate=item B<-full>
5023*0Sstevel@tonic-gate
5024*0Sstevel@tonic-gateProduce the full URL, exactly as if called without any arguments.
5025*0Sstevel@tonic-gateThis overrides the -relative and -absolute arguments.
5026*0Sstevel@tonic-gate
5027*0Sstevel@tonic-gate=item B<-path> (B<-path_info>)
5028*0Sstevel@tonic-gate
5029*0Sstevel@tonic-gateAppend the additional path information to the URL.  This can be
5030*0Sstevel@tonic-gatecombined with B<-full>, B<-absolute> or B<-relative>.  B<-path_info>
5031*0Sstevel@tonic-gateis provided as a synonym.
5032*0Sstevel@tonic-gate
5033*0Sstevel@tonic-gate=item B<-query> (B<-query_string>)
5034*0Sstevel@tonic-gate
5035*0Sstevel@tonic-gateAppend the query string to the URL.  This can be combined with
5036*0Sstevel@tonic-gateB<-full>, B<-absolute> or B<-relative>.  B<-query_string> is provided
5037*0Sstevel@tonic-gateas a synonym.
5038*0Sstevel@tonic-gate
5039*0Sstevel@tonic-gate=item B<-base>
5040*0Sstevel@tonic-gate
5041*0Sstevel@tonic-gateGenerate just the protocol and net location, as in http://www.foo.com:8000
5042*0Sstevel@tonic-gate
5043*0Sstevel@tonic-gate=back
5044*0Sstevel@tonic-gate
5045*0Sstevel@tonic-gate=head2 MIXING POST AND URL PARAMETERS
5046*0Sstevel@tonic-gate
5047*0Sstevel@tonic-gate   $color = $query->url_param('color');
5048*0Sstevel@tonic-gate
5049*0Sstevel@tonic-gateIt is possible for a script to receive CGI parameters in the URL as
5050*0Sstevel@tonic-gatewell as in the fill-out form by creating a form that POSTs to a URL
5051*0Sstevel@tonic-gatecontaining a query string (a "?" mark followed by arguments).  The
5052*0Sstevel@tonic-gateB<param()> method will always return the contents of the POSTed
5053*0Sstevel@tonic-gatefill-out form, ignoring the URL's query string.  To retrieve URL
5054*0Sstevel@tonic-gateparameters, call the B<url_param()> method.  Use it in the same way as
5055*0Sstevel@tonic-gateB<param()>.  The main difference is that it allows you to read the
5056*0Sstevel@tonic-gateparameters, but not set them.
5057*0Sstevel@tonic-gate
5058*0Sstevel@tonic-gate
5059*0Sstevel@tonic-gateUnder no circumstances will the contents of the URL query string
5060*0Sstevel@tonic-gateinterfere with similarly-named CGI parameters in POSTed forms.  If you
5061*0Sstevel@tonic-gatetry to mix a URL query string with a form submitted with the GET
5062*0Sstevel@tonic-gatemethod, the results will not be what you expect.
5063*0Sstevel@tonic-gate
5064*0Sstevel@tonic-gate=head1 CREATING STANDARD HTML ELEMENTS:
5065*0Sstevel@tonic-gate
5066*0Sstevel@tonic-gateCGI.pm defines general HTML shortcut methods for most, if not all of
5067*0Sstevel@tonic-gatethe HTML 3 and HTML 4 tags.  HTML shortcuts are named after a single
5068*0Sstevel@tonic-gateHTML element and return a fragment of HTML text that you can then
5069*0Sstevel@tonic-gateprint or manipulate as you like.  Each shortcut returns a fragment of
5070*0Sstevel@tonic-gateHTML code that you can append to a string, save to a file, or, most
5071*0Sstevel@tonic-gatecommonly, print out so that it displays in the browser window.
5072*0Sstevel@tonic-gate
5073*0Sstevel@tonic-gateThis example shows how to use the HTML methods:
5074*0Sstevel@tonic-gate
5075*0Sstevel@tonic-gate   $q = new CGI;
5076*0Sstevel@tonic-gate   print $q->blockquote(
5077*0Sstevel@tonic-gate		     "Many years ago on the island of",
5078*0Sstevel@tonic-gate		     $q->a({href=>"http://crete.org/"},"Crete"),
5079*0Sstevel@tonic-gate		     "there lived a Minotaur named",
5080*0Sstevel@tonic-gate		     $q->strong("Fred."),
5081*0Sstevel@tonic-gate		    ),
5082*0Sstevel@tonic-gate       $q->hr;
5083*0Sstevel@tonic-gate
5084*0Sstevel@tonic-gateThis results in the following HTML code (extra newlines have been
5085*0Sstevel@tonic-gateadded for readability):
5086*0Sstevel@tonic-gate
5087*0Sstevel@tonic-gate   <blockquote>
5088*0Sstevel@tonic-gate   Many years ago on the island of
5089*0Sstevel@tonic-gate   <a href="http://crete.org/">Crete</a> there lived
5090*0Sstevel@tonic-gate   a minotaur named <strong>Fred.</strong>
5091*0Sstevel@tonic-gate   </blockquote>
5092*0Sstevel@tonic-gate   <hr>
5093*0Sstevel@tonic-gate
5094*0Sstevel@tonic-gateIf you find the syntax for calling the HTML shortcuts awkward, you can
5095*0Sstevel@tonic-gateimport them into your namespace and dispense with the object syntax
5096*0Sstevel@tonic-gatecompletely (see the next section for more details):
5097*0Sstevel@tonic-gate
5098*0Sstevel@tonic-gate   use CGI ':standard';
5099*0Sstevel@tonic-gate   print blockquote(
5100*0Sstevel@tonic-gate      "Many years ago on the island of",
5101*0Sstevel@tonic-gate      a({href=>"http://crete.org/"},"Crete"),
5102*0Sstevel@tonic-gate      "there lived a minotaur named",
5103*0Sstevel@tonic-gate      strong("Fred."),
5104*0Sstevel@tonic-gate      ),
5105*0Sstevel@tonic-gate      hr;
5106*0Sstevel@tonic-gate
5107*0Sstevel@tonic-gate=head2 PROVIDING ARGUMENTS TO HTML SHORTCUTS
5108*0Sstevel@tonic-gate
5109*0Sstevel@tonic-gateThe HTML methods will accept zero, one or multiple arguments.  If you
5110*0Sstevel@tonic-gateprovide no arguments, you get a single tag:
5111*0Sstevel@tonic-gate
5112*0Sstevel@tonic-gate   print hr;  	#  <hr>
5113*0Sstevel@tonic-gate
5114*0Sstevel@tonic-gateIf you provide one or more string arguments, they are concatenated
5115*0Sstevel@tonic-gatetogether with spaces and placed between opening and closing tags:
5116*0Sstevel@tonic-gate
5117*0Sstevel@tonic-gate   print h1("Chapter","1"); # <h1>Chapter 1</h1>"
5118*0Sstevel@tonic-gate
5119*0Sstevel@tonic-gateIf the first argument is an associative array reference, then the keys
5120*0Sstevel@tonic-gateand values of the associative array become the HTML tag's attributes:
5121*0Sstevel@tonic-gate
5122*0Sstevel@tonic-gate   print a({-href=>'fred.html',-target=>'_new'},
5123*0Sstevel@tonic-gate      "Open a new frame");
5124*0Sstevel@tonic-gate
5125*0Sstevel@tonic-gate	    <a href="fred.html",target="_new">Open a new frame</a>
5126*0Sstevel@tonic-gate
5127*0Sstevel@tonic-gateYou may dispense with the dashes in front of the attribute names if
5128*0Sstevel@tonic-gateyou prefer:
5129*0Sstevel@tonic-gate
5130*0Sstevel@tonic-gate   print img {src=>'fred.gif',align=>'LEFT'};
5131*0Sstevel@tonic-gate
5132*0Sstevel@tonic-gate	   <img align="LEFT" src="fred.gif">
5133*0Sstevel@tonic-gate
5134*0Sstevel@tonic-gateSometimes an HTML tag attribute has no argument.  For example, ordered
5135*0Sstevel@tonic-gatelists can be marked as COMPACT.  The syntax for this is an argument that
5136*0Sstevel@tonic-gatethat points to an undef string:
5137*0Sstevel@tonic-gate
5138*0Sstevel@tonic-gate   print ol({compact=>undef},li('one'),li('two'),li('three'));
5139*0Sstevel@tonic-gate
5140*0Sstevel@tonic-gatePrior to CGI.pm version 2.41, providing an empty ('') string as an
5141*0Sstevel@tonic-gateattribute argument was the same as providing undef.  However, this has
5142*0Sstevel@tonic-gatechanged in order to accommodate those who want to create tags of the form
5143*0Sstevel@tonic-gate<img alt="">.  The difference is shown in these two pieces of code:
5144*0Sstevel@tonic-gate
5145*0Sstevel@tonic-gate   CODE                   RESULT
5146*0Sstevel@tonic-gate   img({alt=>undef})      <img alt>
5147*0Sstevel@tonic-gate   img({alt=>''})         <img alt="">
5148*0Sstevel@tonic-gate
5149*0Sstevel@tonic-gate=head2 THE DISTRIBUTIVE PROPERTY OF HTML SHORTCUTS
5150*0Sstevel@tonic-gate
5151*0Sstevel@tonic-gateOne of the cool features of the HTML shortcuts is that they are
5152*0Sstevel@tonic-gatedistributive.  If you give them an argument consisting of a
5153*0Sstevel@tonic-gateB<reference> to a list, the tag will be distributed across each
5154*0Sstevel@tonic-gateelement of the list.  For example, here's one way to make an ordered
5155*0Sstevel@tonic-gatelist:
5156*0Sstevel@tonic-gate
5157*0Sstevel@tonic-gate   print ul(
5158*0Sstevel@tonic-gate             li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy'])
5159*0Sstevel@tonic-gate           );
5160*0Sstevel@tonic-gate
5161*0Sstevel@tonic-gateThis example will result in HTML output that looks like this:
5162*0Sstevel@tonic-gate
5163*0Sstevel@tonic-gate   <ul>
5164*0Sstevel@tonic-gate     <li type="disc">Sneezy</li>
5165*0Sstevel@tonic-gate     <li type="disc">Doc</li>
5166*0Sstevel@tonic-gate     <li type="disc">Sleepy</li>
5167*0Sstevel@tonic-gate     <li type="disc">Happy</li>
5168*0Sstevel@tonic-gate   </ul>
5169*0Sstevel@tonic-gate
5170*0Sstevel@tonic-gateThis is extremely useful for creating tables.  For example:
5171*0Sstevel@tonic-gate
5172*0Sstevel@tonic-gate   print table({-border=>undef},
5173*0Sstevel@tonic-gate           caption('When Should You Eat Your Vegetables?'),
5174*0Sstevel@tonic-gate           Tr({-align=>CENTER,-valign=>TOP},
5175*0Sstevel@tonic-gate           [
5176*0Sstevel@tonic-gate              th(['Vegetable', 'Breakfast','Lunch','Dinner']),
5177*0Sstevel@tonic-gate              td(['Tomatoes' , 'no', 'yes', 'yes']),
5178*0Sstevel@tonic-gate              td(['Broccoli' , 'no', 'no',  'yes']),
5179*0Sstevel@tonic-gate              td(['Onions'   , 'yes','yes', 'yes'])
5180*0Sstevel@tonic-gate           ]
5181*0Sstevel@tonic-gate           )
5182*0Sstevel@tonic-gate        );
5183*0Sstevel@tonic-gate
5184*0Sstevel@tonic-gate=head2 HTML SHORTCUTS AND LIST INTERPOLATION
5185*0Sstevel@tonic-gate
5186*0Sstevel@tonic-gateConsider this bit of code:
5187*0Sstevel@tonic-gate
5188*0Sstevel@tonic-gate   print blockquote(em('Hi'),'mom!'));
5189*0Sstevel@tonic-gate
5190*0Sstevel@tonic-gateIt will ordinarily return the string that you probably expect, namely:
5191*0Sstevel@tonic-gate
5192*0Sstevel@tonic-gate   <blockquote><em>Hi</em> mom!</blockquote>
5193*0Sstevel@tonic-gate
5194*0Sstevel@tonic-gateNote the space between the element "Hi" and the element "mom!".
5195*0Sstevel@tonic-gateCGI.pm puts the extra space there using array interpolation, which is
5196*0Sstevel@tonic-gatecontrolled by the magic $" variable.  Sometimes this extra space is
5197*0Sstevel@tonic-gatenot what you want, for example, when you are trying to align a series
5198*0Sstevel@tonic-gateof images.  In this case, you can simply change the value of $" to an
5199*0Sstevel@tonic-gateempty string.
5200*0Sstevel@tonic-gate
5201*0Sstevel@tonic-gate   {
5202*0Sstevel@tonic-gate      local($") = '';
5203*0Sstevel@tonic-gate      print blockquote(em('Hi'),'mom!'));
5204*0Sstevel@tonic-gate    }
5205*0Sstevel@tonic-gate
5206*0Sstevel@tonic-gateI suggest you put the code in a block as shown here.  Otherwise the
5207*0Sstevel@tonic-gatechange to $" will affect all subsequent code until you explicitly
5208*0Sstevel@tonic-gatereset it.
5209*0Sstevel@tonic-gate
5210*0Sstevel@tonic-gate=head2 NON-STANDARD HTML SHORTCUTS
5211*0Sstevel@tonic-gate
5212*0Sstevel@tonic-gateA few HTML tags don't follow the standard pattern for various
5213*0Sstevel@tonic-gatereasons.
5214*0Sstevel@tonic-gate
5215*0Sstevel@tonic-gateB<comment()> generates an HTML comment (<!-- comment -->).  Call it
5216*0Sstevel@tonic-gatelike
5217*0Sstevel@tonic-gate
5218*0Sstevel@tonic-gate    print comment('here is my comment');
5219*0Sstevel@tonic-gate
5220*0Sstevel@tonic-gateBecause of conflicts with built-in Perl functions, the following functions
5221*0Sstevel@tonic-gatebegin with initial caps:
5222*0Sstevel@tonic-gate
5223*0Sstevel@tonic-gate    Select
5224*0Sstevel@tonic-gate    Tr
5225*0Sstevel@tonic-gate    Link
5226*0Sstevel@tonic-gate    Delete
5227*0Sstevel@tonic-gate    Accept
5228*0Sstevel@tonic-gate    Sub
5229*0Sstevel@tonic-gate
5230*0Sstevel@tonic-gateIn addition, start_html(), end_html(), start_form(), end_form(),
5231*0Sstevel@tonic-gatestart_multipart_form() and all the fill-out form tags are special.
5232*0Sstevel@tonic-gateSee their respective sections.
5233*0Sstevel@tonic-gate
5234*0Sstevel@tonic-gate=head2 AUTOESCAPING HTML
5235*0Sstevel@tonic-gate
5236*0Sstevel@tonic-gateBy default, all HTML that is emitted by the form-generating functions
5237*0Sstevel@tonic-gateis passed through a function called escapeHTML():
5238*0Sstevel@tonic-gate
5239*0Sstevel@tonic-gate=over 4
5240*0Sstevel@tonic-gate
5241*0Sstevel@tonic-gate=item $escaped_string = escapeHTML("unescaped string");
5242*0Sstevel@tonic-gate
5243*0Sstevel@tonic-gateEscape HTML formatting characters in a string.
5244*0Sstevel@tonic-gate
5245*0Sstevel@tonic-gate=back
5246*0Sstevel@tonic-gate
5247*0Sstevel@tonic-gateProvided that you have specified a character set of ISO-8859-1 (the
5248*0Sstevel@tonic-gatedefault), the standard HTML escaping rules will be used.  The "<"
5249*0Sstevel@tonic-gatecharacter becomes "&lt;", ">" becomes "&gt;", "&" becomes "&amp;", and
5250*0Sstevel@tonic-gatethe quote character becomes "&quot;".  In addition, the hexadecimal
5251*0Sstevel@tonic-gate0x8b and 0x9b characters, which some browsers incorrectly interpret
5252*0Sstevel@tonic-gateas the left and right angle-bracket characters, are replaced by their
5253*0Sstevel@tonic-gatenumeric character entities ("&#8249" and "&#8250;").  If you manually change
5254*0Sstevel@tonic-gatethe charset, either by calling the charset() method explicitly or by
5255*0Sstevel@tonic-gatepassing a -charset argument to header(), then B<all> characters will
5256*0Sstevel@tonic-gatebe replaced by their numeric entities, since CGI.pm has no lookup
5257*0Sstevel@tonic-gatetable for all the possible encodings.
5258*0Sstevel@tonic-gate
5259*0Sstevel@tonic-gateThe automatic escaping does not apply to other shortcuts, such as
5260*0Sstevel@tonic-gateh1().  You should call escapeHTML() yourself on untrusted data in
5261*0Sstevel@tonic-gateorder to protect your pages against nasty tricks that people may enter
5262*0Sstevel@tonic-gateinto guestbooks, etc..  To change the character set, use charset().
5263*0Sstevel@tonic-gateTo turn autoescaping off completely, use autoEscape(0):
5264*0Sstevel@tonic-gate
5265*0Sstevel@tonic-gate=over 4
5266*0Sstevel@tonic-gate
5267*0Sstevel@tonic-gate=item $charset = charset([$charset]);
5268*0Sstevel@tonic-gate
5269*0Sstevel@tonic-gateGet or set the current character set.
5270*0Sstevel@tonic-gate
5271*0Sstevel@tonic-gate=item $flag = autoEscape([$flag]);
5272*0Sstevel@tonic-gate
5273*0Sstevel@tonic-gateGet or set the value of the autoescape flag.
5274*0Sstevel@tonic-gate
5275*0Sstevel@tonic-gate=back
5276*0Sstevel@tonic-gate
5277*0Sstevel@tonic-gate=head2 PRETTY-PRINTING HTML
5278*0Sstevel@tonic-gate
5279*0Sstevel@tonic-gateBy default, all the HTML produced by these functions comes out as one
5280*0Sstevel@tonic-gatelong line without carriage returns or indentation. This is yuck, but
5281*0Sstevel@tonic-gateit does reduce the size of the documents by 10-20%.  To get
5282*0Sstevel@tonic-gatepretty-printed output, please use L<CGI::Pretty>, a subclass
5283*0Sstevel@tonic-gatecontributed by Brian Paulsen.
5284*0Sstevel@tonic-gate
5285*0Sstevel@tonic-gate=head1 CREATING FILL-OUT FORMS:
5286*0Sstevel@tonic-gate
5287*0Sstevel@tonic-gateI<General note>  The various form-creating methods all return strings
5288*0Sstevel@tonic-gateto the caller, containing the tag or tags that will create the requested
5289*0Sstevel@tonic-gateform element.  You are responsible for actually printing out these strings.
5290*0Sstevel@tonic-gateIt's set up this way so that you can place formatting tags
5291*0Sstevel@tonic-gatearound the form elements.
5292*0Sstevel@tonic-gate
5293*0Sstevel@tonic-gateI<Another note> The default values that you specify for the forms are only
5294*0Sstevel@tonic-gateused the B<first> time the script is invoked (when there is no query
5295*0Sstevel@tonic-gatestring).  On subsequent invocations of the script (when there is a query
5296*0Sstevel@tonic-gatestring), the former values are used even if they are blank.
5297*0Sstevel@tonic-gate
5298*0Sstevel@tonic-gateIf you want to change the value of a field from its previous value, you have two
5299*0Sstevel@tonic-gatechoices:
5300*0Sstevel@tonic-gate
5301*0Sstevel@tonic-gate(1) call the param() method to set it.
5302*0Sstevel@tonic-gate
5303*0Sstevel@tonic-gate(2) use the -override (alias -force) parameter (a new feature in version 2.15).
5304*0Sstevel@tonic-gateThis forces the default value to be used, regardless of the previous value:
5305*0Sstevel@tonic-gate
5306*0Sstevel@tonic-gate   print $query->textfield(-name=>'field_name',
5307*0Sstevel@tonic-gate			   -default=>'starting value',
5308*0Sstevel@tonic-gate			   -override=>1,
5309*0Sstevel@tonic-gate			   -size=>50,
5310*0Sstevel@tonic-gate			   -maxlength=>80);
5311*0Sstevel@tonic-gate
5312*0Sstevel@tonic-gateI<Yet another note> By default, the text and labels of form elements are
5313*0Sstevel@tonic-gateescaped according to HTML rules.  This means that you can safely use
5314*0Sstevel@tonic-gate"<CLICK ME>" as the label for a button.  However, it also interferes with
5315*0Sstevel@tonic-gateyour ability to incorporate special HTML character sequences, such as &Aacute;,
5316*0Sstevel@tonic-gateinto your fields.  If you wish to turn off automatic escaping, call the
5317*0Sstevel@tonic-gateautoEscape() method with a false value immediately after creating the CGI object:
5318*0Sstevel@tonic-gate
5319*0Sstevel@tonic-gate   $query = new CGI;
5320*0Sstevel@tonic-gate   $query->autoEscape(undef);
5321*0Sstevel@tonic-gate
5322*0Sstevel@tonic-gate=head2 CREATING AN ISINDEX TAG
5323*0Sstevel@tonic-gate
5324*0Sstevel@tonic-gate   print $query->isindex(-action=>$action);
5325*0Sstevel@tonic-gate
5326*0Sstevel@tonic-gate	 -or-
5327*0Sstevel@tonic-gate
5328*0Sstevel@tonic-gate   print $query->isindex($action);
5329*0Sstevel@tonic-gate
5330*0Sstevel@tonic-gatePrints out an <isindex> tag.  Not very exciting.  The parameter
5331*0Sstevel@tonic-gate-action specifies the URL of the script to process the query.  The
5332*0Sstevel@tonic-gatedefault is to process the query with the current script.
5333*0Sstevel@tonic-gate
5334*0Sstevel@tonic-gate=head2 STARTING AND ENDING A FORM
5335*0Sstevel@tonic-gate
5336*0Sstevel@tonic-gate    print $query->start_form(-method=>$method,
5337*0Sstevel@tonic-gate			    -action=>$action,
5338*0Sstevel@tonic-gate			    -enctype=>$encoding);
5339*0Sstevel@tonic-gate      <... various form stuff ...>
5340*0Sstevel@tonic-gate    print $query->endform;
5341*0Sstevel@tonic-gate
5342*0Sstevel@tonic-gate	-or-
5343*0Sstevel@tonic-gate
5344*0Sstevel@tonic-gate    print $query->start_form($method,$action,$encoding);
5345*0Sstevel@tonic-gate      <... various form stuff ...>
5346*0Sstevel@tonic-gate    print $query->endform;
5347*0Sstevel@tonic-gate
5348*0Sstevel@tonic-gatestart_form() will return a <form> tag with the optional method,
5349*0Sstevel@tonic-gateaction and form encoding that you specify.  The defaults are:
5350*0Sstevel@tonic-gate
5351*0Sstevel@tonic-gate    method: POST
5352*0Sstevel@tonic-gate    action: this script
5353*0Sstevel@tonic-gate    enctype: application/x-www-form-urlencoded
5354*0Sstevel@tonic-gate
5355*0Sstevel@tonic-gateendform() returns the closing </form> tag.
5356*0Sstevel@tonic-gate
5357*0Sstevel@tonic-gateStart_form()'s enctype argument tells the browser how to package the various
5358*0Sstevel@tonic-gatefields of the form before sending the form to the server.  Two
5359*0Sstevel@tonic-gatevalues are possible:
5360*0Sstevel@tonic-gate
5361*0Sstevel@tonic-gateB<Note:> This method was previously named startform(), and startform()
5362*0Sstevel@tonic-gateis still recognized as an alias.
5363*0Sstevel@tonic-gate
5364*0Sstevel@tonic-gate=over 4
5365*0Sstevel@tonic-gate
5366*0Sstevel@tonic-gate=item B<application/x-www-form-urlencoded>
5367*0Sstevel@tonic-gate
5368*0Sstevel@tonic-gateThis is the older type of encoding used by all browsers prior to
5369*0Sstevel@tonic-gateNetscape 2.0.  It is compatible with many CGI scripts and is
5370*0Sstevel@tonic-gatesuitable for short fields containing text data.  For your
5371*0Sstevel@tonic-gateconvenience, CGI.pm stores the name of this encoding
5372*0Sstevel@tonic-gatetype in B<&CGI::URL_ENCODED>.
5373*0Sstevel@tonic-gate
5374*0Sstevel@tonic-gate=item B<multipart/form-data>
5375*0Sstevel@tonic-gate
5376*0Sstevel@tonic-gateThis is the newer type of encoding introduced by Netscape 2.0.
5377*0Sstevel@tonic-gateIt is suitable for forms that contain very large fields or that
5378*0Sstevel@tonic-gateare intended for transferring binary data.  Most importantly,
5379*0Sstevel@tonic-gateit enables the "file upload" feature of Netscape 2.0 forms.  For
5380*0Sstevel@tonic-gateyour convenience, CGI.pm stores the name of this encoding type
5381*0Sstevel@tonic-gatein B<&CGI::MULTIPART>
5382*0Sstevel@tonic-gate
5383*0Sstevel@tonic-gateForms that use this type of encoding are not easily interpreted
5384*0Sstevel@tonic-gateby CGI scripts unless they use CGI.pm or another library designed
5385*0Sstevel@tonic-gateto handle them.
5386*0Sstevel@tonic-gate
5387*0Sstevel@tonic-gate=back
5388*0Sstevel@tonic-gate
5389*0Sstevel@tonic-gateFor compatibility, the start_form() method uses the older form of
5390*0Sstevel@tonic-gateencoding by default.  If you want to use the newer form of encoding
5391*0Sstevel@tonic-gateby default, you can call B<start_multipart_form()> instead of
5392*0Sstevel@tonic-gateB<start_form()>.
5393*0Sstevel@tonic-gate
5394*0Sstevel@tonic-gateJAVASCRIPTING: The B<-name> and B<-onSubmit> parameters are provided
5395*0Sstevel@tonic-gatefor use with JavaScript.  The -name parameter gives the
5396*0Sstevel@tonic-gateform a name so that it can be identified and manipulated by
5397*0Sstevel@tonic-gateJavaScript functions.  -onSubmit should point to a JavaScript
5398*0Sstevel@tonic-gatefunction that will be executed just before the form is submitted to your
5399*0Sstevel@tonic-gateserver.  You can use this opportunity to check the contents of the form
5400*0Sstevel@tonic-gatefor consistency and completeness.  If you find something wrong, you
5401*0Sstevel@tonic-gatecan put up an alert box or maybe fix things up yourself.  You can
5402*0Sstevel@tonic-gateabort the submission by returning false from this function.
5403*0Sstevel@tonic-gate
5404*0Sstevel@tonic-gateUsually the bulk of JavaScript functions are defined in a <script>
5405*0Sstevel@tonic-gateblock in the HTML header and -onSubmit points to one of these function
5406*0Sstevel@tonic-gatecall.  See start_html() for details.
5407*0Sstevel@tonic-gate
5408*0Sstevel@tonic-gate=head2 CREATING A TEXT FIELD
5409*0Sstevel@tonic-gate
5410*0Sstevel@tonic-gate    print $query->textfield(-name=>'field_name',
5411*0Sstevel@tonic-gate			    -default=>'starting value',
5412*0Sstevel@tonic-gate			    -size=>50,
5413*0Sstevel@tonic-gate			    -maxlength=>80);
5414*0Sstevel@tonic-gate	-or-
5415*0Sstevel@tonic-gate
5416*0Sstevel@tonic-gate    print $query->textfield('field_name','starting value',50,80);
5417*0Sstevel@tonic-gate
5418*0Sstevel@tonic-gatetextfield() will return a text input field.
5419*0Sstevel@tonic-gate
5420*0Sstevel@tonic-gate=over 4
5421*0Sstevel@tonic-gate
5422*0Sstevel@tonic-gate=item B<Parameters>
5423*0Sstevel@tonic-gate
5424*0Sstevel@tonic-gate=item 1.
5425*0Sstevel@tonic-gate
5426*0Sstevel@tonic-gateThe first parameter is the required name for the field (-name).
5427*0Sstevel@tonic-gate
5428*0Sstevel@tonic-gate=item 2.
5429*0Sstevel@tonic-gate
5430*0Sstevel@tonic-gateThe optional second parameter is the default starting value for the field
5431*0Sstevel@tonic-gatecontents (-default).
5432*0Sstevel@tonic-gate
5433*0Sstevel@tonic-gate=item 3.
5434*0Sstevel@tonic-gate
5435*0Sstevel@tonic-gateThe optional third parameter is the size of the field in
5436*0Sstevel@tonic-gate      characters (-size).
5437*0Sstevel@tonic-gate
5438*0Sstevel@tonic-gate=item 4.
5439*0Sstevel@tonic-gate
5440*0Sstevel@tonic-gateThe optional fourth parameter is the maximum number of characters the
5441*0Sstevel@tonic-gate      field will accept (-maxlength).
5442*0Sstevel@tonic-gate
5443*0Sstevel@tonic-gate=back
5444*0Sstevel@tonic-gate
5445*0Sstevel@tonic-gateAs with all these methods, the field will be initialized with its
5446*0Sstevel@tonic-gateprevious contents from earlier invocations of the script.
5447*0Sstevel@tonic-gateWhen the form is processed, the value of the text field can be
5448*0Sstevel@tonic-gateretrieved with:
5449*0Sstevel@tonic-gate
5450*0Sstevel@tonic-gate       $value = $query->param('foo');
5451*0Sstevel@tonic-gate
5452*0Sstevel@tonic-gateIf you want to reset it from its initial value after the script has been
5453*0Sstevel@tonic-gatecalled once, you can do so like this:
5454*0Sstevel@tonic-gate
5455*0Sstevel@tonic-gate       $query->param('foo',"I'm taking over this value!");
5456*0Sstevel@tonic-gate
5457*0Sstevel@tonic-gateNEW AS OF VERSION 2.15: If you don't want the field to take on its previous
5458*0Sstevel@tonic-gatevalue, you can force its current value by using the -override (alias -force)
5459*0Sstevel@tonic-gateparameter:
5460*0Sstevel@tonic-gate
5461*0Sstevel@tonic-gate    print $query->textfield(-name=>'field_name',
5462*0Sstevel@tonic-gate			    -default=>'starting value',
5463*0Sstevel@tonic-gate			    -override=>1,
5464*0Sstevel@tonic-gate			    -size=>50,
5465*0Sstevel@tonic-gate			    -maxlength=>80);
5466*0Sstevel@tonic-gate
5467*0Sstevel@tonic-gateJAVASCRIPTING: You can also provide B<-onChange>, B<-onFocus>,
5468*0Sstevel@tonic-gateB<-onBlur>, B<-onMouseOver>, B<-onMouseOut> and B<-onSelect>
5469*0Sstevel@tonic-gateparameters to register JavaScript event handlers.  The onChange
5470*0Sstevel@tonic-gatehandler will be called whenever the user changes the contents of the
5471*0Sstevel@tonic-gatetext field.  You can do text validation if you like.  onFocus and
5472*0Sstevel@tonic-gateonBlur are called respectively when the insertion point moves into and
5473*0Sstevel@tonic-gateout of the text field.  onSelect is called when the user changes the
5474*0Sstevel@tonic-gateportion of the text that is selected.
5475*0Sstevel@tonic-gate
5476*0Sstevel@tonic-gate=head2 CREATING A BIG TEXT FIELD
5477*0Sstevel@tonic-gate
5478*0Sstevel@tonic-gate   print $query->textarea(-name=>'foo',
5479*0Sstevel@tonic-gate			  -default=>'starting value',
5480*0Sstevel@tonic-gate			  -rows=>10,
5481*0Sstevel@tonic-gate			  -columns=>50);
5482*0Sstevel@tonic-gate
5483*0Sstevel@tonic-gate	-or
5484*0Sstevel@tonic-gate
5485*0Sstevel@tonic-gate   print $query->textarea('foo','starting value',10,50);
5486*0Sstevel@tonic-gate
5487*0Sstevel@tonic-gatetextarea() is just like textfield, but it allows you to specify
5488*0Sstevel@tonic-gaterows and columns for a multiline text entry box.  You can provide
5489*0Sstevel@tonic-gatea starting value for the field, which can be long and contain
5490*0Sstevel@tonic-gatemultiple lines.
5491*0Sstevel@tonic-gate
5492*0Sstevel@tonic-gateJAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur> ,
5493*0Sstevel@tonic-gateB<-onMouseOver>, B<-onMouseOut>, and B<-onSelect> parameters are
5494*0Sstevel@tonic-gaterecognized.  See textfield().
5495*0Sstevel@tonic-gate
5496*0Sstevel@tonic-gate=head2 CREATING A PASSWORD FIELD
5497*0Sstevel@tonic-gate
5498*0Sstevel@tonic-gate   print $query->password_field(-name=>'secret',
5499*0Sstevel@tonic-gate				-value=>'starting value',
5500*0Sstevel@tonic-gate				-size=>50,
5501*0Sstevel@tonic-gate				-maxlength=>80);
5502*0Sstevel@tonic-gate	-or-
5503*0Sstevel@tonic-gate
5504*0Sstevel@tonic-gate   print $query->password_field('secret','starting value',50,80);
5505*0Sstevel@tonic-gate
5506*0Sstevel@tonic-gatepassword_field() is identical to textfield(), except that its contents
5507*0Sstevel@tonic-gatewill be starred out on the web page.
5508*0Sstevel@tonic-gate
5509*0Sstevel@tonic-gateJAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur>,
5510*0Sstevel@tonic-gateB<-onMouseOver>, B<-onMouseOut> and B<-onSelect> parameters are
5511*0Sstevel@tonic-gaterecognized.  See textfield().
5512*0Sstevel@tonic-gate
5513*0Sstevel@tonic-gate=head2 CREATING A FILE UPLOAD FIELD
5514*0Sstevel@tonic-gate
5515*0Sstevel@tonic-gate    print $query->filefield(-name=>'uploaded_file',
5516*0Sstevel@tonic-gate			    -default=>'starting value',
5517*0Sstevel@tonic-gate			    -size=>50,
5518*0Sstevel@tonic-gate			    -maxlength=>80);
5519*0Sstevel@tonic-gate	-or-
5520*0Sstevel@tonic-gate
5521*0Sstevel@tonic-gate    print $query->filefield('uploaded_file','starting value',50,80);
5522*0Sstevel@tonic-gate
5523*0Sstevel@tonic-gatefilefield() will return a file upload field for Netscape 2.0 browsers.
5524*0Sstevel@tonic-gateIn order to take full advantage of this I<you must use the new
5525*0Sstevel@tonic-gatemultipart encoding scheme> for the form.  You can do this either
5526*0Sstevel@tonic-gateby calling B<start_form()> with an encoding type of B<&CGI::MULTIPART>,
5527*0Sstevel@tonic-gateor by calling the new method B<start_multipart_form()> instead of
5528*0Sstevel@tonic-gatevanilla B<start_form()>.
5529*0Sstevel@tonic-gate
5530*0Sstevel@tonic-gate=over 4
5531*0Sstevel@tonic-gate
5532*0Sstevel@tonic-gate=item B<Parameters>
5533*0Sstevel@tonic-gate
5534*0Sstevel@tonic-gate=item 1.
5535*0Sstevel@tonic-gate
5536*0Sstevel@tonic-gateThe first parameter is the required name for the field (-name).
5537*0Sstevel@tonic-gate
5538*0Sstevel@tonic-gate=item 2.
5539*0Sstevel@tonic-gate
5540*0Sstevel@tonic-gateThe optional second parameter is the starting value for the field contents
5541*0Sstevel@tonic-gateto be used as the default file name (-default).
5542*0Sstevel@tonic-gate
5543*0Sstevel@tonic-gateFor security reasons, browsers don't pay any attention to this field,
5544*0Sstevel@tonic-gateand so the starting value will always be blank.  Worse, the field
5545*0Sstevel@tonic-gateloses its "sticky" behavior and forgets its previous contents.  The
5546*0Sstevel@tonic-gatestarting value field is called for in the HTML specification, however,
5547*0Sstevel@tonic-gateand possibly some browser will eventually provide support for it.
5548*0Sstevel@tonic-gate
5549*0Sstevel@tonic-gate=item 3.
5550*0Sstevel@tonic-gate
5551*0Sstevel@tonic-gateThe optional third parameter is the size of the field in
5552*0Sstevel@tonic-gatecharacters (-size).
5553*0Sstevel@tonic-gate
5554*0Sstevel@tonic-gate=item 4.
5555*0Sstevel@tonic-gate
5556*0Sstevel@tonic-gateThe optional fourth parameter is the maximum number of characters the
5557*0Sstevel@tonic-gatefield will accept (-maxlength).
5558*0Sstevel@tonic-gate
5559*0Sstevel@tonic-gate=back
5560*0Sstevel@tonic-gate
5561*0Sstevel@tonic-gateWhen the form is processed, you can retrieve the entered filename
5562*0Sstevel@tonic-gateby calling param():
5563*0Sstevel@tonic-gate
5564*0Sstevel@tonic-gate       $filename = $query->param('uploaded_file');
5565*0Sstevel@tonic-gate
5566*0Sstevel@tonic-gateDifferent browsers will return slightly different things for the
5567*0Sstevel@tonic-gatename.  Some browsers return the filename only.  Others return the full
5568*0Sstevel@tonic-gatepath to the file, using the path conventions of the user's machine.
5569*0Sstevel@tonic-gateRegardless, the name returned is always the name of the file on the
5570*0Sstevel@tonic-gateI<user's> machine, and is unrelated to the name of the temporary file
5571*0Sstevel@tonic-gatethat CGI.pm creates during upload spooling (see below).
5572*0Sstevel@tonic-gate
5573*0Sstevel@tonic-gateThe filename returned is also a file handle.  You can read the contents
5574*0Sstevel@tonic-gateof the file using standard Perl file reading calls:
5575*0Sstevel@tonic-gate
5576*0Sstevel@tonic-gate	# Read a text file and print it out
5577*0Sstevel@tonic-gate	while (<$filename>) {
5578*0Sstevel@tonic-gate	   print;
5579*0Sstevel@tonic-gate	}
5580*0Sstevel@tonic-gate
5581*0Sstevel@tonic-gate	# Copy a binary file to somewhere safe
5582*0Sstevel@tonic-gate	open (OUTFILE,">>/usr/local/web/users/feedback");
5583*0Sstevel@tonic-gate	while ($bytesread=read($filename,$buffer,1024)) {
5584*0Sstevel@tonic-gate	   print OUTFILE $buffer;
5585*0Sstevel@tonic-gate	}
5586*0Sstevel@tonic-gate
5587*0Sstevel@tonic-gateHowever, there are problems with the dual nature of the upload fields.
5588*0Sstevel@tonic-gateIf you C<use strict>, then Perl will complain when you try to use a
5589*0Sstevel@tonic-gatestring as a filehandle.  You can get around this by placing the file
5590*0Sstevel@tonic-gatereading code in a block containing the C<no strict> pragma.  More
5591*0Sstevel@tonic-gateseriously, it is possible for the remote user to type garbage into the
5592*0Sstevel@tonic-gateupload field, in which case what you get from param() is not a
5593*0Sstevel@tonic-gatefilehandle at all, but a string.
5594*0Sstevel@tonic-gate
5595*0Sstevel@tonic-gateTo be safe, use the I<upload()> function (new in version 2.47).  When
5596*0Sstevel@tonic-gatecalled with the name of an upload field, I<upload()> returns a
5597*0Sstevel@tonic-gatefilehandle, or undef if the parameter is not a valid filehandle.
5598*0Sstevel@tonic-gate
5599*0Sstevel@tonic-gate     $fh = $query->upload('uploaded_file');
5600*0Sstevel@tonic-gate     while (<$fh>) {
5601*0Sstevel@tonic-gate	   print;
5602*0Sstevel@tonic-gate     }
5603*0Sstevel@tonic-gate
5604*0Sstevel@tonic-gateIn an array context, upload() will return an array of filehandles.
5605*0Sstevel@tonic-gateThis makes it possible to create forms that use the same name for
5606*0Sstevel@tonic-gatemultiple upload fields.
5607*0Sstevel@tonic-gate
5608*0Sstevel@tonic-gateThis is the recommended idiom.
5609*0Sstevel@tonic-gate
5610*0Sstevel@tonic-gateWhen a file is uploaded the browser usually sends along some
5611*0Sstevel@tonic-gateinformation along with it in the format of headers.  The information
5612*0Sstevel@tonic-gateusually includes the MIME content type.  Future browsers may send
5613*0Sstevel@tonic-gateother information as well (such as modification date and size). To
5614*0Sstevel@tonic-gateretrieve this information, call uploadInfo().  It returns a reference to
5615*0Sstevel@tonic-gatean associative array containing all the document headers.
5616*0Sstevel@tonic-gate
5617*0Sstevel@tonic-gate       $filename = $query->param('uploaded_file');
5618*0Sstevel@tonic-gate       $type = $query->uploadInfo($filename)->{'Content-Type'};
5619*0Sstevel@tonic-gate       unless ($type eq 'text/html') {
5620*0Sstevel@tonic-gate	  die "HTML FILES ONLY!";
5621*0Sstevel@tonic-gate       }
5622*0Sstevel@tonic-gate
5623*0Sstevel@tonic-gateIf you are using a machine that recognizes "text" and "binary" data
5624*0Sstevel@tonic-gatemodes, be sure to understand when and how to use them (see the Camel book).
5625*0Sstevel@tonic-gateOtherwise you may find that binary files are corrupted during file
5626*0Sstevel@tonic-gateuploads.
5627*0Sstevel@tonic-gate
5628*0Sstevel@tonic-gateThere are occasionally problems involving parsing the uploaded file.
5629*0Sstevel@tonic-gateThis usually happens when the user presses "Stop" before the upload is
5630*0Sstevel@tonic-gatefinished.  In this case, CGI.pm will return undef for the name of the
5631*0Sstevel@tonic-gateuploaded file and set I<cgi_error()> to the string "400 Bad request
5632*0Sstevel@tonic-gate(malformed multipart POST)".  This error message is designed so that
5633*0Sstevel@tonic-gateyou can incorporate it into a status code to be sent to the browser.
5634*0Sstevel@tonic-gateExample:
5635*0Sstevel@tonic-gate
5636*0Sstevel@tonic-gate   $file = $query->upload('uploaded_file');
5637*0Sstevel@tonic-gate   if (!$file && $query->cgi_error) {
5638*0Sstevel@tonic-gate      print $query->header(-status=>$query->cgi_error);
5639*0Sstevel@tonic-gate      exit 0;
5640*0Sstevel@tonic-gate   }
5641*0Sstevel@tonic-gate
5642*0Sstevel@tonic-gateYou are free to create a custom HTML page to complain about the error,
5643*0Sstevel@tonic-gateif you wish.
5644*0Sstevel@tonic-gate
5645*0Sstevel@tonic-gateYou can set up a callback that will be called whenever a file upload
5646*0Sstevel@tonic-gateis being read during the form processing. This is much like the
5647*0Sstevel@tonic-gateUPLOAD_HOOK facility available in Apache::Request, with the exception
5648*0Sstevel@tonic-gatethat the first argument to the callback is an Apache::Upload object,
5649*0Sstevel@tonic-gatehere it's the remote filename.
5650*0Sstevel@tonic-gate
5651*0Sstevel@tonic-gate $q = CGI->new();
5652*0Sstevel@tonic-gate $q->upload_hook(\&hook,$data);
5653*0Sstevel@tonic-gate
5654*0Sstevel@tonic-gate sub hook
5655*0Sstevel@tonic-gate {
5656*0Sstevel@tonic-gate        my ($filename, $buffer, $bytes_read, $data) = @_;
5657*0Sstevel@tonic-gate        print  "Read $bytes_read bytes of $filename\n";
5658*0Sstevel@tonic-gate }
5659*0Sstevel@tonic-gate
5660*0Sstevel@tonic-gateIf using the function-oriented interface, call the CGI::upload_hook()
5661*0Sstevel@tonic-gatemethod before calling param() or any other CGI functions:
5662*0Sstevel@tonic-gate
5663*0Sstevel@tonic-gate  CGI::upload_hook(\&hook,$data);
5664*0Sstevel@tonic-gate
5665*0Sstevel@tonic-gateThis method is not exported by default.  You will have to import it
5666*0Sstevel@tonic-gateexplicitly if you wish to use it without the CGI:: prefix.
5667*0Sstevel@tonic-gate
5668*0Sstevel@tonic-gateIf you are using CGI.pm on a Windows platform and find that binary
5669*0Sstevel@tonic-gatefiles get slightly larger when uploaded but that text files remain the
5670*0Sstevel@tonic-gatesame, then you have forgotten to activate binary mode on the output
5671*0Sstevel@tonic-gatefilehandle.  Be sure to call binmode() on any handle that you create
5672*0Sstevel@tonic-gateto write the uploaded file to disk.
5673*0Sstevel@tonic-gate
5674*0Sstevel@tonic-gateJAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur>,
5675*0Sstevel@tonic-gateB<-onMouseOver>, B<-onMouseOut> and B<-onSelect> parameters are
5676*0Sstevel@tonic-gaterecognized.  See textfield() for details.
5677*0Sstevel@tonic-gate
5678*0Sstevel@tonic-gate=head2 CREATING A POPUP MENU
5679*0Sstevel@tonic-gate
5680*0Sstevel@tonic-gate   print $query->popup_menu('menu_name',
5681*0Sstevel@tonic-gate			    ['eenie','meenie','minie'],
5682*0Sstevel@tonic-gate			    'meenie');
5683*0Sstevel@tonic-gate
5684*0Sstevel@tonic-gate      -or-
5685*0Sstevel@tonic-gate
5686*0Sstevel@tonic-gate   %labels = ('eenie'=>'your first choice',
5687*0Sstevel@tonic-gate	      'meenie'=>'your second choice',
5688*0Sstevel@tonic-gate	      'minie'=>'your third choice');
5689*0Sstevel@tonic-gate   %attributes = ('eenie'=>{'class'=>'class of first choice'});
5690*0Sstevel@tonic-gate   print $query->popup_menu('menu_name',
5691*0Sstevel@tonic-gate			    ['eenie','meenie','minie'],
5692*0Sstevel@tonic-gate          'meenie',\%labels,\%attributes);
5693*0Sstevel@tonic-gate
5694*0Sstevel@tonic-gate	-or (named parameter style)-
5695*0Sstevel@tonic-gate
5696*0Sstevel@tonic-gate   print $query->popup_menu(-name=>'menu_name',
5697*0Sstevel@tonic-gate			    -values=>['eenie','meenie','minie'],
5698*0Sstevel@tonic-gate			    -default=>'meenie',
5699*0Sstevel@tonic-gate          -labels=>\%labels,
5700*0Sstevel@tonic-gate          -attributes=>\%attributes);
5701*0Sstevel@tonic-gate
5702*0Sstevel@tonic-gatepopup_menu() creates a menu.
5703*0Sstevel@tonic-gate
5704*0Sstevel@tonic-gate=over 4
5705*0Sstevel@tonic-gate
5706*0Sstevel@tonic-gate=item 1.
5707*0Sstevel@tonic-gate
5708*0Sstevel@tonic-gateThe required first argument is the menu's name (-name).
5709*0Sstevel@tonic-gate
5710*0Sstevel@tonic-gate=item 2.
5711*0Sstevel@tonic-gate
5712*0Sstevel@tonic-gateThe required second argument (-values) is an array B<reference>
5713*0Sstevel@tonic-gatecontaining the list of menu items in the menu.  You can pass the
5714*0Sstevel@tonic-gatemethod an anonymous array, as shown in the example, or a reference to
5715*0Sstevel@tonic-gatea named array, such as "\@foo".
5716*0Sstevel@tonic-gate
5717*0Sstevel@tonic-gate=item 3.
5718*0Sstevel@tonic-gate
5719*0Sstevel@tonic-gateThe optional third parameter (-default) is the name of the default
5720*0Sstevel@tonic-gatemenu choice.  If not specified, the first item will be the default.
5721*0Sstevel@tonic-gateThe values of the previous choice will be maintained across queries.
5722*0Sstevel@tonic-gate
5723*0Sstevel@tonic-gate=item 4.
5724*0Sstevel@tonic-gate
5725*0Sstevel@tonic-gateThe optional fourth parameter (-labels) is provided for people who
5726*0Sstevel@tonic-gatewant to use different values for the user-visible label inside the
5727*0Sstevel@tonic-gatepopup menu and the value returned to your script.  It's a pointer to an
5728*0Sstevel@tonic-gateassociative array relating menu values to user-visible labels.  If you
5729*0Sstevel@tonic-gateleave this parameter blank, the menu values will be displayed by
5730*0Sstevel@tonic-gatedefault.  (You can also leave a label undefined if you want to).
5731*0Sstevel@tonic-gate
5732*0Sstevel@tonic-gate=item 5.
5733*0Sstevel@tonic-gate
5734*0Sstevel@tonic-gateThe optional fifth parameter (-attributes) is provided to assign
5735*0Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's
5736*0Sstevel@tonic-gatea pointer to an associative array relating menu values to another
5737*0Sstevel@tonic-gateassociative array with the attribute's name as the key and the
5738*0Sstevel@tonic-gateattribute's value as the value.
5739*0Sstevel@tonic-gate
5740*0Sstevel@tonic-gate=back
5741*0Sstevel@tonic-gate
5742*0Sstevel@tonic-gateWhen the form is processed, the selected value of the popup menu can
5743*0Sstevel@tonic-gatebe retrieved using:
5744*0Sstevel@tonic-gate
5745*0Sstevel@tonic-gate      $popup_menu_value = $query->param('menu_name');
5746*0Sstevel@tonic-gate
5747*0Sstevel@tonic-gateJAVASCRIPTING: popup_menu() recognizes the following event handlers:
5748*0Sstevel@tonic-gateB<-onChange>, B<-onFocus>, B<-onMouseOver>, B<-onMouseOut>, and
5749*0Sstevel@tonic-gateB<-onBlur>.  See the textfield() section for details on when these
5750*0Sstevel@tonic-gatehandlers are called.
5751*0Sstevel@tonic-gate
5752*0Sstevel@tonic-gate=head2 CREATING AN OPTION GROUP
5753*0Sstevel@tonic-gate
5754*0Sstevel@tonic-gateNamed parameter style
5755*0Sstevel@tonic-gate
5756*0Sstevel@tonic-gate  print $query->popup_menu(-name=>'menu_name',
5757*0Sstevel@tonic-gate                  -values=>[qw/eenie meenie minie/,
5758*0Sstevel@tonic-gate                            $q->optgroup(-name=>'optgroup_name',
5759*0Sstevel@tonic-gate                                         -values ['moe','catch'],
5760*0Sstevel@tonic-gate                                         -attributes=>{'catch'=>{'class'=>'red'}}),
5761*0Sstevel@tonic-gate                  -labels=>{'eenie'=>'one',
5762*0Sstevel@tonic-gate                            'meenie'=>'two',
5763*0Sstevel@tonic-gate                            'minie'=>'three'},
5764*0Sstevel@tonic-gate                  -default=>'meenie');
5765*0Sstevel@tonic-gate
5766*0Sstevel@tonic-gate  Old style
5767*0Sstevel@tonic-gate  print $query->popup_menu('menu_name',
5768*0Sstevel@tonic-gate                  ['eenie','meenie','minie',
5769*0Sstevel@tonic-gate                   $q->optgroup('optgroup_name', ['moe', 'catch'],
5770*0Sstevel@tonic-gate                         {'catch'=>{'class'=>'red'}})],'meenie',
5771*0Sstevel@tonic-gate                  {'eenie'=>'one','meenie'=>'two','minie'=>'three'});
5772*0Sstevel@tonic-gate
5773*0Sstevel@tonic-gateoptgroup creates an option group within a popup menu.
5774*0Sstevel@tonic-gate
5775*0Sstevel@tonic-gate=over 4
5776*0Sstevel@tonic-gate
5777*0Sstevel@tonic-gate=item 1.
5778*0Sstevel@tonic-gate
5779*0Sstevel@tonic-gateThe required first argument (B<-name>) is the label attribute of the
5780*0Sstevel@tonic-gateoptgroup and is B<not> inserted in the parameter list of the query.
5781*0Sstevel@tonic-gate
5782*0Sstevel@tonic-gate=item 2.
5783*0Sstevel@tonic-gate
5784*0Sstevel@tonic-gateThe required second argument (B<-values>)  is an array reference
5785*0Sstevel@tonic-gatecontaining the list of menu items in the menu.  You can pass the
5786*0Sstevel@tonic-gatemethod an anonymous array, as shown in the example, or a reference
5787*0Sstevel@tonic-gateto a named array, such as \@foo.  If you pass a HASH reference,
5788*0Sstevel@tonic-gatethe keys will be used for the menu values, and the values will be
5789*0Sstevel@tonic-gateused for the menu labels (see -labels below).
5790*0Sstevel@tonic-gate
5791*0Sstevel@tonic-gate=item 3.
5792*0Sstevel@tonic-gate
5793*0Sstevel@tonic-gateThe optional third parameter (B<-labels>) allows you to pass a reference
5794*0Sstevel@tonic-gateto an associative array containing user-visible labels for one or more
5795*0Sstevel@tonic-gateof the menu items.  You can use this when you want the user to see one
5796*0Sstevel@tonic-gatemenu string, but have the browser return your program a different one.
5797*0Sstevel@tonic-gateIf you don't specify this, the value string will be used instead
5798*0Sstevel@tonic-gate("eenie", "meenie" and "minie" in this example).  This is equivalent
5799*0Sstevel@tonic-gateto using a hash reference for the -values parameter.
5800*0Sstevel@tonic-gate
5801*0Sstevel@tonic-gate=item 4.
5802*0Sstevel@tonic-gate
5803*0Sstevel@tonic-gateAn optional fourth parameter (B<-labeled>) can be set to a true value
5804*0Sstevel@tonic-gateand indicates that the values should be used as the label attribute
5805*0Sstevel@tonic-gatefor each option element within the optgroup.
5806*0Sstevel@tonic-gate
5807*0Sstevel@tonic-gate=item 5.
5808*0Sstevel@tonic-gate
5809*0Sstevel@tonic-gateAn optional fifth parameter (-novals) can be set to a true value and
5810*0Sstevel@tonic-gateindicates to suppress the val attribut in each option element within
5811*0Sstevel@tonic-gatethe optgroup.
5812*0Sstevel@tonic-gate
5813*0Sstevel@tonic-gateSee the discussion on optgroup at W3C
5814*0Sstevel@tonic-gate(http://www.w3.org/TR/REC-html40/interact/forms.html#edef-OPTGROUP)
5815*0Sstevel@tonic-gatefor details.
5816*0Sstevel@tonic-gate
5817*0Sstevel@tonic-gate=item 6.
5818*0Sstevel@tonic-gate
5819*0Sstevel@tonic-gateAn optional sixth parameter (-attributes) is provided to assign
5820*0Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's
5821*0Sstevel@tonic-gatea pointer to an associative array relating menu values to another
5822*0Sstevel@tonic-gateassociative array with the attribute's name as the key and the
5823*0Sstevel@tonic-gateattribute's value as the value.
5824*0Sstevel@tonic-gate
5825*0Sstevel@tonic-gate=back
5826*0Sstevel@tonic-gate
5827*0Sstevel@tonic-gate=head2 CREATING A SCROLLING LIST
5828*0Sstevel@tonic-gate
5829*0Sstevel@tonic-gate   print $query->scrolling_list('list_name',
5830*0Sstevel@tonic-gate				['eenie','meenie','minie','moe'],
5831*0Sstevel@tonic-gate        ['eenie','moe'],5,'true',{'moe'=>{'class'=>'red'}});
5832*0Sstevel@tonic-gate      -or-
5833*0Sstevel@tonic-gate
5834*0Sstevel@tonic-gate   print $query->scrolling_list('list_name',
5835*0Sstevel@tonic-gate				['eenie','meenie','minie','moe'],
5836*0Sstevel@tonic-gate				['eenie','moe'],5,'true',
5837*0Sstevel@tonic-gate        \%labels,%attributes);
5838*0Sstevel@tonic-gate
5839*0Sstevel@tonic-gate	-or-
5840*0Sstevel@tonic-gate
5841*0Sstevel@tonic-gate   print $query->scrolling_list(-name=>'list_name',
5842*0Sstevel@tonic-gate				-values=>['eenie','meenie','minie','moe'],
5843*0Sstevel@tonic-gate				-default=>['eenie','moe'],
5844*0Sstevel@tonic-gate				-size=>5,
5845*0Sstevel@tonic-gate				-multiple=>'true',
5846*0Sstevel@tonic-gate        -labels=>\%labels,
5847*0Sstevel@tonic-gate        -attributes=>\%attributes);
5848*0Sstevel@tonic-gate
5849*0Sstevel@tonic-gatescrolling_list() creates a scrolling list.
5850*0Sstevel@tonic-gate
5851*0Sstevel@tonic-gate=over 4
5852*0Sstevel@tonic-gate
5853*0Sstevel@tonic-gate=item B<Parameters:>
5854*0Sstevel@tonic-gate
5855*0Sstevel@tonic-gate=item 1.
5856*0Sstevel@tonic-gate
5857*0Sstevel@tonic-gateThe first and second arguments are the list name (-name) and values
5858*0Sstevel@tonic-gate(-values).  As in the popup menu, the second argument should be an
5859*0Sstevel@tonic-gatearray reference.
5860*0Sstevel@tonic-gate
5861*0Sstevel@tonic-gate=item 2.
5862*0Sstevel@tonic-gate
5863*0Sstevel@tonic-gateThe optional third argument (-default) can be either a reference to a
5864*0Sstevel@tonic-gatelist containing the values to be selected by default, or can be a
5865*0Sstevel@tonic-gatesingle value to select.  If this argument is missing or undefined,
5866*0Sstevel@tonic-gatethen nothing is selected when the list first appears.  In the named
5867*0Sstevel@tonic-gateparameter version, you can use the synonym "-defaults" for this
5868*0Sstevel@tonic-gateparameter.
5869*0Sstevel@tonic-gate
5870*0Sstevel@tonic-gate=item 3.
5871*0Sstevel@tonic-gate
5872*0Sstevel@tonic-gateThe optional fourth argument is the size of the list (-size).
5873*0Sstevel@tonic-gate
5874*0Sstevel@tonic-gate=item 4.
5875*0Sstevel@tonic-gate
5876*0Sstevel@tonic-gateThe optional fifth argument can be set to true to allow multiple
5877*0Sstevel@tonic-gatesimultaneous selections (-multiple).  Otherwise only one selection
5878*0Sstevel@tonic-gatewill be allowed at a time.
5879*0Sstevel@tonic-gate
5880*0Sstevel@tonic-gate=item 5.
5881*0Sstevel@tonic-gate
5882*0Sstevel@tonic-gateThe optional sixth argument is a pointer to an associative array
5883*0Sstevel@tonic-gatecontaining long user-visible labels for the list items (-labels).
5884*0Sstevel@tonic-gateIf not provided, the values will be displayed.
5885*0Sstevel@tonic-gate
5886*0Sstevel@tonic-gate=item 6.
5887*0Sstevel@tonic-gate
5888*0Sstevel@tonic-gateThe optional sixth parameter (-attributes) is provided to assign
5889*0Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's
5890*0Sstevel@tonic-gatea pointer to an associative array relating menu values to another
5891*0Sstevel@tonic-gateassociative array with the attribute's name as the key and the
5892*0Sstevel@tonic-gateattribute's value as the value.
5893*0Sstevel@tonic-gate
5894*0Sstevel@tonic-gateWhen this form is processed, all selected list items will be returned as
5895*0Sstevel@tonic-gatea list under the parameter name 'list_name'.  The values of the
5896*0Sstevel@tonic-gateselected items can be retrieved with:
5897*0Sstevel@tonic-gate
5898*0Sstevel@tonic-gate      @selected = $query->param('list_name');
5899*0Sstevel@tonic-gate
5900*0Sstevel@tonic-gate=back
5901*0Sstevel@tonic-gate
5902*0Sstevel@tonic-gateJAVASCRIPTING: scrolling_list() recognizes the following event
5903*0Sstevel@tonic-gatehandlers: B<-onChange>, B<-onFocus>, B<-onMouseOver>, B<-onMouseOut>
5904*0Sstevel@tonic-gateand B<-onBlur>.  See textfield() for the description of when these
5905*0Sstevel@tonic-gatehandlers are called.
5906*0Sstevel@tonic-gate
5907*0Sstevel@tonic-gate=head2 CREATING A GROUP OF RELATED CHECKBOXES
5908*0Sstevel@tonic-gate
5909*0Sstevel@tonic-gate   print $query->checkbox_group(-name=>'group_name',
5910*0Sstevel@tonic-gate				-values=>['eenie','meenie','minie','moe'],
5911*0Sstevel@tonic-gate				-default=>['eenie','moe'],
5912*0Sstevel@tonic-gate				-linebreak=>'true',
5913*0Sstevel@tonic-gate        -labels=>\%labels,
5914*0Sstevel@tonic-gate        -attributes=>\%attributes);
5915*0Sstevel@tonic-gate
5916*0Sstevel@tonic-gate   print $query->checkbox_group('group_name',
5917*0Sstevel@tonic-gate				['eenie','meenie','minie','moe'],
5918*0Sstevel@tonic-gate        ['eenie','moe'],'true',\%labels,
5919*0Sstevel@tonic-gate        {'moe'=>{'class'=>'red'}});
5920*0Sstevel@tonic-gate
5921*0Sstevel@tonic-gate   HTML3-COMPATIBLE BROWSERS ONLY:
5922*0Sstevel@tonic-gate
5923*0Sstevel@tonic-gate   print $query->checkbox_group(-name=>'group_name',
5924*0Sstevel@tonic-gate				-values=>['eenie','meenie','minie','moe'],
5925*0Sstevel@tonic-gate				-rows=2,-columns=>2);
5926*0Sstevel@tonic-gate
5927*0Sstevel@tonic-gate
5928*0Sstevel@tonic-gatecheckbox_group() creates a list of checkboxes that are related
5929*0Sstevel@tonic-gateby the same name.
5930*0Sstevel@tonic-gate
5931*0Sstevel@tonic-gate=over 4
5932*0Sstevel@tonic-gate
5933*0Sstevel@tonic-gate=item B<Parameters:>
5934*0Sstevel@tonic-gate
5935*0Sstevel@tonic-gate=item 1.
5936*0Sstevel@tonic-gate
5937*0Sstevel@tonic-gateThe first and second arguments are the checkbox name and values,
5938*0Sstevel@tonic-gaterespectively (-name and -values).  As in the popup menu, the second
5939*0Sstevel@tonic-gateargument should be an array reference.  These values are used for the
5940*0Sstevel@tonic-gateuser-readable labels printed next to the checkboxes as well as for the
5941*0Sstevel@tonic-gatevalues passed to your script in the query string.
5942*0Sstevel@tonic-gate
5943*0Sstevel@tonic-gate=item 2.
5944*0Sstevel@tonic-gate
5945*0Sstevel@tonic-gateThe optional third argument (-default) can be either a reference to a
5946*0Sstevel@tonic-gatelist containing the values to be checked by default, or can be a
5947*0Sstevel@tonic-gatesingle value to checked.  If this argument is missing or undefined,
5948*0Sstevel@tonic-gatethen nothing is selected when the list first appears.
5949*0Sstevel@tonic-gate
5950*0Sstevel@tonic-gate=item 3.
5951*0Sstevel@tonic-gate
5952*0Sstevel@tonic-gateThe optional fourth argument (-linebreak) can be set to true to place
5953*0Sstevel@tonic-gateline breaks between the checkboxes so that they appear as a vertical
5954*0Sstevel@tonic-gatelist.  Otherwise, they will be strung together on a horizontal line.
5955*0Sstevel@tonic-gate
5956*0Sstevel@tonic-gate=item 4.
5957*0Sstevel@tonic-gate
5958*0Sstevel@tonic-gateThe optional fifth argument is a pointer to an associative array
5959*0Sstevel@tonic-gaterelating the checkbox values to the user-visible labels that will
5960*0Sstevel@tonic-gatebe printed next to them (-labels).  If not provided, the values will
5961*0Sstevel@tonic-gatebe used as the default.
5962*0Sstevel@tonic-gate
5963*0Sstevel@tonic-gate=item 5.
5964*0Sstevel@tonic-gate
5965*0Sstevel@tonic-gateB<HTML3-compatible browsers> (such as Netscape) can take advantage of
5966*0Sstevel@tonic-gatethe optional parameters B<-rows>, and B<-columns>.  These parameters
5967*0Sstevel@tonic-gatecause checkbox_group() to return an HTML3 compatible table containing
5968*0Sstevel@tonic-gatethe checkbox group formatted with the specified number of rows and
5969*0Sstevel@tonic-gatecolumns.  You can provide just the -columns parameter if you wish;
5970*0Sstevel@tonic-gatecheckbox_group will calculate the correct number of rows for you.
5971*0Sstevel@tonic-gate
5972*0Sstevel@tonic-gate=item 6.
5973*0Sstevel@tonic-gate
5974*0Sstevel@tonic-gateThe optional sixth parameter (-attributes) is provided to assign
5975*0Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's
5976*0Sstevel@tonic-gatea pointer to an associative array relating menu values to another
5977*0Sstevel@tonic-gateassociative array with the attribute's name as the key and the
5978*0Sstevel@tonic-gateattribute's value as the value.
5979*0Sstevel@tonic-gate
5980*0Sstevel@tonic-gateTo include row and column headings in the returned table, you
5981*0Sstevel@tonic-gatecan use the B<-rowheaders> and B<-colheaders> parameters.  Both
5982*0Sstevel@tonic-gateof these accept a pointer to an array of headings to use.
5983*0Sstevel@tonic-gateThe headings are just decorative.  They don't reorganize the
5984*0Sstevel@tonic-gateinterpretation of the checkboxes -- they're still a single named
5985*0Sstevel@tonic-gateunit.
5986*0Sstevel@tonic-gate
5987*0Sstevel@tonic-gate=back
5988*0Sstevel@tonic-gate
5989*0Sstevel@tonic-gateWhen the form is processed, all checked boxes will be returned as
5990*0Sstevel@tonic-gatea list under the parameter name 'group_name'.  The values of the
5991*0Sstevel@tonic-gate"on" checkboxes can be retrieved with:
5992*0Sstevel@tonic-gate
5993*0Sstevel@tonic-gate      @turned_on = $query->param('group_name');
5994*0Sstevel@tonic-gate
5995*0Sstevel@tonic-gateThe value returned by checkbox_group() is actually an array of button
5996*0Sstevel@tonic-gateelements.  You can capture them and use them within tables, lists,
5997*0Sstevel@tonic-gateor in other creative ways:
5998*0Sstevel@tonic-gate
5999*0Sstevel@tonic-gate    @h = $query->checkbox_group(-name=>'group_name',-values=>\@values);
6000*0Sstevel@tonic-gate    &use_in_creative_way(@h);
6001*0Sstevel@tonic-gate
6002*0Sstevel@tonic-gateJAVASCRIPTING: checkbox_group() recognizes the B<-onClick>
6003*0Sstevel@tonic-gateparameter.  This specifies a JavaScript code fragment or
6004*0Sstevel@tonic-gatefunction call to be executed every time the user clicks on
6005*0Sstevel@tonic-gateany of the buttons in the group.  You can retrieve the identity
6006*0Sstevel@tonic-gateof the particular button clicked on using the "this" variable.
6007*0Sstevel@tonic-gate
6008*0Sstevel@tonic-gate=head2 CREATING A STANDALONE CHECKBOX
6009*0Sstevel@tonic-gate
6010*0Sstevel@tonic-gate    print $query->checkbox(-name=>'checkbox_name',
6011*0Sstevel@tonic-gate			   -checked=>1,
6012*0Sstevel@tonic-gate			   -value=>'ON',
6013*0Sstevel@tonic-gate			   -label=>'CLICK ME');
6014*0Sstevel@tonic-gate
6015*0Sstevel@tonic-gate	-or-
6016*0Sstevel@tonic-gate
6017*0Sstevel@tonic-gate    print $query->checkbox('checkbox_name','checked','ON','CLICK ME');
6018*0Sstevel@tonic-gate
6019*0Sstevel@tonic-gatecheckbox() is used to create an isolated checkbox that isn't logically
6020*0Sstevel@tonic-gaterelated to any others.
6021*0Sstevel@tonic-gate
6022*0Sstevel@tonic-gate=over 4
6023*0Sstevel@tonic-gate
6024*0Sstevel@tonic-gate=item B<Parameters:>
6025*0Sstevel@tonic-gate
6026*0Sstevel@tonic-gate=item 1.
6027*0Sstevel@tonic-gate
6028*0Sstevel@tonic-gateThe first parameter is the required name for the checkbox (-name).  It
6029*0Sstevel@tonic-gatewill also be used for the user-readable label printed next to the
6030*0Sstevel@tonic-gatecheckbox.
6031*0Sstevel@tonic-gate
6032*0Sstevel@tonic-gate=item 2.
6033*0Sstevel@tonic-gate
6034*0Sstevel@tonic-gateThe optional second parameter (-checked) specifies that the checkbox
6035*0Sstevel@tonic-gateis turned on by default.  Synonyms are -selected and -on.
6036*0Sstevel@tonic-gate
6037*0Sstevel@tonic-gate=item 3.
6038*0Sstevel@tonic-gate
6039*0Sstevel@tonic-gateThe optional third parameter (-value) specifies the value of the
6040*0Sstevel@tonic-gatecheckbox when it is checked.  If not provided, the word "on" is
6041*0Sstevel@tonic-gateassumed.
6042*0Sstevel@tonic-gate
6043*0Sstevel@tonic-gate=item 4.
6044*0Sstevel@tonic-gate
6045*0Sstevel@tonic-gateThe optional fourth parameter (-label) is the user-readable label to
6046*0Sstevel@tonic-gatebe attached to the checkbox.  If not provided, the checkbox name is
6047*0Sstevel@tonic-gateused.
6048*0Sstevel@tonic-gate
6049*0Sstevel@tonic-gate=back
6050*0Sstevel@tonic-gate
6051*0Sstevel@tonic-gateThe value of the checkbox can be retrieved using:
6052*0Sstevel@tonic-gate
6053*0Sstevel@tonic-gate    $turned_on = $query->param('checkbox_name');
6054*0Sstevel@tonic-gate
6055*0Sstevel@tonic-gateJAVASCRIPTING: checkbox() recognizes the B<-onClick>
6056*0Sstevel@tonic-gateparameter.  See checkbox_group() for further details.
6057*0Sstevel@tonic-gate
6058*0Sstevel@tonic-gate=head2 CREATING A RADIO BUTTON GROUP
6059*0Sstevel@tonic-gate
6060*0Sstevel@tonic-gate   print $query->radio_group(-name=>'group_name',
6061*0Sstevel@tonic-gate			     -values=>['eenie','meenie','minie'],
6062*0Sstevel@tonic-gate			     -default=>'meenie',
6063*0Sstevel@tonic-gate			     -linebreak=>'true',
6064*0Sstevel@tonic-gate           -labels=>\%labels,
6065*0Sstevel@tonic-gate           -attributes=>\%attributes);
6066*0Sstevel@tonic-gate
6067*0Sstevel@tonic-gate	-or-
6068*0Sstevel@tonic-gate
6069*0Sstevel@tonic-gate   print $query->radio_group('group_name',['eenie','meenie','minie'],
6070*0Sstevel@tonic-gate            'meenie','true',\%labels,\%attributes);
6071*0Sstevel@tonic-gate
6072*0Sstevel@tonic-gate
6073*0Sstevel@tonic-gate   HTML3-COMPATIBLE BROWSERS ONLY:
6074*0Sstevel@tonic-gate
6075*0Sstevel@tonic-gate   print $query->radio_group(-name=>'group_name',
6076*0Sstevel@tonic-gate			     -values=>['eenie','meenie','minie','moe'],
6077*0Sstevel@tonic-gate			     -rows=2,-columns=>2);
6078*0Sstevel@tonic-gate
6079*0Sstevel@tonic-gateradio_group() creates a set of logically-related radio buttons
6080*0Sstevel@tonic-gate(turning one member of the group on turns the others off)
6081*0Sstevel@tonic-gate
6082*0Sstevel@tonic-gate=over 4
6083*0Sstevel@tonic-gate
6084*0Sstevel@tonic-gate=item B<Parameters:>
6085*0Sstevel@tonic-gate
6086*0Sstevel@tonic-gate=item 1.
6087*0Sstevel@tonic-gate
6088*0Sstevel@tonic-gateThe first argument is the name of the group and is required (-name).
6089*0Sstevel@tonic-gate
6090*0Sstevel@tonic-gate=item 2.
6091*0Sstevel@tonic-gate
6092*0Sstevel@tonic-gateThe second argument (-values) is the list of values for the radio
6093*0Sstevel@tonic-gatebuttons.  The values and the labels that appear on the page are
6094*0Sstevel@tonic-gateidentical.  Pass an array I<reference> in the second argument, either
6095*0Sstevel@tonic-gateusing an anonymous array, as shown, or by referencing a named array as
6096*0Sstevel@tonic-gatein "\@foo".
6097*0Sstevel@tonic-gate
6098*0Sstevel@tonic-gate=item 3.
6099*0Sstevel@tonic-gate
6100*0Sstevel@tonic-gateThe optional third parameter (-default) is the name of the default
6101*0Sstevel@tonic-gatebutton to turn on. If not specified, the first item will be the
6102*0Sstevel@tonic-gatedefault.  You can provide a nonexistent button name, such as "-" to
6103*0Sstevel@tonic-gatestart up with no buttons selected.
6104*0Sstevel@tonic-gate
6105*0Sstevel@tonic-gate=item 4.
6106*0Sstevel@tonic-gate
6107*0Sstevel@tonic-gateThe optional fourth parameter (-linebreak) can be set to 'true' to put
6108*0Sstevel@tonic-gateline breaks between the buttons, creating a vertical list.
6109*0Sstevel@tonic-gate
6110*0Sstevel@tonic-gate=item 5.
6111*0Sstevel@tonic-gate
6112*0Sstevel@tonic-gateThe optional fifth parameter (-labels) is a pointer to an associative
6113*0Sstevel@tonic-gatearray relating the radio button values to user-visible labels to be
6114*0Sstevel@tonic-gateused in the display.  If not provided, the values themselves are
6115*0Sstevel@tonic-gatedisplayed.
6116*0Sstevel@tonic-gate
6117*0Sstevel@tonic-gate=item 6.
6118*0Sstevel@tonic-gate
6119*0Sstevel@tonic-gateB<HTML3-compatible browsers> (such as Netscape) can take advantage
6120*0Sstevel@tonic-gateof the optional
6121*0Sstevel@tonic-gateparameters B<-rows>, and B<-columns>.  These parameters cause
6122*0Sstevel@tonic-gateradio_group() to return an HTML3 compatible table containing
6123*0Sstevel@tonic-gatethe radio group formatted with the specified number of rows
6124*0Sstevel@tonic-gateand columns.  You can provide just the -columns parameter if you
6125*0Sstevel@tonic-gatewish; radio_group will calculate the correct number of rows
6126*0Sstevel@tonic-gatefor you.
6127*0Sstevel@tonic-gate
6128*0Sstevel@tonic-gate=item 6.
6129*0Sstevel@tonic-gate
6130*0Sstevel@tonic-gateThe optional sixth parameter (-attributes) is provided to assign
6131*0Sstevel@tonic-gateany of the common HTML attributes to an individual menu item. It's
6132*0Sstevel@tonic-gatea pointer to an associative array relating menu values to another
6133*0Sstevel@tonic-gateassociative array with the attribute's name as the key and the
6134*0Sstevel@tonic-gateattribute's value as the value.
6135*0Sstevel@tonic-gate
6136*0Sstevel@tonic-gateTo include row and column headings in the returned table, you
6137*0Sstevel@tonic-gatecan use the B<-rowheader> and B<-colheader> parameters.  Both
6138*0Sstevel@tonic-gateof these accept a pointer to an array of headings to use.
6139*0Sstevel@tonic-gateThe headings are just decorative.  They don't reorganize the
6140*0Sstevel@tonic-gateinterpretation of the radio buttons -- they're still a single named
6141*0Sstevel@tonic-gateunit.
6142*0Sstevel@tonic-gate
6143*0Sstevel@tonic-gate=back
6144*0Sstevel@tonic-gate
6145*0Sstevel@tonic-gateWhen the form is processed, the selected radio button can
6146*0Sstevel@tonic-gatebe retrieved using:
6147*0Sstevel@tonic-gate
6148*0Sstevel@tonic-gate      $which_radio_button = $query->param('group_name');
6149*0Sstevel@tonic-gate
6150*0Sstevel@tonic-gateThe value returned by radio_group() is actually an array of button
6151*0Sstevel@tonic-gateelements.  You can capture them and use them within tables, lists,
6152*0Sstevel@tonic-gateor in other creative ways:
6153*0Sstevel@tonic-gate
6154*0Sstevel@tonic-gate    @h = $query->radio_group(-name=>'group_name',-values=>\@values);
6155*0Sstevel@tonic-gate    &use_in_creative_way(@h);
6156*0Sstevel@tonic-gate
6157*0Sstevel@tonic-gate=head2 CREATING A SUBMIT BUTTON
6158*0Sstevel@tonic-gate
6159*0Sstevel@tonic-gate   print $query->submit(-name=>'button_name',
6160*0Sstevel@tonic-gate			-value=>'value');
6161*0Sstevel@tonic-gate
6162*0Sstevel@tonic-gate	-or-
6163*0Sstevel@tonic-gate
6164*0Sstevel@tonic-gate   print $query->submit('button_name','value');
6165*0Sstevel@tonic-gate
6166*0Sstevel@tonic-gatesubmit() will create the query submission button.  Every form
6167*0Sstevel@tonic-gateshould have one of these.
6168*0Sstevel@tonic-gate
6169*0Sstevel@tonic-gate=over 4
6170*0Sstevel@tonic-gate
6171*0Sstevel@tonic-gate=item B<Parameters:>
6172*0Sstevel@tonic-gate
6173*0Sstevel@tonic-gate=item 1.
6174*0Sstevel@tonic-gate
6175*0Sstevel@tonic-gateThe first argument (-name) is optional.  You can give the button a
6176*0Sstevel@tonic-gatename if you have several submission buttons in your form and you want
6177*0Sstevel@tonic-gateto distinguish between them.  The name will also be used as the
6178*0Sstevel@tonic-gateuser-visible label.  Be aware that a few older browsers don't deal with this correctly and
6179*0Sstevel@tonic-gateB<never> send back a value from a button.
6180*0Sstevel@tonic-gate
6181*0Sstevel@tonic-gate=item 2.
6182*0Sstevel@tonic-gate
6183*0Sstevel@tonic-gateThe second argument (-value) is also optional.  This gives the button
6184*0Sstevel@tonic-gatea value that will be passed to your script in the query string.
6185*0Sstevel@tonic-gate
6186*0Sstevel@tonic-gate=back
6187*0Sstevel@tonic-gate
6188*0Sstevel@tonic-gateYou can figure out which button was pressed by using different
6189*0Sstevel@tonic-gatevalues for each one:
6190*0Sstevel@tonic-gate
6191*0Sstevel@tonic-gate     $which_one = $query->param('button_name');
6192*0Sstevel@tonic-gate
6193*0Sstevel@tonic-gateJAVASCRIPTING: radio_group() recognizes the B<-onClick>
6194*0Sstevel@tonic-gateparameter.  See checkbox_group() for further details.
6195*0Sstevel@tonic-gate
6196*0Sstevel@tonic-gate=head2 CREATING A RESET BUTTON
6197*0Sstevel@tonic-gate
6198*0Sstevel@tonic-gate   print $query->reset
6199*0Sstevel@tonic-gate
6200*0Sstevel@tonic-gatereset() creates the "reset" button.  Note that it restores the
6201*0Sstevel@tonic-gateform to its value from the last time the script was called,
6202*0Sstevel@tonic-gateNOT necessarily to the defaults.
6203*0Sstevel@tonic-gate
6204*0Sstevel@tonic-gateNote that this conflicts with the Perl reset() built-in.  Use
6205*0Sstevel@tonic-gateCORE::reset() to get the original reset function.
6206*0Sstevel@tonic-gate
6207*0Sstevel@tonic-gate=head2 CREATING A DEFAULT BUTTON
6208*0Sstevel@tonic-gate
6209*0Sstevel@tonic-gate   print $query->defaults('button_label')
6210*0Sstevel@tonic-gate
6211*0Sstevel@tonic-gatedefaults() creates a button that, when invoked, will cause the
6212*0Sstevel@tonic-gateform to be completely reset to its defaults, wiping out all the
6213*0Sstevel@tonic-gatechanges the user ever made.
6214*0Sstevel@tonic-gate
6215*0Sstevel@tonic-gate=head2 CREATING A HIDDEN FIELD
6216*0Sstevel@tonic-gate
6217*0Sstevel@tonic-gate	print $query->hidden(-name=>'hidden_name',
6218*0Sstevel@tonic-gate			     -default=>['value1','value2'...]);
6219*0Sstevel@tonic-gate
6220*0Sstevel@tonic-gate		-or-
6221*0Sstevel@tonic-gate
6222*0Sstevel@tonic-gate	print $query->hidden('hidden_name','value1','value2'...);
6223*0Sstevel@tonic-gate
6224*0Sstevel@tonic-gatehidden() produces a text field that can't be seen by the user.  It
6225*0Sstevel@tonic-gateis useful for passing state variable information from one invocation
6226*0Sstevel@tonic-gateof the script to the next.
6227*0Sstevel@tonic-gate
6228*0Sstevel@tonic-gate=over 4
6229*0Sstevel@tonic-gate
6230*0Sstevel@tonic-gate=item B<Parameters:>
6231*0Sstevel@tonic-gate
6232*0Sstevel@tonic-gate=item 1.
6233*0Sstevel@tonic-gate
6234*0Sstevel@tonic-gateThe first argument is required and specifies the name of this
6235*0Sstevel@tonic-gatefield (-name).
6236*0Sstevel@tonic-gate
6237*0Sstevel@tonic-gate=item 2.
6238*0Sstevel@tonic-gate
6239*0Sstevel@tonic-gateThe second argument is also required and specifies its value
6240*0Sstevel@tonic-gate(-default).  In the named parameter style of calling, you can provide
6241*0Sstevel@tonic-gatea single value here or a reference to a whole list
6242*0Sstevel@tonic-gate
6243*0Sstevel@tonic-gate=back
6244*0Sstevel@tonic-gate
6245*0Sstevel@tonic-gateFetch the value of a hidden field this way:
6246*0Sstevel@tonic-gate
6247*0Sstevel@tonic-gate     $hidden_value = $query->param('hidden_name');
6248*0Sstevel@tonic-gate
6249*0Sstevel@tonic-gateNote, that just like all the other form elements, the value of a
6250*0Sstevel@tonic-gatehidden field is "sticky".  If you want to replace a hidden field with
6251*0Sstevel@tonic-gatesome other values after the script has been called once you'll have to
6252*0Sstevel@tonic-gatedo it manually:
6253*0Sstevel@tonic-gate
6254*0Sstevel@tonic-gate     $query->param('hidden_name','new','values','here');
6255*0Sstevel@tonic-gate
6256*0Sstevel@tonic-gate=head2 CREATING A CLICKABLE IMAGE BUTTON
6257*0Sstevel@tonic-gate
6258*0Sstevel@tonic-gate     print $query->image_button(-name=>'button_name',
6259*0Sstevel@tonic-gate				-src=>'/source/URL',
6260*0Sstevel@tonic-gate				-align=>'MIDDLE');
6261*0Sstevel@tonic-gate
6262*0Sstevel@tonic-gate	-or-
6263*0Sstevel@tonic-gate
6264*0Sstevel@tonic-gate     print $query->image_button('button_name','/source/URL','MIDDLE');
6265*0Sstevel@tonic-gate
6266*0Sstevel@tonic-gateimage_button() produces a clickable image.  When it's clicked on the
6267*0Sstevel@tonic-gateposition of the click is returned to your script as "button_name.x"
6268*0Sstevel@tonic-gateand "button_name.y", where "button_name" is the name you've assigned
6269*0Sstevel@tonic-gateto it.
6270*0Sstevel@tonic-gate
6271*0Sstevel@tonic-gateJAVASCRIPTING: image_button() recognizes the B<-onClick>
6272*0Sstevel@tonic-gateparameter.  See checkbox_group() for further details.
6273*0Sstevel@tonic-gate
6274*0Sstevel@tonic-gate=over 4
6275*0Sstevel@tonic-gate
6276*0Sstevel@tonic-gate=item B<Parameters:>
6277*0Sstevel@tonic-gate
6278*0Sstevel@tonic-gate=item 1.
6279*0Sstevel@tonic-gate
6280*0Sstevel@tonic-gateThe first argument (-name) is required and specifies the name of this
6281*0Sstevel@tonic-gatefield.
6282*0Sstevel@tonic-gate
6283*0Sstevel@tonic-gate=item 2.
6284*0Sstevel@tonic-gate
6285*0Sstevel@tonic-gateThe second argument (-src) is also required and specifies the URL
6286*0Sstevel@tonic-gate
6287*0Sstevel@tonic-gate=item 3.
6288*0Sstevel@tonic-gateThe third option (-align, optional) is an alignment type, and may be
6289*0Sstevel@tonic-gateTOP, BOTTOM or MIDDLE
6290*0Sstevel@tonic-gate
6291*0Sstevel@tonic-gate=back
6292*0Sstevel@tonic-gate
6293*0Sstevel@tonic-gateFetch the value of the button this way:
6294*0Sstevel@tonic-gate     $x = $query->param('button_name.x');
6295*0Sstevel@tonic-gate     $y = $query->param('button_name.y');
6296*0Sstevel@tonic-gate
6297*0Sstevel@tonic-gate=head2 CREATING A JAVASCRIPT ACTION BUTTON
6298*0Sstevel@tonic-gate
6299*0Sstevel@tonic-gate     print $query->button(-name=>'button_name',
6300*0Sstevel@tonic-gate			  -value=>'user visible label',
6301*0Sstevel@tonic-gate			  -onClick=>"do_something()");
6302*0Sstevel@tonic-gate
6303*0Sstevel@tonic-gate	-or-
6304*0Sstevel@tonic-gate
6305*0Sstevel@tonic-gate     print $query->button('button_name',"do_something()");
6306*0Sstevel@tonic-gate
6307*0Sstevel@tonic-gatebutton() produces a button that is compatible with Netscape 2.0's
6308*0Sstevel@tonic-gateJavaScript.  When it's pressed the fragment of JavaScript code
6309*0Sstevel@tonic-gatepointed to by the B<-onClick> parameter will be executed.  On
6310*0Sstevel@tonic-gatenon-Netscape browsers this form element will probably not even
6311*0Sstevel@tonic-gatedisplay.
6312*0Sstevel@tonic-gate
6313*0Sstevel@tonic-gate=head1 HTTP COOKIES
6314*0Sstevel@tonic-gate
6315*0Sstevel@tonic-gateNetscape browsers versions 1.1 and higher, and all versions of
6316*0Sstevel@tonic-gateInternet Explorer, support a so-called "cookie" designed to help
6317*0Sstevel@tonic-gatemaintain state within a browser session.  CGI.pm has several methods
6318*0Sstevel@tonic-gatethat support cookies.
6319*0Sstevel@tonic-gate
6320*0Sstevel@tonic-gateA cookie is a name=value pair much like the named parameters in a CGI
6321*0Sstevel@tonic-gatequery string.  CGI scripts create one or more cookies and send
6322*0Sstevel@tonic-gatethem to the browser in the HTTP header.  The browser maintains a list
6323*0Sstevel@tonic-gateof cookies that belong to a particular Web server, and returns them
6324*0Sstevel@tonic-gateto the CGI script during subsequent interactions.
6325*0Sstevel@tonic-gate
6326*0Sstevel@tonic-gateIn addition to the required name=value pair, each cookie has several
6327*0Sstevel@tonic-gateoptional attributes:
6328*0Sstevel@tonic-gate
6329*0Sstevel@tonic-gate=over 4
6330*0Sstevel@tonic-gate
6331*0Sstevel@tonic-gate=item 1. an expiration time
6332*0Sstevel@tonic-gate
6333*0Sstevel@tonic-gateThis is a time/date string (in a special GMT format) that indicates
6334*0Sstevel@tonic-gatewhen a cookie expires.  The cookie will be saved and returned to your
6335*0Sstevel@tonic-gatescript until this expiration date is reached if the user exits
6336*0Sstevel@tonic-gatethe browser and restarts it.  If an expiration date isn't specified, the cookie
6337*0Sstevel@tonic-gatewill remain active until the user quits the browser.
6338*0Sstevel@tonic-gate
6339*0Sstevel@tonic-gate=item 2. a domain
6340*0Sstevel@tonic-gate
6341*0Sstevel@tonic-gateThis is a partial or complete domain name for which the cookie is
6342*0Sstevel@tonic-gatevalid.  The browser will return the cookie to any host that matches
6343*0Sstevel@tonic-gatethe partial domain name.  For example, if you specify a domain name
6344*0Sstevel@tonic-gateof ".capricorn.com", then the browser will return the cookie to
6345*0Sstevel@tonic-gateWeb servers running on any of the machines "www.capricorn.com",
6346*0Sstevel@tonic-gate"www2.capricorn.com", "feckless.capricorn.com", etc.  Domain names
6347*0Sstevel@tonic-gatemust contain at least two periods to prevent attempts to match
6348*0Sstevel@tonic-gateon top level domains like ".edu".  If no domain is specified, then
6349*0Sstevel@tonic-gatethe browser will only return the cookie to servers on the host the
6350*0Sstevel@tonic-gatecookie originated from.
6351*0Sstevel@tonic-gate
6352*0Sstevel@tonic-gate=item 3. a path
6353*0Sstevel@tonic-gate
6354*0Sstevel@tonic-gateIf you provide a cookie path attribute, the browser will check it
6355*0Sstevel@tonic-gateagainst your script's URL before returning the cookie.  For example,
6356*0Sstevel@tonic-gateif you specify the path "/cgi-bin", then the cookie will be returned
6357*0Sstevel@tonic-gateto each of the scripts "/cgi-bin/tally.pl", "/cgi-bin/order.pl",
6358*0Sstevel@tonic-gateand "/cgi-bin/customer_service/complain.pl", but not to the script
6359*0Sstevel@tonic-gate"/cgi-private/site_admin.pl".  By default, path is set to "/", which
6360*0Sstevel@tonic-gatecauses the cookie to be sent to any CGI script on your site.
6361*0Sstevel@tonic-gate
6362*0Sstevel@tonic-gate=item 4. a "secure" flag
6363*0Sstevel@tonic-gate
6364*0Sstevel@tonic-gateIf the "secure" attribute is set, the cookie will only be sent to your
6365*0Sstevel@tonic-gatescript if the CGI request is occurring on a secure channel, such as SSL.
6366*0Sstevel@tonic-gate
6367*0Sstevel@tonic-gate=back
6368*0Sstevel@tonic-gate
6369*0Sstevel@tonic-gateThe interface to HTTP cookies is the B<cookie()> method:
6370*0Sstevel@tonic-gate
6371*0Sstevel@tonic-gate    $cookie = $query->cookie(-name=>'sessionID',
6372*0Sstevel@tonic-gate			     -value=>'xyzzy',
6373*0Sstevel@tonic-gate			     -expires=>'+1h',
6374*0Sstevel@tonic-gate			     -path=>'/cgi-bin/database',
6375*0Sstevel@tonic-gate			     -domain=>'.capricorn.org',
6376*0Sstevel@tonic-gate			     -secure=>1);
6377*0Sstevel@tonic-gate    print $query->header(-cookie=>$cookie);
6378*0Sstevel@tonic-gate
6379*0Sstevel@tonic-gateB<cookie()> creates a new cookie.  Its parameters include:
6380*0Sstevel@tonic-gate
6381*0Sstevel@tonic-gate=over 4
6382*0Sstevel@tonic-gate
6383*0Sstevel@tonic-gate=item B<-name>
6384*0Sstevel@tonic-gate
6385*0Sstevel@tonic-gateThe name of the cookie (required).  This can be any string at all.
6386*0Sstevel@tonic-gateAlthough browsers limit their cookie names to non-whitespace
6387*0Sstevel@tonic-gatealphanumeric characters, CGI.pm removes this restriction by escaping
6388*0Sstevel@tonic-gateand unescaping cookies behind the scenes.
6389*0Sstevel@tonic-gate
6390*0Sstevel@tonic-gate=item B<-value>
6391*0Sstevel@tonic-gate
6392*0Sstevel@tonic-gateThe value of the cookie.  This can be any scalar value,
6393*0Sstevel@tonic-gatearray reference, or even associative array reference.  For example,
6394*0Sstevel@tonic-gateyou can store an entire associative array into a cookie this way:
6395*0Sstevel@tonic-gate
6396*0Sstevel@tonic-gate	$cookie=$query->cookie(-name=>'family information',
6397*0Sstevel@tonic-gate			       -value=>\%childrens_ages);
6398*0Sstevel@tonic-gate
6399*0Sstevel@tonic-gate=item B<-path>
6400*0Sstevel@tonic-gate
6401*0Sstevel@tonic-gateThe optional partial path for which this cookie will be valid, as described
6402*0Sstevel@tonic-gateabove.
6403*0Sstevel@tonic-gate
6404*0Sstevel@tonic-gate=item B<-domain>
6405*0Sstevel@tonic-gate
6406*0Sstevel@tonic-gateThe optional partial domain for which this cookie will be valid, as described
6407*0Sstevel@tonic-gateabove.
6408*0Sstevel@tonic-gate
6409*0Sstevel@tonic-gate=item B<-expires>
6410*0Sstevel@tonic-gate
6411*0Sstevel@tonic-gateThe optional expiration date for this cookie.  The format is as described
6412*0Sstevel@tonic-gatein the section on the B<header()> method:
6413*0Sstevel@tonic-gate
6414*0Sstevel@tonic-gate	"+1h"  one hour from now
6415*0Sstevel@tonic-gate
6416*0Sstevel@tonic-gate=item B<-secure>
6417*0Sstevel@tonic-gate
6418*0Sstevel@tonic-gateIf set to true, this cookie will only be used within a secure
6419*0Sstevel@tonic-gateSSL session.
6420*0Sstevel@tonic-gate
6421*0Sstevel@tonic-gate=back
6422*0Sstevel@tonic-gate
6423*0Sstevel@tonic-gateThe cookie created by cookie() must be incorporated into the HTTP
6424*0Sstevel@tonic-gateheader within the string returned by the header() method:
6425*0Sstevel@tonic-gate
6426*0Sstevel@tonic-gate	print $query->header(-cookie=>$my_cookie);
6427*0Sstevel@tonic-gate
6428*0Sstevel@tonic-gateTo create multiple cookies, give header() an array reference:
6429*0Sstevel@tonic-gate
6430*0Sstevel@tonic-gate	$cookie1 = $query->cookie(-name=>'riddle_name',
6431*0Sstevel@tonic-gate				  -value=>"The Sphynx's Question");
6432*0Sstevel@tonic-gate	$cookie2 = $query->cookie(-name=>'answers',
6433*0Sstevel@tonic-gate				  -value=>\%answers);
6434*0Sstevel@tonic-gate	print $query->header(-cookie=>[$cookie1,$cookie2]);
6435*0Sstevel@tonic-gate
6436*0Sstevel@tonic-gateTo retrieve a cookie, request it by name by calling cookie() method
6437*0Sstevel@tonic-gatewithout the B<-value> parameter:
6438*0Sstevel@tonic-gate
6439*0Sstevel@tonic-gate	use CGI;
6440*0Sstevel@tonic-gate	$query = new CGI;
6441*0Sstevel@tonic-gate	$riddle = $query->cookie('riddle_name');
6442*0Sstevel@tonic-gate        %answers = $query->cookie('answers');
6443*0Sstevel@tonic-gate
6444*0Sstevel@tonic-gateCookies created with a single scalar value, such as the "riddle_name"
6445*0Sstevel@tonic-gatecookie, will be returned in that form.  Cookies with array and hash
6446*0Sstevel@tonic-gatevalues can also be retrieved.
6447*0Sstevel@tonic-gate
6448*0Sstevel@tonic-gateThe cookie and CGI namespaces are separate.  If you have a parameter
6449*0Sstevel@tonic-gatenamed 'answers' and a cookie named 'answers', the values retrieved by
6450*0Sstevel@tonic-gateparam() and cookie() are independent of each other.  However, it's
6451*0Sstevel@tonic-gatesimple to turn a CGI parameter into a cookie, and vice-versa:
6452*0Sstevel@tonic-gate
6453*0Sstevel@tonic-gate   # turn a CGI parameter into a cookie
6454*0Sstevel@tonic-gate   $c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
6455*0Sstevel@tonic-gate   # vice-versa
6456*0Sstevel@tonic-gate   $q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
6457*0Sstevel@tonic-gate
6458*0Sstevel@tonic-gateSee the B<cookie.cgi> example script for some ideas on how to use
6459*0Sstevel@tonic-gatecookies effectively.
6460*0Sstevel@tonic-gate
6461*0Sstevel@tonic-gate=head1 WORKING WITH FRAMES
6462*0Sstevel@tonic-gate
6463*0Sstevel@tonic-gateIt's possible for CGI.pm scripts to write into several browser panels
6464*0Sstevel@tonic-gateand windows using the HTML 4 frame mechanism.  There are three
6465*0Sstevel@tonic-gatetechniques for defining new frames programmatically:
6466*0Sstevel@tonic-gate
6467*0Sstevel@tonic-gate=over 4
6468*0Sstevel@tonic-gate
6469*0Sstevel@tonic-gate=item 1. Create a <Frameset> document
6470*0Sstevel@tonic-gate
6471*0Sstevel@tonic-gateAfter writing out the HTTP header, instead of creating a standard
6472*0Sstevel@tonic-gateHTML document using the start_html() call, create a <frameset>
6473*0Sstevel@tonic-gatedocument that defines the frames on the page.  Specify your script(s)
6474*0Sstevel@tonic-gate(with appropriate parameters) as the SRC for each of the frames.
6475*0Sstevel@tonic-gate
6476*0Sstevel@tonic-gateThere is no specific support for creating <frameset> sections
6477*0Sstevel@tonic-gatein CGI.pm, but the HTML is very simple to write.  See the frame
6478*0Sstevel@tonic-gatedocumentation in Netscape's home pages for details
6479*0Sstevel@tonic-gate
6480*0Sstevel@tonic-gate  http://home.netscape.com/assist/net_sites/frames.html
6481*0Sstevel@tonic-gate
6482*0Sstevel@tonic-gate=item 2. Specify the destination for the document in the HTTP header
6483*0Sstevel@tonic-gate
6484*0Sstevel@tonic-gateYou may provide a B<-target> parameter to the header() method:
6485*0Sstevel@tonic-gate
6486*0Sstevel@tonic-gate    print $q->header(-target=>'ResultsWindow');
6487*0Sstevel@tonic-gate
6488*0Sstevel@tonic-gateThis will tell the browser to load the output of your script into the
6489*0Sstevel@tonic-gateframe named "ResultsWindow".  If a frame of that name doesn't already
6490*0Sstevel@tonic-gateexist, the browser will pop up a new window and load your script's
6491*0Sstevel@tonic-gatedocument into that.  There are a number of magic names that you can
6492*0Sstevel@tonic-gateuse for targets.  See the frame documents on Netscape's home pages for
6493*0Sstevel@tonic-gatedetails.
6494*0Sstevel@tonic-gate
6495*0Sstevel@tonic-gate=item 3. Specify the destination for the document in the <form> tag
6496*0Sstevel@tonic-gate
6497*0Sstevel@tonic-gateYou can specify the frame to load in the FORM tag itself.  With
6498*0Sstevel@tonic-gateCGI.pm it looks like this:
6499*0Sstevel@tonic-gate
6500*0Sstevel@tonic-gate    print $q->start_form(-target=>'ResultsWindow');
6501*0Sstevel@tonic-gate
6502*0Sstevel@tonic-gateWhen your script is reinvoked by the form, its output will be loaded
6503*0Sstevel@tonic-gateinto the frame named "ResultsWindow".  If one doesn't already exist
6504*0Sstevel@tonic-gatea new window will be created.
6505*0Sstevel@tonic-gate
6506*0Sstevel@tonic-gate=back
6507*0Sstevel@tonic-gate
6508*0Sstevel@tonic-gateThe script "frameset.cgi" in the examples directory shows one way to
6509*0Sstevel@tonic-gatecreate pages in which the fill-out form and the response live in
6510*0Sstevel@tonic-gateside-by-side frames.
6511*0Sstevel@tonic-gate
6512*0Sstevel@tonic-gate=head1 LIMITED SUPPORT FOR CASCADING STYLE SHEETS
6513*0Sstevel@tonic-gate
6514*0Sstevel@tonic-gateCGI.pm has limited support for HTML3's cascading style sheets (css).
6515*0Sstevel@tonic-gateTo incorporate a stylesheet into your document, pass the
6516*0Sstevel@tonic-gatestart_html() method a B<-style> parameter.  The value of this
6517*0Sstevel@tonic-gateparameter may be a scalar, in which case it is treated as the source
6518*0Sstevel@tonic-gateURL for the stylesheet, or it may be a hash reference.  In the latter
6519*0Sstevel@tonic-gatecase you should provide the hash with one or more of B<-src> or
6520*0Sstevel@tonic-gateB<-code>.  B<-src> points to a URL where an externally-defined
6521*0Sstevel@tonic-gatestylesheet can be found.  B<-code> points to a scalar value to be
6522*0Sstevel@tonic-gateincorporated into a <style> section.  Style definitions in B<-code>
6523*0Sstevel@tonic-gateoverride similarly-named ones in B<-src>, hence the name "cascading."
6524*0Sstevel@tonic-gate
6525*0Sstevel@tonic-gateYou may also specify the type of the stylesheet by adding the optional
6526*0Sstevel@tonic-gateB<-type> parameter to the hash pointed to by B<-style>.  If not
6527*0Sstevel@tonic-gatespecified, the style defaults to 'text/css'.
6528*0Sstevel@tonic-gate
6529*0Sstevel@tonic-gateTo refer to a style within the body of your document, add the
6530*0Sstevel@tonic-gateB<-class> parameter to any HTML element:
6531*0Sstevel@tonic-gate
6532*0Sstevel@tonic-gate    print h1({-class=>'Fancy'},'Welcome to the Party');
6533*0Sstevel@tonic-gate
6534*0Sstevel@tonic-gateOr define styles on the fly with the B<-style> parameter:
6535*0Sstevel@tonic-gate
6536*0Sstevel@tonic-gate    print h1({-style=>'Color: red;'},'Welcome to Hell');
6537*0Sstevel@tonic-gate
6538*0Sstevel@tonic-gateYou may also use the new B<span()> element to apply a style to a
6539*0Sstevel@tonic-gatesection of text:
6540*0Sstevel@tonic-gate
6541*0Sstevel@tonic-gate    print span({-style=>'Color: red;'},
6542*0Sstevel@tonic-gate	       h1('Welcome to Hell'),
6543*0Sstevel@tonic-gate	       "Where did that handbasket get to?"
6544*0Sstevel@tonic-gate	       );
6545*0Sstevel@tonic-gate
6546*0Sstevel@tonic-gateNote that you must import the ":html3" definitions to have the
6547*0Sstevel@tonic-gateB<span()> method available.  Here's a quick and dirty example of using
6548*0Sstevel@tonic-gateCSS's.  See the CSS specification at
6549*0Sstevel@tonic-gatehttp://www.w3.org/pub/WWW/TR/Wd-css-1.html for more information.
6550*0Sstevel@tonic-gate
6551*0Sstevel@tonic-gate    use CGI qw/:standard :html3/;
6552*0Sstevel@tonic-gate
6553*0Sstevel@tonic-gate    #here's a stylesheet incorporated directly into the page
6554*0Sstevel@tonic-gate    $newStyle=<<END;
6555*0Sstevel@tonic-gate    <!--
6556*0Sstevel@tonic-gate    P.Tip {
6557*0Sstevel@tonic-gate	margin-right: 50pt;
6558*0Sstevel@tonic-gate	margin-left: 50pt;
6559*0Sstevel@tonic-gate        color: red;
6560*0Sstevel@tonic-gate    }
6561*0Sstevel@tonic-gate    P.Alert {
6562*0Sstevel@tonic-gate	font-size: 30pt;
6563*0Sstevel@tonic-gate        font-family: sans-serif;
6564*0Sstevel@tonic-gate      color: red;
6565*0Sstevel@tonic-gate    }
6566*0Sstevel@tonic-gate    -->
6567*0Sstevel@tonic-gate    END
6568*0Sstevel@tonic-gate    print header();
6569*0Sstevel@tonic-gate    print start_html( -title=>'CGI with Style',
6570*0Sstevel@tonic-gate		      -style=>{-src=>'http://www.capricorn.com/style/st1.css',
6571*0Sstevel@tonic-gate		               -code=>$newStyle}
6572*0Sstevel@tonic-gate	             );
6573*0Sstevel@tonic-gate    print h1('CGI with Style'),
6574*0Sstevel@tonic-gate          p({-class=>'Tip'},
6575*0Sstevel@tonic-gate	    "Better read the cascading style sheet spec before playing with this!"),
6576*0Sstevel@tonic-gate          span({-style=>'color: magenta'},
6577*0Sstevel@tonic-gate	       "Look Mom, no hands!",
6578*0Sstevel@tonic-gate	       p(),
6579*0Sstevel@tonic-gate	       "Whooo wee!"
6580*0Sstevel@tonic-gate	       );
6581*0Sstevel@tonic-gate    print end_html;
6582*0Sstevel@tonic-gate
6583*0Sstevel@tonic-gatePass an array reference to B<-style> in order to incorporate multiple
6584*0Sstevel@tonic-gatestylesheets into your document.
6585*0Sstevel@tonic-gate
6586*0Sstevel@tonic-gateShould you wish to incorporate a verbatim stylesheet that includes
6587*0Sstevel@tonic-gatearbitrary formatting in the header, you may pass a -verbatim tag to
6588*0Sstevel@tonic-gatethe -style hash, as follows:
6589*0Sstevel@tonic-gate
6590*0Sstevel@tonic-gateprint $q->start_html (-STYLE  =>  {-verbatim => '@import
6591*0Sstevel@tonic-gateurl("/server-common/css/'.$cssFile.'");',
6592*0Sstevel@tonic-gate                      -src      =>  '/server-common/css/core.css'});
6593*0Sstevel@tonic-gate</blockquote></pre>
6594*0Sstevel@tonic-gate
6595*0Sstevel@tonic-gate
6596*0Sstevel@tonic-gateThis will generate an HTML header that contains this:
6597*0Sstevel@tonic-gate
6598*0Sstevel@tonic-gate <link rel="stylesheet" type="text/css"  href="/server-common/css/core.css">
6599*0Sstevel@tonic-gate   <style type="text/css">
6600*0Sstevel@tonic-gate   @import url("/server-common/css/main.css");
6601*0Sstevel@tonic-gate   </style>
6602*0Sstevel@tonic-gate
6603*0Sstevel@tonic-gateAny additional arguments passed in the -style value will be
6604*0Sstevel@tonic-gateincorporated into the <link> tag.  For example:
6605*0Sstevel@tonic-gate
6606*0Sstevel@tonic-gate start_html(-style=>{-src=>['/styles/print.css','/styles/layout.css'],
6607*0Sstevel@tonic-gate			  -media => 'all'});
6608*0Sstevel@tonic-gate
6609*0Sstevel@tonic-gateThis will give:
6610*0Sstevel@tonic-gate
6611*0Sstevel@tonic-gate <link rel="stylesheet" type="text/css" href="/styles/print.css" media="all"/>
6612*0Sstevel@tonic-gate <link rel="stylesheet" type="text/css" href="/styles/layout.css" media="all"/>
6613*0Sstevel@tonic-gate
6614*0Sstevel@tonic-gate<p>
6615*0Sstevel@tonic-gate
6616*0Sstevel@tonic-gateTo make more complicated <link> tags, use the Link() function
6617*0Sstevel@tonic-gateand pass it to start_html() in the -head argument, as in:
6618*0Sstevel@tonic-gate
6619*0Sstevel@tonic-gate  @h = (Link({-rel=>'stylesheet',-type=>'text/css',-src=>'/ss/ss.css',-media=>'all'}),
6620*0Sstevel@tonic-gate        Link({-rel=>'stylesheet',-type=>'text/css',-src=>'/ss/fred.css',-media=>'paper'}));
6621*0Sstevel@tonic-gate  print start_html({-head=>\@h})
6622*0Sstevel@tonic-gate
6623*0Sstevel@tonic-gate=head1 DEBUGGING
6624*0Sstevel@tonic-gate
6625*0Sstevel@tonic-gateIf you are running the script from the command line or in the perl
6626*0Sstevel@tonic-gatedebugger, you can pass the script a list of keywords or
6627*0Sstevel@tonic-gateparameter=value pairs on the command line or from standard input (you
6628*0Sstevel@tonic-gatedon't have to worry about tricking your script into reading from
6629*0Sstevel@tonic-gateenvironment variables).  You can pass keywords like this:
6630*0Sstevel@tonic-gate
6631*0Sstevel@tonic-gate    your_script.pl keyword1 keyword2 keyword3
6632*0Sstevel@tonic-gate
6633*0Sstevel@tonic-gateor this:
6634*0Sstevel@tonic-gate
6635*0Sstevel@tonic-gate   your_script.pl keyword1+keyword2+keyword3
6636*0Sstevel@tonic-gate
6637*0Sstevel@tonic-gateor this:
6638*0Sstevel@tonic-gate
6639*0Sstevel@tonic-gate    your_script.pl name1=value1 name2=value2
6640*0Sstevel@tonic-gate
6641*0Sstevel@tonic-gateor this:
6642*0Sstevel@tonic-gate
6643*0Sstevel@tonic-gate    your_script.pl name1=value1&name2=value2
6644*0Sstevel@tonic-gate
6645*0Sstevel@tonic-gateTo turn off this feature, use the -no_debug pragma.
6646*0Sstevel@tonic-gate
6647*0Sstevel@tonic-gateTo test the POST method, you may enable full debugging with the -debug
6648*0Sstevel@tonic-gatepragma.  This will allow you to feed newline-delimited name=value
6649*0Sstevel@tonic-gatepairs to the script on standard input.
6650*0Sstevel@tonic-gate
6651*0Sstevel@tonic-gateWhen debugging, you can use quotes and backslashes to escape
6652*0Sstevel@tonic-gatecharacters in the familiar shell manner, letting you place
6653*0Sstevel@tonic-gatespaces and other funny characters in your parameter=value
6654*0Sstevel@tonic-gatepairs:
6655*0Sstevel@tonic-gate
6656*0Sstevel@tonic-gate   your_script.pl "name1='I am a long value'" "name2=two\ words"
6657*0Sstevel@tonic-gate
6658*0Sstevel@tonic-gateFinally, you can set the path info for the script by prefixing the first
6659*0Sstevel@tonic-gatename/value parameter with the path followed by a question mark (?):
6660*0Sstevel@tonic-gate
6661*0Sstevel@tonic-gate    your_script.pl /your/path/here?name1=value1&name2=value2
6662*0Sstevel@tonic-gate
6663*0Sstevel@tonic-gate=head2 DUMPING OUT ALL THE NAME/VALUE PAIRS
6664*0Sstevel@tonic-gate
6665*0Sstevel@tonic-gateThe Dump() method produces a string consisting of all the query's
6666*0Sstevel@tonic-gatename/value pairs formatted nicely as a nested list.  This is useful
6667*0Sstevel@tonic-gatefor debugging purposes:
6668*0Sstevel@tonic-gate
6669*0Sstevel@tonic-gate    print $query->Dump
6670*0Sstevel@tonic-gate
6671*0Sstevel@tonic-gate
6672*0Sstevel@tonic-gateProduces something that looks like:
6673*0Sstevel@tonic-gate
6674*0Sstevel@tonic-gate    <ul>
6675*0Sstevel@tonic-gate    <li>name1
6676*0Sstevel@tonic-gate	<ul>
6677*0Sstevel@tonic-gate	<li>value1
6678*0Sstevel@tonic-gate	<li>value2
6679*0Sstevel@tonic-gate	</ul>
6680*0Sstevel@tonic-gate    <li>name2
6681*0Sstevel@tonic-gate	<ul>
6682*0Sstevel@tonic-gate	<li>value1
6683*0Sstevel@tonic-gate	</ul>
6684*0Sstevel@tonic-gate    </ul>
6685*0Sstevel@tonic-gate
6686*0Sstevel@tonic-gateAs a shortcut, you can interpolate the entire CGI object into a string
6687*0Sstevel@tonic-gateand it will be replaced with the a nice HTML dump shown above:
6688*0Sstevel@tonic-gate
6689*0Sstevel@tonic-gate    $query=new CGI;
6690*0Sstevel@tonic-gate    print "<h2>Current Values</h2> $query\n";
6691*0Sstevel@tonic-gate
6692*0Sstevel@tonic-gate=head1 FETCHING ENVIRONMENT VARIABLES
6693*0Sstevel@tonic-gate
6694*0Sstevel@tonic-gateSome of the more useful environment variables can be fetched
6695*0Sstevel@tonic-gatethrough this interface.  The methods are as follows:
6696*0Sstevel@tonic-gate
6697*0Sstevel@tonic-gate=over 4
6698*0Sstevel@tonic-gate
6699*0Sstevel@tonic-gate=item B<Accept()>
6700*0Sstevel@tonic-gate
6701*0Sstevel@tonic-gateReturn a list of MIME types that the remote browser accepts. If you
6702*0Sstevel@tonic-gategive this method a single argument corresponding to a MIME type, as in
6703*0Sstevel@tonic-gate$query->Accept('text/html'), it will return a floating point value
6704*0Sstevel@tonic-gatecorresponding to the browser's preference for this type from 0.0
6705*0Sstevel@tonic-gate(don't want) to 1.0.  Glob types (e.g. text/*) in the browser's accept
6706*0Sstevel@tonic-gatelist are handled correctly.
6707*0Sstevel@tonic-gate
6708*0Sstevel@tonic-gateNote that the capitalization changed between version 2.43 and 2.44 in
6709*0Sstevel@tonic-gateorder to avoid conflict with Perl's accept() function.
6710*0Sstevel@tonic-gate
6711*0Sstevel@tonic-gate=item B<raw_cookie()>
6712*0Sstevel@tonic-gate
6713*0Sstevel@tonic-gateReturns the HTTP_COOKIE variable, an HTTP extension implemented by
6714*0Sstevel@tonic-gateNetscape browsers version 1.1 and higher, and all versions of Internet
6715*0Sstevel@tonic-gateExplorer.  Cookies have a special format, and this method call just
6716*0Sstevel@tonic-gatereturns the raw form (?cookie dough).  See cookie() for ways of
6717*0Sstevel@tonic-gatesetting and retrieving cooked cookies.
6718*0Sstevel@tonic-gate
6719*0Sstevel@tonic-gateCalled with no parameters, raw_cookie() returns the packed cookie
6720*0Sstevel@tonic-gatestructure.  You can separate it into individual cookies by splitting
6721*0Sstevel@tonic-gateon the character sequence "; ".  Called with the name of a cookie,
6722*0Sstevel@tonic-gateretrieves the B<unescaped> form of the cookie.  You can use the
6723*0Sstevel@tonic-gateregular cookie() method to get the names, or use the raw_fetch()
6724*0Sstevel@tonic-gatemethod from the CGI::Cookie module.
6725*0Sstevel@tonic-gate
6726*0Sstevel@tonic-gate=item B<user_agent()>
6727*0Sstevel@tonic-gate
6728*0Sstevel@tonic-gateReturns the HTTP_USER_AGENT variable.  If you give
6729*0Sstevel@tonic-gatethis method a single argument, it will attempt to
6730*0Sstevel@tonic-gatepattern match on it, allowing you to do something
6731*0Sstevel@tonic-gatelike $query->user_agent(netscape);
6732*0Sstevel@tonic-gate
6733*0Sstevel@tonic-gate=item B<path_info()>
6734*0Sstevel@tonic-gate
6735*0Sstevel@tonic-gateReturns additional path information from the script URL.
6736*0Sstevel@tonic-gateE.G. fetching /cgi-bin/your_script/additional/stuff will result in
6737*0Sstevel@tonic-gate$query->path_info() returning "/additional/stuff".
6738*0Sstevel@tonic-gate
6739*0Sstevel@tonic-gateNOTE: The Microsoft Internet Information Server
6740*0Sstevel@tonic-gateis broken with respect to additional path information.  If
6741*0Sstevel@tonic-gateyou use the Perl DLL library, the IIS server will attempt to
6742*0Sstevel@tonic-gateexecute the additional path information as a Perl script.
6743*0Sstevel@tonic-gateIf you use the ordinary file associations mapping, the
6744*0Sstevel@tonic-gatepath information will be present in the environment,
6745*0Sstevel@tonic-gatebut incorrect.  The best thing to do is to avoid using additional
6746*0Sstevel@tonic-gatepath information in CGI scripts destined for use with IIS.
6747*0Sstevel@tonic-gate
6748*0Sstevel@tonic-gate=item B<path_translated()>
6749*0Sstevel@tonic-gate
6750*0Sstevel@tonic-gateAs per path_info() but returns the additional
6751*0Sstevel@tonic-gatepath information translated into a physical path, e.g.
6752*0Sstevel@tonic-gate"/usr/local/etc/httpd/htdocs/additional/stuff".
6753*0Sstevel@tonic-gate
6754*0Sstevel@tonic-gateThe Microsoft IIS is broken with respect to the translated
6755*0Sstevel@tonic-gatepath as well.
6756*0Sstevel@tonic-gate
6757*0Sstevel@tonic-gate=item B<remote_host()>
6758*0Sstevel@tonic-gate
6759*0Sstevel@tonic-gateReturns either the remote host name or IP address.
6760*0Sstevel@tonic-gateif the former is unavailable.
6761*0Sstevel@tonic-gate
6762*0Sstevel@tonic-gate=item B<script_name()>
6763*0Sstevel@tonic-gateReturn the script name as a partial URL, for self-refering
6764*0Sstevel@tonic-gatescripts.
6765*0Sstevel@tonic-gate
6766*0Sstevel@tonic-gate=item B<referer()>
6767*0Sstevel@tonic-gate
6768*0Sstevel@tonic-gateReturn the URL of the page the browser was viewing
6769*0Sstevel@tonic-gateprior to fetching your script.  Not available for all
6770*0Sstevel@tonic-gatebrowsers.
6771*0Sstevel@tonic-gate
6772*0Sstevel@tonic-gate=item B<auth_type ()>
6773*0Sstevel@tonic-gate
6774*0Sstevel@tonic-gateReturn the authorization/verification method in use for this
6775*0Sstevel@tonic-gatescript, if any.
6776*0Sstevel@tonic-gate
6777*0Sstevel@tonic-gate=item B<server_name ()>
6778*0Sstevel@tonic-gate
6779*0Sstevel@tonic-gateReturns the name of the server, usually the machine's host
6780*0Sstevel@tonic-gatename.
6781*0Sstevel@tonic-gate
6782*0Sstevel@tonic-gate=item B<virtual_host ()>
6783*0Sstevel@tonic-gate
6784*0Sstevel@tonic-gateWhen using virtual hosts, returns the name of the host that
6785*0Sstevel@tonic-gatethe browser attempted to contact
6786*0Sstevel@tonic-gate
6787*0Sstevel@tonic-gate=item B<server_port ()>
6788*0Sstevel@tonic-gate
6789*0Sstevel@tonic-gateReturn the port that the server is listening on.
6790*0Sstevel@tonic-gate
6791*0Sstevel@tonic-gate=item B<virtual_port ()>
6792*0Sstevel@tonic-gate
6793*0Sstevel@tonic-gateLike server_port() except that it takes virtual hosts into account.
6794*0Sstevel@tonic-gateUse this when running with virtual hosts.
6795*0Sstevel@tonic-gate
6796*0Sstevel@tonic-gate=item B<server_software ()>
6797*0Sstevel@tonic-gate
6798*0Sstevel@tonic-gateReturns the server software and version number.
6799*0Sstevel@tonic-gate
6800*0Sstevel@tonic-gate=item B<remote_user ()>
6801*0Sstevel@tonic-gate
6802*0Sstevel@tonic-gateReturn the authorization/verification name used for user
6803*0Sstevel@tonic-gateverification, if this script is protected.
6804*0Sstevel@tonic-gate
6805*0Sstevel@tonic-gate=item B<user_name ()>
6806*0Sstevel@tonic-gate
6807*0Sstevel@tonic-gateAttempt to obtain the remote user's name, using a variety of different
6808*0Sstevel@tonic-gatetechniques.  This only works with older browsers such as Mosaic.
6809*0Sstevel@tonic-gateNewer browsers do not report the user name for privacy reasons!
6810*0Sstevel@tonic-gate
6811*0Sstevel@tonic-gate=item B<request_method()>
6812*0Sstevel@tonic-gate
6813*0Sstevel@tonic-gateReturns the method used to access your script, usually
6814*0Sstevel@tonic-gateone of 'POST', 'GET' or 'HEAD'.
6815*0Sstevel@tonic-gate
6816*0Sstevel@tonic-gate=item B<content_type()>
6817*0Sstevel@tonic-gate
6818*0Sstevel@tonic-gateReturns the content_type of data submitted in a POST, generally
6819*0Sstevel@tonic-gatemultipart/form-data or application/x-www-form-urlencoded
6820*0Sstevel@tonic-gate
6821*0Sstevel@tonic-gate=item B<http()>
6822*0Sstevel@tonic-gate
6823*0Sstevel@tonic-gateCalled with no arguments returns the list of HTTP environment
6824*0Sstevel@tonic-gatevariables, including such things as HTTP_USER_AGENT,
6825*0Sstevel@tonic-gateHTTP_ACCEPT_LANGUAGE, and HTTP_ACCEPT_CHARSET, corresponding to the
6826*0Sstevel@tonic-gatelike-named HTTP header fields in the request.  Called with the name of
6827*0Sstevel@tonic-gatean HTTP header field, returns its value.  Capitalization and the use
6828*0Sstevel@tonic-gateof hyphens versus underscores are not significant.
6829*0Sstevel@tonic-gate
6830*0Sstevel@tonic-gateFor example, all three of these examples are equivalent:
6831*0Sstevel@tonic-gate
6832*0Sstevel@tonic-gate   $requested_language = $q->http('Accept-language');
6833*0Sstevel@tonic-gate   $requested_language = $q->http('Accept_language');
6834*0Sstevel@tonic-gate   $requested_language = $q->http('HTTP_ACCEPT_LANGUAGE');
6835*0Sstevel@tonic-gate
6836*0Sstevel@tonic-gate=item B<https()>
6837*0Sstevel@tonic-gate
6838*0Sstevel@tonic-gateThe same as I<http()>, but operates on the HTTPS environment variables
6839*0Sstevel@tonic-gatepresent when the SSL protocol is in effect.  Can be used to determine
6840*0Sstevel@tonic-gatewhether SSL is turned on.
6841*0Sstevel@tonic-gate
6842*0Sstevel@tonic-gate=back
6843*0Sstevel@tonic-gate
6844*0Sstevel@tonic-gate=head1 USING NPH SCRIPTS
6845*0Sstevel@tonic-gate
6846*0Sstevel@tonic-gateNPH, or "no-parsed-header", scripts bypass the server completely by
6847*0Sstevel@tonic-gatesending the complete HTTP header directly to the browser.  This has
6848*0Sstevel@tonic-gateslight performance benefits, but is of most use for taking advantage
6849*0Sstevel@tonic-gateof HTTP extensions that are not directly supported by your server,
6850*0Sstevel@tonic-gatesuch as server push and PICS headers.
6851*0Sstevel@tonic-gate
6852*0Sstevel@tonic-gateServers use a variety of conventions for designating CGI scripts as
6853*0Sstevel@tonic-gateNPH.  Many Unix servers look at the beginning of the script's name for
6854*0Sstevel@tonic-gatethe prefix "nph-".  The Macintosh WebSTAR server and Microsoft's
6855*0Sstevel@tonic-gateInternet Information Server, in contrast, try to decide whether a
6856*0Sstevel@tonic-gateprogram is an NPH script by examining the first line of script output.
6857*0Sstevel@tonic-gate
6858*0Sstevel@tonic-gate
6859*0Sstevel@tonic-gateCGI.pm supports NPH scripts with a special NPH mode.  When in this
6860*0Sstevel@tonic-gatemode, CGI.pm will output the necessary extra header information when
6861*0Sstevel@tonic-gatethe header() and redirect() methods are
6862*0Sstevel@tonic-gatecalled.
6863*0Sstevel@tonic-gate
6864*0Sstevel@tonic-gateThe Microsoft Internet Information Server requires NPH mode.  As of
6865*0Sstevel@tonic-gateversion 2.30, CGI.pm will automatically detect when the script is
6866*0Sstevel@tonic-gaterunning under IIS and put itself into this mode.  You do not need to
6867*0Sstevel@tonic-gatedo this manually, although it won't hurt anything if you do.  However,
6868*0Sstevel@tonic-gatenote that if you have applied Service Pack 6, much of the
6869*0Sstevel@tonic-gatefunctionality of NPH scripts, including the ability to redirect while
6870*0Sstevel@tonic-gatesetting a cookie, b<do not work at all> on IIS without a special patch
6871*0Sstevel@tonic-gatefrom Microsoft.  See
6872*0Sstevel@tonic-gatehttp://support.microsoft.com/support/kb/articles/Q280/3/41.ASP:
6873*0Sstevel@tonic-gateNon-Parsed Headers Stripped From CGI Applications That Have nph-
6874*0Sstevel@tonic-gatePrefix in Name.
6875*0Sstevel@tonic-gate
6876*0Sstevel@tonic-gate=over 4
6877*0Sstevel@tonic-gate
6878*0Sstevel@tonic-gate=item In the B<use> statement
6879*0Sstevel@tonic-gate
6880*0Sstevel@tonic-gateSimply add the "-nph" pragmato the list of symbols to be imported into
6881*0Sstevel@tonic-gateyour script:
6882*0Sstevel@tonic-gate
6883*0Sstevel@tonic-gate      use CGI qw(:standard -nph)
6884*0Sstevel@tonic-gate
6885*0Sstevel@tonic-gate=item By calling the B<nph()> method:
6886*0Sstevel@tonic-gate
6887*0Sstevel@tonic-gateCall B<nph()> with a non-zero parameter at any point after using CGI.pm in your program.
6888*0Sstevel@tonic-gate
6889*0Sstevel@tonic-gate      CGI->nph(1)
6890*0Sstevel@tonic-gate
6891*0Sstevel@tonic-gate=item By using B<-nph> parameters
6892*0Sstevel@tonic-gate
6893*0Sstevel@tonic-gatein the B<header()> and B<redirect()>  statements:
6894*0Sstevel@tonic-gate
6895*0Sstevel@tonic-gate      print $q->header(-nph=>1);
6896*0Sstevel@tonic-gate
6897*0Sstevel@tonic-gate=back
6898*0Sstevel@tonic-gate
6899*0Sstevel@tonic-gate=head1 Server Push
6900*0Sstevel@tonic-gate
6901*0Sstevel@tonic-gateCGI.pm provides four simple functions for producing multipart
6902*0Sstevel@tonic-gatedocuments of the type needed to implement server push.  These
6903*0Sstevel@tonic-gatefunctions were graciously provided by Ed Jordan <ed@fidalgo.net>.  To
6904*0Sstevel@tonic-gateimport these into your namespace, you must import the ":push" set.
6905*0Sstevel@tonic-gateYou are also advised to put the script into NPH mode and to set $| to
6906*0Sstevel@tonic-gate1 to avoid buffering problems.
6907*0Sstevel@tonic-gate
6908*0Sstevel@tonic-gateHere is a simple script that demonstrates server push:
6909*0Sstevel@tonic-gate
6910*0Sstevel@tonic-gate  #!/usr/local/bin/perl
6911*0Sstevel@tonic-gate  use CGI qw/:push -nph/;
6912*0Sstevel@tonic-gate  $| = 1;
6913*0Sstevel@tonic-gate  print multipart_init(-boundary=>'----here we go!');
6914*0Sstevel@tonic-gate  foreach (0 .. 4) {
6915*0Sstevel@tonic-gate      print multipart_start(-type=>'text/plain'),
6916*0Sstevel@tonic-gate            "The current time is ",scalar(localtime),"\n";
6917*0Sstevel@tonic-gate      if ($_ < 4) {
6918*0Sstevel@tonic-gate              print multipart_end;
6919*0Sstevel@tonic-gate      } else {
6920*0Sstevel@tonic-gate              print multipart_final;
6921*0Sstevel@tonic-gate      }
6922*0Sstevel@tonic-gate      sleep 1;
6923*0Sstevel@tonic-gate  }
6924*0Sstevel@tonic-gate
6925*0Sstevel@tonic-gateThis script initializes server push by calling B<multipart_init()>.
6926*0Sstevel@tonic-gateIt then enters a loop in which it begins a new multipart section by
6927*0Sstevel@tonic-gatecalling B<multipart_start()>, prints the current local time,
6928*0Sstevel@tonic-gateand ends a multipart section with B<multipart_end()>.  It then sleeps
6929*0Sstevel@tonic-gatea second, and begins again. On the final iteration, it ends the
6930*0Sstevel@tonic-gatemultipart section with B<multipart_final()> rather than with
6931*0Sstevel@tonic-gateB<multipart_end()>.
6932*0Sstevel@tonic-gate
6933*0Sstevel@tonic-gate=over 4
6934*0Sstevel@tonic-gate
6935*0Sstevel@tonic-gate=item multipart_init()
6936*0Sstevel@tonic-gate
6937*0Sstevel@tonic-gate  multipart_init(-boundary=>$boundary);
6938*0Sstevel@tonic-gate
6939*0Sstevel@tonic-gateInitialize the multipart system.  The -boundary argument specifies
6940*0Sstevel@tonic-gatewhat MIME boundary string to use to separate parts of the document.
6941*0Sstevel@tonic-gateIf not provided, CGI.pm chooses a reasonable boundary for you.
6942*0Sstevel@tonic-gate
6943*0Sstevel@tonic-gate=item multipart_start()
6944*0Sstevel@tonic-gate
6945*0Sstevel@tonic-gate  multipart_start(-type=>$type)
6946*0Sstevel@tonic-gate
6947*0Sstevel@tonic-gateStart a new part of the multipart document using the specified MIME
6948*0Sstevel@tonic-gatetype.  If not specified, text/html is assumed.
6949*0Sstevel@tonic-gate
6950*0Sstevel@tonic-gate=item multipart_end()
6951*0Sstevel@tonic-gate
6952*0Sstevel@tonic-gate  multipart_end()
6953*0Sstevel@tonic-gate
6954*0Sstevel@tonic-gateEnd a part.  You must remember to call multipart_end() once for each
6955*0Sstevel@tonic-gatemultipart_start(), except at the end of the last part of the multipart
6956*0Sstevel@tonic-gatedocument when multipart_final() should be called instead of multipart_end().
6957*0Sstevel@tonic-gate
6958*0Sstevel@tonic-gate=item multipart_final()
6959*0Sstevel@tonic-gate
6960*0Sstevel@tonic-gate  multipart_final()
6961*0Sstevel@tonic-gate
6962*0Sstevel@tonic-gateEnd all parts.  You should call multipart_final() rather than
6963*0Sstevel@tonic-gatemultipart_end() at the end of the last part of the multipart document.
6964*0Sstevel@tonic-gate
6965*0Sstevel@tonic-gate=back
6966*0Sstevel@tonic-gate
6967*0Sstevel@tonic-gateUsers interested in server push applications should also have a look
6968*0Sstevel@tonic-gateat the CGI::Push module.
6969*0Sstevel@tonic-gate
6970*0Sstevel@tonic-gateOnly Netscape Navigator supports server push.  Internet Explorer
6971*0Sstevel@tonic-gatebrowsers do not.
6972*0Sstevel@tonic-gate
6973*0Sstevel@tonic-gate=head1 Avoiding Denial of Service Attacks
6974*0Sstevel@tonic-gate
6975*0Sstevel@tonic-gateA potential problem with CGI.pm is that, by default, it attempts to
6976*0Sstevel@tonic-gateprocess form POSTings no matter how large they are.  A wily hacker
6977*0Sstevel@tonic-gatecould attack your site by sending a CGI script a huge POST of many
6978*0Sstevel@tonic-gatemegabytes.  CGI.pm will attempt to read the entire POST into a
6979*0Sstevel@tonic-gatevariable, growing hugely in size until it runs out of memory.  While
6980*0Sstevel@tonic-gatethe script attempts to allocate the memory the system may slow down
6981*0Sstevel@tonic-gatedramatically.  This is a form of denial of service attack.
6982*0Sstevel@tonic-gate
6983*0Sstevel@tonic-gateAnother possible attack is for the remote user to force CGI.pm to
6984*0Sstevel@tonic-gateaccept a huge file upload.  CGI.pm will accept the upload and store it
6985*0Sstevel@tonic-gatein a temporary directory even if your script doesn't expect to receive
6986*0Sstevel@tonic-gatean uploaded file.  CGI.pm will delete the file automatically when it
6987*0Sstevel@tonic-gateterminates, but in the meantime the remote user may have filled up the
6988*0Sstevel@tonic-gateserver's disk space, causing problems for other programs.
6989*0Sstevel@tonic-gate
6990*0Sstevel@tonic-gateThe best way to avoid denial of service attacks is to limit the amount
6991*0Sstevel@tonic-gateof memory, CPU time and disk space that CGI scripts can use.  Some Web
6992*0Sstevel@tonic-gateservers come with built-in facilities to accomplish this. In other
6993*0Sstevel@tonic-gatecases, you can use the shell I<limit> or I<ulimit>
6994*0Sstevel@tonic-gatecommands to put ceilings on CGI resource usage.
6995*0Sstevel@tonic-gate
6996*0Sstevel@tonic-gate
6997*0Sstevel@tonic-gateCGI.pm also has some simple built-in protections against denial of
6998*0Sstevel@tonic-gateservice attacks, but you must activate them before you can use them.
6999*0Sstevel@tonic-gateThese take the form of two global variables in the CGI name space:
7000*0Sstevel@tonic-gate
7001*0Sstevel@tonic-gate=over 4
7002*0Sstevel@tonic-gate
7003*0Sstevel@tonic-gate=item B<$CGI::POST_MAX>
7004*0Sstevel@tonic-gate
7005*0Sstevel@tonic-gateIf set to a non-negative integer, this variable puts a ceiling
7006*0Sstevel@tonic-gateon the size of POSTings, in bytes.  If CGI.pm detects a POST
7007*0Sstevel@tonic-gatethat is greater than the ceiling, it will immediately exit with an error
7008*0Sstevel@tonic-gatemessage.  This value will affect both ordinary POSTs and
7009*0Sstevel@tonic-gatemultipart POSTs, meaning that it limits the maximum size of file
7010*0Sstevel@tonic-gateuploads as well.  You should set this to a reasonably high
7011*0Sstevel@tonic-gatevalue, such as 1 megabyte.
7012*0Sstevel@tonic-gate
7013*0Sstevel@tonic-gate=item B<$CGI::DISABLE_UPLOADS>
7014*0Sstevel@tonic-gate
7015*0Sstevel@tonic-gateIf set to a non-zero value, this will disable file uploads
7016*0Sstevel@tonic-gatecompletely.  Other fill-out form values will work as usual.
7017*0Sstevel@tonic-gate
7018*0Sstevel@tonic-gate=back
7019*0Sstevel@tonic-gate
7020*0Sstevel@tonic-gateYou can use these variables in either of two ways.
7021*0Sstevel@tonic-gate
7022*0Sstevel@tonic-gate=over 4
7023*0Sstevel@tonic-gate
7024*0Sstevel@tonic-gate=item B<1. On a script-by-script basis>
7025*0Sstevel@tonic-gate
7026*0Sstevel@tonic-gateSet the variable at the top of the script, right after the "use" statement:
7027*0Sstevel@tonic-gate
7028*0Sstevel@tonic-gate    use CGI qw/:standard/;
7029*0Sstevel@tonic-gate    use CGI::Carp 'fatalsToBrowser';
7030*0Sstevel@tonic-gate    $CGI::POST_MAX=1024 * 100;  # max 100K posts
7031*0Sstevel@tonic-gate    $CGI::DISABLE_UPLOADS = 1;  # no uploads
7032*0Sstevel@tonic-gate
7033*0Sstevel@tonic-gate=item B<2. Globally for all scripts>
7034*0Sstevel@tonic-gate
7035*0Sstevel@tonic-gateOpen up CGI.pm, find the definitions for $POST_MAX and
7036*0Sstevel@tonic-gate$DISABLE_UPLOADS, and set them to the desired values.  You'll
7037*0Sstevel@tonic-gatefind them towards the top of the file in a subroutine named
7038*0Sstevel@tonic-gateinitialize_globals().
7039*0Sstevel@tonic-gate
7040*0Sstevel@tonic-gate=back
7041*0Sstevel@tonic-gate
7042*0Sstevel@tonic-gateAn attempt to send a POST larger than $POST_MAX bytes will cause
7043*0Sstevel@tonic-gateI<param()> to return an empty CGI parameter list.  You can test for
7044*0Sstevel@tonic-gatethis event by checking I<cgi_error()>, either after you create the CGI
7045*0Sstevel@tonic-gateobject or, if you are using the function-oriented interface, call
7046*0Sstevel@tonic-gate<param()> for the first time.  If the POST was intercepted, then
7047*0Sstevel@tonic-gatecgi_error() will return the message "413 POST too large".
7048*0Sstevel@tonic-gate
7049*0Sstevel@tonic-gateThis error message is actually defined by the HTTP protocol, and is
7050*0Sstevel@tonic-gatedesigned to be returned to the browser as the CGI script's status
7051*0Sstevel@tonic-gate code.  For example:
7052*0Sstevel@tonic-gate
7053*0Sstevel@tonic-gate   $uploaded_file = param('upload');
7054*0Sstevel@tonic-gate   if (!$uploaded_file && cgi_error()) {
7055*0Sstevel@tonic-gate      print header(-status=>cgi_error());
7056*0Sstevel@tonic-gate      exit 0;
7057*0Sstevel@tonic-gate   }
7058*0Sstevel@tonic-gate
7059*0Sstevel@tonic-gateHowever it isn't clear that any browser currently knows what to do
7060*0Sstevel@tonic-gatewith this status code.  It might be better just to create an
7061*0Sstevel@tonic-gateHTML page that warns the user of the problem.
7062*0Sstevel@tonic-gate
7063*0Sstevel@tonic-gate=head1 COMPATIBILITY WITH CGI-LIB.PL
7064*0Sstevel@tonic-gate
7065*0Sstevel@tonic-gateTo make it easier to port existing programs that use cgi-lib.pl the
7066*0Sstevel@tonic-gatecompatibility routine "ReadParse" is provided.  Porting is simple:
7067*0Sstevel@tonic-gate
7068*0Sstevel@tonic-gateOLD VERSION
7069*0Sstevel@tonic-gate    require "cgi-lib.pl";
7070*0Sstevel@tonic-gate    &ReadParse;
7071*0Sstevel@tonic-gate    print "The value of the antique is $in{antique}.\n";
7072*0Sstevel@tonic-gate
7073*0Sstevel@tonic-gateNEW VERSION
7074*0Sstevel@tonic-gate    use CGI;
7075*0Sstevel@tonic-gate    CGI::ReadParse
7076*0Sstevel@tonic-gate    print "The value of the antique is $in{antique}.\n";
7077*0Sstevel@tonic-gate
7078*0Sstevel@tonic-gateCGI.pm's ReadParse() routine creates a tied variable named %in,
7079*0Sstevel@tonic-gatewhich can be accessed to obtain the query variables.  Like
7080*0Sstevel@tonic-gateReadParse, you can also provide your own variable.  Infrequently
7081*0Sstevel@tonic-gateused features of ReadParse, such as the creation of @in and $in
7082*0Sstevel@tonic-gatevariables, are not supported.
7083*0Sstevel@tonic-gate
7084*0Sstevel@tonic-gateOnce you use ReadParse, you can retrieve the query object itself
7085*0Sstevel@tonic-gatethis way:
7086*0Sstevel@tonic-gate
7087*0Sstevel@tonic-gate    $q = $in{CGI};
7088*0Sstevel@tonic-gate    print $q->textfield(-name=>'wow',
7089*0Sstevel@tonic-gate			-value=>'does this really work?');
7090*0Sstevel@tonic-gate
7091*0Sstevel@tonic-gateThis allows you to start using the more interesting features
7092*0Sstevel@tonic-gateof CGI.pm without rewriting your old scripts from scratch.
7093*0Sstevel@tonic-gate
7094*0Sstevel@tonic-gate=head1 AUTHOR INFORMATION
7095*0Sstevel@tonic-gate
7096*0Sstevel@tonic-gateCopyright 1995-1998, Lincoln D. Stein.  All rights reserved.
7097*0Sstevel@tonic-gate
7098*0Sstevel@tonic-gateThis library is free software; you can redistribute it and/or modify
7099*0Sstevel@tonic-gateit under the same terms as Perl itself.
7100*0Sstevel@tonic-gate
7101*0Sstevel@tonic-gateAddress bug reports and comments to: lstein@cshl.org.  When sending
7102*0Sstevel@tonic-gatebug reports, please provide the version of CGI.pm, the version of
7103*0Sstevel@tonic-gatePerl, the name and version of your Web server, and the name and
7104*0Sstevel@tonic-gateversion of the operating system you are using.  If the problem is even
7105*0Sstevel@tonic-gateremotely browser dependent, please provide information about the
7106*0Sstevel@tonic-gateaffected browers as well.
7107*0Sstevel@tonic-gate
7108*0Sstevel@tonic-gate=head1 CREDITS
7109*0Sstevel@tonic-gate
7110*0Sstevel@tonic-gateThanks very much to:
7111*0Sstevel@tonic-gate
7112*0Sstevel@tonic-gate=over 4
7113*0Sstevel@tonic-gate
7114*0Sstevel@tonic-gate=item Matt Heffron (heffron@falstaff.css.beckman.com)
7115*0Sstevel@tonic-gate
7116*0Sstevel@tonic-gate=item James Taylor (james.taylor@srs.gov)
7117*0Sstevel@tonic-gate
7118*0Sstevel@tonic-gate=item Scott Anguish <sanguish@digifix.com>
7119*0Sstevel@tonic-gate
7120*0Sstevel@tonic-gate=item Mike Jewell (mlj3u@virginia.edu)
7121*0Sstevel@tonic-gate
7122*0Sstevel@tonic-gate=item Timothy Shimmin (tes@kbs.citri.edu.au)
7123*0Sstevel@tonic-gate
7124*0Sstevel@tonic-gate=item Joergen Haegg (jh@axis.se)
7125*0Sstevel@tonic-gate
7126*0Sstevel@tonic-gate=item Laurent Delfosse (delfosse@delfosse.com)
7127*0Sstevel@tonic-gate
7128*0Sstevel@tonic-gate=item Richard Resnick (applepi1@aol.com)
7129*0Sstevel@tonic-gate
7130*0Sstevel@tonic-gate=item Craig Bishop (csb@barwonwater.vic.gov.au)
7131*0Sstevel@tonic-gate
7132*0Sstevel@tonic-gate=item Tony Curtis (tc@vcpc.univie.ac.at)
7133*0Sstevel@tonic-gate
7134*0Sstevel@tonic-gate=item Tim Bunce (Tim.Bunce@ig.co.uk)
7135*0Sstevel@tonic-gate
7136*0Sstevel@tonic-gate=item Tom Christiansen (tchrist@convex.com)
7137*0Sstevel@tonic-gate
7138*0Sstevel@tonic-gate=item Andreas Koenig (k@franz.ww.TU-Berlin.DE)
7139*0Sstevel@tonic-gate
7140*0Sstevel@tonic-gate=item Tim MacKenzie (Tim.MacKenzie@fulcrum.com.au)
7141*0Sstevel@tonic-gate
7142*0Sstevel@tonic-gate=item Kevin B. Hendricks (kbhend@dogwood.tyler.wm.edu)
7143*0Sstevel@tonic-gate
7144*0Sstevel@tonic-gate=item Stephen Dahmen (joyfire@inxpress.net)
7145*0Sstevel@tonic-gate
7146*0Sstevel@tonic-gate=item Ed Jordan (ed@fidalgo.net)
7147*0Sstevel@tonic-gate
7148*0Sstevel@tonic-gate=item David Alan Pisoni (david@cnation.com)
7149*0Sstevel@tonic-gate
7150*0Sstevel@tonic-gate=item Doug MacEachern (dougm@opengroup.org)
7151*0Sstevel@tonic-gate
7152*0Sstevel@tonic-gate=item Robin Houston (robin@oneworld.org)
7153*0Sstevel@tonic-gate
7154*0Sstevel@tonic-gate=item ...and many many more...
7155*0Sstevel@tonic-gate
7156*0Sstevel@tonic-gatefor suggestions and bug fixes.
7157*0Sstevel@tonic-gate
7158*0Sstevel@tonic-gate=back
7159*0Sstevel@tonic-gate
7160*0Sstevel@tonic-gate=head1 A COMPLETE EXAMPLE OF A SIMPLE FORM-BASED SCRIPT
7161*0Sstevel@tonic-gate
7162*0Sstevel@tonic-gate
7163*0Sstevel@tonic-gate	#!/usr/local/bin/perl
7164*0Sstevel@tonic-gate
7165*0Sstevel@tonic-gate	use CGI;
7166*0Sstevel@tonic-gate
7167*0Sstevel@tonic-gate	$query = new CGI;
7168*0Sstevel@tonic-gate
7169*0Sstevel@tonic-gate	print $query->header;
7170*0Sstevel@tonic-gate	print $query->start_html("Example CGI.pm Form");
7171*0Sstevel@tonic-gate	print "<h1> Example CGI.pm Form</h1>\n";
7172*0Sstevel@tonic-gate	&print_prompt($query);
7173*0Sstevel@tonic-gate	&do_work($query);
7174*0Sstevel@tonic-gate	&print_tail;
7175*0Sstevel@tonic-gate	print $query->end_html;
7176*0Sstevel@tonic-gate
7177*0Sstevel@tonic-gate	sub print_prompt {
7178*0Sstevel@tonic-gate	   my($query) = @_;
7179*0Sstevel@tonic-gate
7180*0Sstevel@tonic-gate	   print $query->start_form;
7181*0Sstevel@tonic-gate	   print "<em>What's your name?</em><br>";
7182*0Sstevel@tonic-gate	   print $query->textfield('name');
7183*0Sstevel@tonic-gate	   print $query->checkbox('Not my real name');
7184*0Sstevel@tonic-gate
7185*0Sstevel@tonic-gate	   print "<p><em>Where can you find English Sparrows?</em><br>";
7186*0Sstevel@tonic-gate	   print $query->checkbox_group(
7187*0Sstevel@tonic-gate				 -name=>'Sparrow locations',
7188*0Sstevel@tonic-gate				 -values=>[England,France,Spain,Asia,Hoboken],
7189*0Sstevel@tonic-gate				 -linebreak=>'yes',
7190*0Sstevel@tonic-gate				 -defaults=>[England,Asia]);
7191*0Sstevel@tonic-gate
7192*0Sstevel@tonic-gate	   print "<p><em>How far can they fly?</em><br>",
7193*0Sstevel@tonic-gate		$query->radio_group(
7194*0Sstevel@tonic-gate			-name=>'how far',
7195*0Sstevel@tonic-gate			-values=>['10 ft','1 mile','10 miles','real far'],
7196*0Sstevel@tonic-gate			-default=>'1 mile');
7197*0Sstevel@tonic-gate
7198*0Sstevel@tonic-gate	   print "<p><em>What's your favorite color?</em>  ";
7199*0Sstevel@tonic-gate	   print $query->popup_menu(-name=>'Color',
7200*0Sstevel@tonic-gate				    -values=>['black','brown','red','yellow'],
7201*0Sstevel@tonic-gate				    -default=>'red');
7202*0Sstevel@tonic-gate
7203*0Sstevel@tonic-gate	   print $query->hidden('Reference','Monty Python and the Holy Grail');
7204*0Sstevel@tonic-gate
7205*0Sstevel@tonic-gate	   print "<p><em>What have you got there?</em><br>";
7206*0Sstevel@tonic-gate	   print $query->scrolling_list(
7207*0Sstevel@tonic-gate			 -name=>'possessions',
7208*0Sstevel@tonic-gate			 -values=>['A Coconut','A Grail','An Icon',
7209*0Sstevel@tonic-gate				   'A Sword','A Ticket'],
7210*0Sstevel@tonic-gate			 -size=>5,
7211*0Sstevel@tonic-gate			 -multiple=>'true');
7212*0Sstevel@tonic-gate
7213*0Sstevel@tonic-gate	   print "<p><em>Any parting comments?</em><br>";
7214*0Sstevel@tonic-gate	   print $query->textarea(-name=>'Comments',
7215*0Sstevel@tonic-gate				  -rows=>10,
7216*0Sstevel@tonic-gate				  -columns=>50);
7217*0Sstevel@tonic-gate
7218*0Sstevel@tonic-gate	   print "<p>",$query->reset;
7219*0Sstevel@tonic-gate	   print $query->submit('Action','Shout');
7220*0Sstevel@tonic-gate	   print $query->submit('Action','Scream');
7221*0Sstevel@tonic-gate	   print $query->endform;
7222*0Sstevel@tonic-gate	   print "<hr>\n";
7223*0Sstevel@tonic-gate	}
7224*0Sstevel@tonic-gate
7225*0Sstevel@tonic-gate	sub do_work {
7226*0Sstevel@tonic-gate	   my($query) = @_;
7227*0Sstevel@tonic-gate	   my(@values,$key);
7228*0Sstevel@tonic-gate
7229*0Sstevel@tonic-gate	   print "<h2>Here are the current settings in this form</h2>";
7230*0Sstevel@tonic-gate
7231*0Sstevel@tonic-gate	   foreach $key ($query->param) {
7232*0Sstevel@tonic-gate	      print "<strong>$key</strong> -> ";
7233*0Sstevel@tonic-gate	      @values = $query->param($key);
7234*0Sstevel@tonic-gate	      print join(", ",@values),"<br>\n";
7235*0Sstevel@tonic-gate	  }
7236*0Sstevel@tonic-gate	}
7237*0Sstevel@tonic-gate
7238*0Sstevel@tonic-gate	sub print_tail {
7239*0Sstevel@tonic-gate	   print <<END;
7240*0Sstevel@tonic-gate	<hr>
7241*0Sstevel@tonic-gate	<address>Lincoln D. Stein</address><br>
7242*0Sstevel@tonic-gate	<a href="/">Home Page</a>
7243*0Sstevel@tonic-gate	END
7244*0Sstevel@tonic-gate	}
7245*0Sstevel@tonic-gate
7246*0Sstevel@tonic-gate=head1 BUGS
7247*0Sstevel@tonic-gate
7248*0Sstevel@tonic-gatePlease report them.
7249*0Sstevel@tonic-gate
7250*0Sstevel@tonic-gate=head1 SEE ALSO
7251*0Sstevel@tonic-gate
7252*0Sstevel@tonic-gateL<CGI::Carp>, L<CGI::Fast>, L<CGI::Pretty>
7253*0Sstevel@tonic-gate
7254*0Sstevel@tonic-gate=cut
7255*0Sstevel@tonic-gate
7256