CGI Programming with LAML

Kurt Nørmark ©
Department of Computer Science, Aalborg University


In this chapter we give an example of a CGI program written in Scheme using the LAML cgi library.


1     Introduction
We are going to develop a simple number guessing game.
1.1     The game

1.1     The game
The game is very simple, and it is a common demonstration of a www server side program. The machine picks a secret number between 0 and 100 which you are supposed to guess. Upon each guess, the machine will tell you if your guess is too low, too high, or correct. The machine part is running on an Appache WEB server on a Unix machine.

The game is operational, and it can be played from here if you are connected to the Internet.

The pure Scheme program is available via the tutorial example page .
2     Overall design
Although this program is simple and small we have used a structure which, in some respects at least, can be used for larger and more realistic CGI programs.
2.1     The overall design

2.1     The overall design
We decide to split the program in a tiny CGI shell and the Scheme program as such. The CGI shell, which must be located in the .public_html/cgi-bin directory, is here:
string=? ; exec /pack/mzscheme/bin/mzscheme \-r \$0 "\$\@"

;; This program implements a number guessing game, 
;; which is commonly used to illustrate simple WWW
;; server programming.

(define example-tutorial-dir "/user/normark/scheme/examples/tutorial/")
(load (string-append example-tutorial-dir 
The name of the file must be number-guess.cgi , and it should be file protected to be executable (typically with chmod 755 ).

This starts MzScheme via a shell script, and the load line is executed. It would be perfectly possible to place the entire Scheme program here, but we prefer in general to organize our software in a directory outside the .public_html catalogue. Therefore we load the number guessing program from the tutorial example directory in my LAML development directory, which happens to be /normark/scheme .

As another important point, we decide to organize the number guessing system as a single program, which in the page-write part branches between a game init part ( ) and a game playing part ( ). We could as well have written two separate CGI programs, which probably would have been preferable in case the 'System' is larger. Such an alternative organization would typically call for common definitions organized in a shared scheme number guessing libary file.
3     The program
In this section we describe the number guessing program details.
3.1     The preamble part
3.2     The init game part
3.3     The game part

3.1     The preamble part
We will here comment on the preamble part of the number guessing program. It follows the typical pattern of most Scheme CGI programs we have written.

The first thing to do in the section laml-loading is to load laml.scm .In order to do so we must set laml-dir ( ). laml-dir is important, because it's value points at the root of the LAML system, which is used. Being at it is natural to use the shared LAML system in /pack/laml/ . Alternatively, the directory address of your own LAML system can be used.

Next comes the section initial-constants . The variable number-guess-url-prefix and not least the derived function number-guess-url are used to address the number guessing program from a browser. The function returns an URL with actual URL parameters - following the question mark. The function make-url-parameters is from the cgi LAML library, and it makes a list of actual URL parameters. We will meet the function number-guess-url later on.

Next comes the additional-loading part of the program. Here the cgi library is loaded by means of the lib-load procedure, and a number of other libraries are loaded too. The encode-decode library ( ) is used by cgi.scm for encoding and decoding URL parameters.

In other-settings we set the variable cgi-testing to #f and we register the current time in cur-time . The time is not used in this program, but it general this number is useful for a variety of purposes (such as making file names 'unique').

In the section url-parameters we extract the URL parameters passed to the program. The variable language-preference controls whether the Danish or English language is used in the game, with english as the default. The function text-choice uses the variable language-preference . The variable mode is important because it controls the part of the program to be started; Possible values are the symbols init or play , with init as the default. The function defaulted-get is a function from the LAML general library.

The CGI library function extract-url-parameters decodes the URL parameters. The variable url-pars is an association list (a list of cons pairs), such as
  ((language . "english") (mode . "init"))
This ends the game preamble part.

3.2     The init game part
The function game-init returns a HTML body to be used in one of the branches of the page-write section in the program. This is the place to draw the secret number ( ).

Also notice the form element, generated by form-1 at ( ). This determines the program which will receive form input when submitted. Thus, when we submit a new guess this detail determines the receiving CGI program. Here, we reuse the same program for this purpose (due the outer branching discussed above), but notice that we switch to play mode. We pass the language-preference as the language URL parameter.

After a welcome text we call guess-part ( ), which renders the form used for the user's guess.

Let us now look at guess-part , which returns part of the body. Most functions called by guess-part are so-called convenience functions, made on top of the HTML mirror libraries. The function text-line renders an input field, in which the guess can be entered ( ). The secret number is passed on using a hidden field ( ). In a better version of the program we should protect this field from being read directly in the document source. The submit button is also made in this function ( ).

3.3     The game part
The game part, represented by game-play , is the place where we get a hint about our guess, and we are allowed to make a new guess if we did not hit the number exactly. We first have to extract the submitted form input. This is done by the CGI library extract-form-input from the CGI library ( ), which returns an association list such as
((secret-number . "42") (players-guess . "22"))
We prepare a body with a new form element (as above) ( ). The conditional ( ) compares the secret number with the players guess, and an appropriate hint is presented. Notice how guess-part is activated if no exact hit is found ( ). In the lucky case where the player guesses the number an URL is given to restart the game ( ).