#!/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 = <FILE>;
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 '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ';
print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">' . "\n";
print '<head>' . "\n";
print '<link rel="StyleSheet" href="css/assign1.css" type="text/css" ';
print 'media="screen" title="mystyle" />' . "\n";
print '<title>Restaurant Bill Calculator</title>' . "\n";
print '</head>' . "\n";
print '<body>' . "\n";
print '<form action="assign1.cgi" method="get" name="patrons">' . "\n";
if (defined $errmsg) {
print '<div class="error">' . $errmsg . '</div>' . "\n";
print '<br />' . "\n";
}
print '<table>' . "\n";
print '<tr>' . "\n";
print '<td class="label">Number of Patrons: </td>';
print '<td class="value">' . "\n";
print '<input type="text" name="patrons" size="6" maxlength="10" />' . "\n";
print '</td>' . "\n";
print '</tr><tr>' . "\n";
print '<td align="center" colspan="2">' . "\n";
print '<input type="submit" name="go" value="submit" />' . "\n";
print '</td>' . "\n";
print '</tr>' . "\n";
print '</table>' . "\n";
print '<input type="hidden" name="file" value="patron" />' . "\n";
print '</form>' . "\n";
print '</body>' . "\n";
print '</html>' . "\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 '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ';
print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">' . "\n";
print '<head>' . "\n";
print '<link rel="StyleSheet" href="css/assign1.css" type="text/css" ';
print 'media="screen" title="mystyle" />' . "\n";
print '<title>Restaurant Bill Calculator - Appetizers</title>' . "\n";
print '</head>' . "\n";
print '<body>' . "\n";
print '<form action="assign1.cgi" method="get" name="appetizer">' . "\n";
if (defined $errmsg) {
print '<div class="error">' . $errmsg . '</div>' . "\n";
}
print '<table style="form">' . "\n";
print '<tr>' . "\n";
print '<td class="label">Appetizers: </td>' . "\n";
print '<td class="value">' . "\n";
print '<select name="appetizer">' . "\n";
print '<option value="garlic bread">Garlic Bread ($3.95)</option>' . "\n";
print '<option value="brushetta">Brushetta ($4.95)</option>' . "\n";
print '<option value="hummus">Humous & Tabouleh ($5.95)</option>' . "\n";
print '</select>' . "\n";
print '</tr><tr>' . "\n";
print '<td class="label">Quantity: </td>' . "\n";
print '<td class="value">';
print '<input type="text" name="qty" size="6" maxlength="2" />' . "\n";
print '</td>' . "\n";
print '</tr><tr>' . "\n";
print '<td class="label">Add more? </td>' . "\n";
print '<td class="value"><input type="checkbox" name="more" /></td>' ."\n";
print '</tr><tr>' . "\n";
print '<td align="center" colspan="2">';
print '<input type="submit" name="go" value="Submit" />';
print '</td>' . "\n";
print '</table>' . "\n";
print '<input type="hidden" name="file" value="appetizer">' . "\n";
print '<input type="hidden" name="session_id" value="' . $session_id
. '">' . "\n";
print '</form>' . "\n";
print '</body>' . "\n";
print '</html>' . "\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 '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ';
print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">' . "\n";
print '<head>' . "\n";
print '<link rel="StyleSheet" href="css/assign1.css" type="text/css" ';
print 'media="screen" title="mystyle" />' . "\n";
print '<title>Restaurant Bill Calculator - Entrees</title>' . "\n";
print '</head>' . "\n";
print '<body>' . "\n";
print '<form action="assign1.cgi" method="get" name="entrees">' . "\n";
print '<table style="form">' . "\n";
print '<tr>' . "\n";
print '<td class="label">Entrees: </td>' . "\n";
print '<td class="value">' . "\n";
print '<select name="entree">' . "\n";
print '<option value="spaghetti">Spaghetti ($8.95)</option>' . "\n";
print '<option value="lasagna">Lasanga ($9.95)</option>' . "\n";
print '<option value="pizza">Pizza ($10.95)</option>' . "\n";
print '</select>' . "\n";
print '</tr><tr>' . "\n";
print '<td class="label">Add a Salad? </td>' . "\n";
print '<td class="value"><input type="checkbox" name="salad" /></td>'."\n";
print '</tr><tr>' . "\n";
print '<td class="label">Quantity: </td>' . "\n";
print '<td class="value">';
print '<input type="text" name="qty" size="6" maxlength="2" />' . "\n";
print '</td>' . "\n";
print '</tr><tr>' . "\n";
print '<td class="label">Add more? </td>' . "\n";
print '<td class="value"><input type="checkbox" name="more" /></td>' ."\n";
print '</tr><tr>' . "\n";
print '<td align="center" colspan="2">';
print '<input type="submit" name="go" value="Submit" />';
print '</td>' . "\n";
print '</table>' . "\n";
print '<input type="hidden" name="file" value="entree">' . "\n";
print '<input type="hidden" name="session_id" value="' . $session_id
. '">' . "\n";
print '</form>' . "\n";
print '</body>' . "\n";
print '</html>' . "\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 '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ';
print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . "\n";
print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">' . "\n";
print '<head>' . "\n";
print '<link rel="StyleSheet" href="css/assign1.css" type="text/css" ';
print 'media="screen" title="mystyle" />' . "\n";
print '<title>Restaurant Bill Calculator - Drinks</title>' . "\n";
print '</head>' . "\n";
print '<body>' . "\n";
print '<form action="assign1.cgi" method="get" name="drinks">' . "\n";
if (defined $errmsg) {
print '<div class="error">' . $errmsg . '</div>' . "\n";
}
print '<table style="form">' . "\n";
print '<tr>' . "\n";
print '<td class="label">Drinks: </td>' . "\n";
print '<td class="value">' . "\n";
print '<select name="drink">' . "\n";
print '<option value="soft drink">Soft Drink ($2)</option>' . "\n";
print '<option value="Beer">Beer ($3)</option>' . "\n";
print '<option value="Liquor">Liquor ($3.50)</option>' . "\n";
print '<option value="Wine">Wine ($4)</option>' . "\n";
print '</select>' . "\n";
print '</tr><tr>' . "\n";
print '<td class="label">Quantity: </td>' . "\n";
print '<td class="value">';
print '<input type="text" name="qty" size="6" maxlength="2" />' . "\n";
print '</td>' . "\n";
print '</tr><tr>' . "\n";
print '<td class="label">Add more? </td>' . "\n";
print '<td class="value"><input type="checkbox" name="more" /></td>' ."\n";
print '</tr><tr>' . "\n";
print '<td align="center" colspan="2">';
print '<input type="submit" name="go" value="Submit" />';
print '</td>' . "\n";
print '</table>' . "\n";
print '<input type="hidden" name="file" value="drink">' . "\n";
print '<input type="hidden" name="session_id" value="' . $session_id
. '">' . "\n";
print '</form>' . "\n";
print '</body>' . "\n";
print '</html>' . "\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();