CSE 490c/303 Homework 7 Milestone 2

Target Date: Friday, 12/5
Turnin: Nothing
This is a piece of Homework 7. If you haven't come here by first reading that, this page won't make much sense.

Milestone 2 - Target Date: 12/5

You'll be reading some and writing a bit of Perl code for this milestone. In particular, you will be working on the step 6 of the process shown on the application structure diagram.

The basic idea here is that cseBay will have many web pages. Some of what goes on the web page is data obtained from the DB, but much of it is likely to be just static text (and possibly images, etc.). We have to use (perl) code to talk with the DB, and so to compose the data dependent parts of the pages, but we'd rather not hardcode what a page looks like into a program. Instead, we'd like decisions about how to lay out the data to be represented in data files.

We do that by creating files that are basically .html, except that:

To distinguish these files from .html files, we give them the file extent .template. We won't be reading anything from the DB for this milestone, but we will be implementing the basic scheme of substituting some value for placeholder (%NAME%) tokens.

Here is an example .template file. You can see how it might be used (eventually, when all milestones are completed) here.

Name/Value Maps

(This description is generic only. How this is actually implemented in perl is described next.)

A map is composed of two parts, a 1-d array of strings, NAMES[K], and a 2-d array of values, VALUES[N][K]. If %NAMES[k]% is seen in a .template file, it should be replaced by VALUES[n][k], for an n described next.

In the usual case, we replace %NAMES[k]% with VALUES[0][k]. However, sometimes we want a single line of the .template file to expand into a list. In our example .template file, we do this because we want to create a table with a number of rows that depends on how many cseBay users there are in the DB (which we don't know when we're writing the .template file). We indicate that we want a list by beginning the template file line with '{' and ending it with '}'. Lines flagged in that way should have %NAME% replacement applied to them N times (where N is the number of rows in the VALUES array). We use row 0<n<N of the VALUES array to produce the nth output line. Each of the N substitutions occurs based on the original line from the .template file -- that is, the substitutions are not cumulative.

Map Implementation in perl

A (cseBay) map is implemented in perl like this:

The "(....)"s are perl arrays. The arrows are perl references. This map says that substitutions should occur for tokens %ONE%, %TWO%, etc., and that if the input line is not enclosed in braces the substitutions should be "First %ONE% val", etc.

Setup

I've dumped the starter files into your cvs repository. To get them, cd into your working directory and cvs update -d. That should introduce the following files into your working directory:
Makefile       index.html          templateDebug.pm
htmlTemplates  processTemplate.pm  templateTest.cgi
htmlTemplates is a directory containing:
Makefile  listUsers.template  templateTest.template  userBids.template
(as well as the CVS directory CVS creates itself).

Running the Test Program

The starter files you just fetched include a single test case, templateTest.cgi.
Running Locally (as a Program)
You can run it locally, on whatever machine your working directory is on (so long as you have a version of perl installed on that machine):
perl templateTest.cgi
A bunch of output should appear: because it's a .cgi, an HTTP header followed by a lot of HTML.

Alternatively, you can run the program under the debugger:

perl -d templateTest.cgi
That will let you step through your code. (You can also type arbitrary perl statements in at any time, e.g., print $myVar;.)

The upside of this approach is that it is convenient: you don't have to be connected to debug, for instance. The downside is that the output, being HTML is tough to read. You can address that by redirecting the output from your execution to a file, and then drag-and-drop'ing the output file onto Mozilla.

Running as a .cgi (on abstract)
If you copy all the files to your abstract:www/cse490c directory, you can run your code as a .cgi using Mozilla:
http://abstract.cs.washington.edu/~<yourlogin>/templateTest.cgi
This is a satisfying experience, but it's a lot harder to debug a .cgi than a program (because you have put the web server, the browser, and HTTP between you and your bugs).

The Makefile will automate copying everything to your abstract account if you want to try this, though. You must first create directory www/cse490c/htmlTemplates on abstract for it to work.

Note: On a least one windows machine I use, scp'ing my files to abstract ends up with the horrible end of line problem: I have '\r' characters in the files. This prevents the .cgi from being launched.

To deal with that, I wrote a routine, deWinify.c, that gets rid of them, and a shell script, deWin.sh that invokes deWinify, and a .cgi, deWin.cgi, that lets me run deWin.sh from a link on a web page.

If you find you need them, (a) copy them all to your www directory on abstract, and then (b) compile the .c to produce an executable named deWinify. You can execute ./deWin.sh while logged into abstract, or you can embed this link in a web page and invoke the thing remotely:

<a href="http://abstract.cs.washington.edu/~yourlogin/cse490c/deWin.cgi">deWinify me!</a>

What To Do

This page shows what your code will produce, once it's working. (It also is intended to be useful in understanding what maps are, what templates are, and how they're useful.)

Control flow starts in templateTest.cgi. It creates a test map, then calls some library routines to print out the various sections of its output. templateTest.cgi is a fully working program - you don't have to do anything to it.

In fact, the only code required is in two well-marked locations in processTemplate.pm. A .pm file is a perl library. If you look in templateTest.cgi, you'll see at the top

use processTemplate;
use templateDebug;
That imports the two libraries it uses. If you look at the top of processTemplate.pm you'll see a small set of syntax-challenged statements that enable and control exporting of the routines in that file for use in other perl programs. For this assignment, there's no need to worry about the details of all that, though. ("It just works.")

In processTemplate.pm are two spots marked with

# CODE MISSING HERE
The second one is in routine ProcessTemplate, which is called directly from templateTest.cgi. This routine takes a filename and a map and is supposed to return a string representing the contents of the file after applying the substitutions indicated by the map.

There is code in that routine already to read each line of the file, and to apply the "standard map" to it, a map that replaces the string %TIME% with a string representing the current time, for instance. (The standard map is implemented in that file, so you can easily find the details if you want.) What is missing is code to apply the map supplied as an argument to the call. You need to provide that.

The other missing piece of code is in routine ApplyMap. ApplyMap takes a string, a map, and an integer index. It does replacement on the string using the names in the map and the row of the values array given by the index. It returns the results of those replacements.