CGI Programming with LAML

Kurt Nørmark ©    normark@cs.auc.dk    Department of Computer Science, Aalborg University    

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

 

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

Introduction   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

 

 Introduction The program design-sect
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
 

Overall design   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:

#!/bin/sh
 
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 
         "cgi-programming/number-guess.scm"))
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 (A link to a program source marker in page-write) and a game playing part (A link to a program source marker in page-write). 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. 

 

 Overall design  the-program-part
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
 

The program  The init game part preamble-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 (A link to a program source marker in laml-dir). laml-dir is important, because it's value points at the root of the LAML system, which is used. Being at cs.auc.dk 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 (A link to a program source marker in additional-loading) 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. 

 

The program The preamble part The game part init-game
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 (A link to a program source marker in game-init).

Also notice the form element, generated by form-1 at (A link to a program source marker in game-init). 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 (A link to a program source marker in game-init), 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 (A link to a program source marker in guess-part). The secret number is passed on using a hidden field (A link to a program source marker in guess-part). 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 (A link to a program source marker in guess-part). 

 

The program The init game part  game-part
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 (A link to a program source marker in game-play), which returns an association list such as

((secret-number . "42") (players-guess . "22"))
We prepare a body with a new form element (as above) (A link to a program source marker in game-play). The conditional (A link to a program source marker in game-play) 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 (A link to a program source marker in game-play A link to a program source marker in game-play). In the lucky case where the player guesses the number an URL is given to restart the game (A link to a program source marker in game-play).