#!/usr/bin/perl use warnings; use strict; # the first argument of this function is a filename # the second argument is a reference to a hash of variables # all variables in that hash will be written out to a file # the format of the file is as follows # SCALARS: s:name:value # ARRAYS : a:name:value1:value2:value3 # HASHES : h:name:key1:value1:key2:value2 # newlines are the seperators! there is no terminating character sub write_hash { my $filename = shift @_; my $vars = shift @_; open(FILE, ">$filename"); foreach my $key (keys %{$vars}) { # this one is just for convienence my $i = \( $vars->{$key} ); # this is a switch statement # make a reference to $vars->{$key} and pass it to ref for (ref $i) { # if it is scalar, ref will return SCALAR... if (/SCALAR/) { print FILE "s:$key:" . $vars->{$key} . "\n"; } # ...otherwise it returns an empty string # which means it is a hash or an array else { my $j = $vars->{$key}; my $type = ref $j; # if it is an array, print out each element if ($type eq "ARRAY") { print FILE "a:$key"; for my $element ( @{$j} ) { print FILE ":$element"; } print FILE "\n"; } # likewise for a hash, print out the key/value pairs elsif ($type eq "HASH") { print FILE "h:$key"; for my $k ( keys %{$j} ) { print FILE ":$k:" . $j->{$k}; } print FILE "\n"; } } } } close(FILE); return; } # the first argument of this function is a filename # function returns a hash # see the above function for the format of the file sub read_hash { my $filename = shift @_; my %vars; # these are used when extracting data from the fields my ($type, $name, $value, $key); print STDERR "$filename\n"; open(FILE, "$filename"); my @data = ; close(FILE); # iterate through the array foreach my $line (@data) { # retrieve the type $type = substr($line, 0, 1); for ($type) { # if it's a scalar... if (/s/) { (undef,$name,$value) = split(/:/, $line, 3); chomp $value; $vars{$name} = $value; } # if it's an array... if (/a/) { # stores the elements of the array, temporarily my ($values, @elements); (undef,$name,$values) = split(/:/, $line, 3); chomp $values; @elements = split(/:/, $values); # now we've got the values split up # time to write things to the hash $vars{$name} = (\@elements); } # if it's a hash... if (/h/) { # $k and $v are for key and value my ($k, $v, $pairs, %hash); (undef,$name,$pairs) = split(/:/, $line, 3); chomp $pairs; # extract all the pairs and put them in the hash while (defined $pairs) { ($k,$v,$pairs) = split(/:/, $pairs, 3); $hash{$k} = $v; } # now shove a hash ref into our big hash! $vars{$name} = \%hash; } } } return %vars; } sub write_start { # get the error message, if there is one # undefined if there is no errmsg my $errmsg = shift(@_); print "Content-Type: text/html"; print "\n\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print 'Restaurant Bill Calculator' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; if (defined $errmsg) { print '
' . $errmsg . '
' . "\n"; print '
' . "\n"; } print '' . "\n"; print '' . "\n"; print ''; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '
Number of Patrons: ' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '' . "\n"; return; } sub write_appetizer { # get the session id... my $session_id = shift @_; # this will have an error message if one was passed, and will be # undefined otherwise my $errmsg = shift @_; # ...and write the page print "Content-Type: text/html"; print "\n\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print 'Restaurant Bill Calculator - Appetizers' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; if (defined $errmsg) { print '
' . $errmsg . '
' . "\n"; } print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' ."\n"; print '' . "\n"; print '' . "\n"; print '
Appetizers: ' . "\n"; print '' . "\n"; print '
Quantity: '; print '' . "\n"; print '
Add more?
'; print ''; print '
' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '' . "\n"; return; } sub write_entree { # retrieve the session id... my $session_id = shift @_; # ...and write the page print "Content-Type: text/html"; print "\n\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print 'Restaurant Bill Calculator - Entrees' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print ''."\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' ."\n"; print '' . "\n"; print '' . "\n"; print '
Entrees: ' . "\n"; print '' . "\n"; print '
Add a Salad?
Quantity: '; print '' . "\n"; print '
Add more?
'; print ''; print '
' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '' . "\n"; return; } sub write_drinks { # get the session id... my $session_id = shift @_; # this will have an error message if one was passed, and will be # undefined otherwise my $errmsg = shift @_; # ...and write the page print "Content-Type: text/html"; print "\n\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print 'Restaurant Bill Calculator - Drinks' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; if (defined $errmsg) { print '
' . $errmsg . '
' . "\n"; } print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' . "\n"; print '' ."\n"; print '' . "\n"; print '' . "\n"; print '
Drinks: ' . "\n"; print '' . "\n"; print '
Quantity: '; print '' . "\n"; print '
Add more?
'; print ''; print '
' . "\n"; print '' . "\n"; print '' . "\n"; print '
' . "\n"; print '' . "\n"; print '' . "\n"; return; } # returns the number of patrons, and the errorcode sub process_patron { # put the query string into something we can work with my $qs = $_[0]; my $err = 0; if (! $qs->{'patrons'} || length $qs->{'patrons'} > 2) { $err = 1; } return $qs->{'patrons'}, $err; } sub process_appetizer { # again with the query string my $qs = shift @_; # more contains 'on' if it was checked my $more = ($qs->{'more'}) ? 1 : 0; # fill %ret with the return values my %ret = ( appetizer => $qs->{'appetizer'}, qty => $qs->{'qty'}, more => $more, ); return %ret; } sub process_entree { # get the QS my $qs = shift @_; # contains 'on' if it was checked my $more = ($qs->{'more'}) ? 1 : 0; my $salad = ($qs->{'salad'}) ? 1 : 0; # fill ret with the appropriate values my %ret = ( entree => $qs->{'entree'}, qty => $qs->{'qty'}, more => $more, salad => $salad ); return %ret; } sub process_drinks { # get the query string my $qs = shift @_; # more contains 'on' if it was checked my $more = ($qs->{'more'}) ? 1 : 0; # fill %ret with the return values my %ret = ( drink => $qs->{'drink'}, qty => $qs->{'qty'}, more => $more ); return %ret; } sub main { my %qs= split(/[;&=]/,$ENV{QUERY_STRING}); foreach (values(%qs)) { s/(%[0-9a-f]{2}|\+)/$1 eq '+'?' ': chr(hex(substr($1,1)))/gei; } # initialize a few variables my $page = $qs{'file'}; my $err = 0; my $filename = ""; my $errmsg = ""; # if its the patron page, generate a new session id # otherwise, get the session id my $session_id; my %vars; if (! defined $qs{'session_id'} ) { $session_id = int(rand(100)) . time(); } else { $session_id = $qs{'session_id'}; $filename = ".meal-" . $session_id; print STDERR "Retrieving old data...\n"; %vars = read_hash($filename); } # this is the big important variable. it holds all the information # from the forms. # this is a switch statement for ($page) { if (/patron/) { ($vars{'patrons'}, $err) = process_patron(\%qs); if (! $err) { write_appetizer($session_id); } else { $errmsg = "Number of patrons must be between 1 and 99"; # needs error message write_start($errmsg); } } elsif (/appetizer/) { # validate the appetizer page my %ret = process_appetizer(\%qs); my $amt = 0; # if this isn't the first time through the appetizers page # get the total number of appetizers ordered already... if (defined $vars{'appetizers'}) { foreach my $key (keys %{ $vars{'appetizers'} }) { $amt += $vars{'appetizers'}->{$key}; } } # ...and add the number of appetizers ordered on this iteration $amt += $ret{'qty'}; # if there are more appetizers than people, give an error... if ($amt > $vars{'patrons'}) { $errmsg = "Total quantity of appetizers must be between" . " 0 and " . $vars{'patrons'}; write_appetizer($session_id, $errmsg); } # ...otherwise, save the data and display the appropriate page else { # these are just for syntactical simplicity my $key = $ret{'appetizer'}; my $qty = $ret{'qty'}; # if the appetizers reference isn't there... if (! defined $vars{'appetizers'}) { # ...create it... $vars{'appetizers'} = {}; # ...and initialize it $vars{'appetizers'}->{'garlic bread'} = 0; $vars{'appetizers'}->{'brushetta'} = 0; $vars{'appetizers'}->{'hummus'} = 0; } # save the appetizer data $vars{'appetizers'}->{$key} += $qty; # if they want to add more appetizers... if ($ret{'more'} == 1) { # ...write out the appetizer page write_appetizer($session_id); } # otherwise... else { # write out the entree page write_entree($session_id); } } } elsif (/entree/) { # validate the entree data my %ret = process_entree(\%qs); my $amt = 0; # if this isn't the first time through the entree page # total up the amount of entrees ordered so far... if (defined $vars{'entrees'}) { foreach my $key (keys %{ $vars{'entrees'} }) { $amt += $vars{'entrees'}->{$key}; } } # ...and add the amount ordered in this iteration $amt += $ret{'qty'}; # if the amount of entrees is not the same as number of patrons # and they are not going to add more... if ($amt != $vars{'patrons'} && $ret{'more'} == 0) { # give 'em a nice error message and send 'em back. $errmsg = "Total number of entrees must be" . $vars{'patrons'}; write_entree($session_id, $errmsg); } else { # for simplicity my $key = $ret{'entree'}; my $qty = $ret{'qty'}; # if the entree hash in not defined, if (! defined $vars{'entrees'}) { # declare it... $vars{'entrees'} = {}; # and initialize it $vars{'entrees'}->{'salads'} = 0; $vars{'entrees'}->{'spaghetti'} = 0; $vars{'entrees'}->{'lasagna'} = 0; $vars{'entrees'}->{'pizza'} = 0; } # save the data $vars{'entrees'}->{$key} += $qty; $vars{'entrees'}->{'salads'} += $qty * $ret{'salad'}; # if they want to add more, write out the entree page if ($ret{'more'} == 1) { write_entree($session_id); } # otherwise, write out the drinks page else { write_drinks($session_id); } } } elsif (/drink/) { } elsif (/subtotal/) { } elsif (/total/) { # WE NEED TO GET RID OF THE FILE HERE } } # write the vars out to the file, whee. $filename = ".meal-" . $session_id; write_hash($filename, \%vars); } main();