Le Sursis is a system to aid in writing CGI scripts in Common Lisp. This manual describes its use.

[ Next: | Previous:Top | Up:Top ]

Distribution and Copying

This is Version 0.1.1 of Le Sursis by Tom Burdick.

The latest version of Le Sursis can always be found on the Sursis web site .

Le Sursis is Free Software licensed to you, the user, under the terms of the GNU General Public License , a copy of which should be in the COPYING file included in the Le Sursis distribution. Please read it as it is designed to protect your rights as the user of this software; it also places certain restrictions on the use of this software so as to protect the rights of all users.

[ Next: | Previous:Dist and Copying | Up:Top ]


Le Sursis is an attempt to provide a good environment to write CGI scripts in Common Lisp. It consists of two packages: sursis and sursis-html. sursis contains the functions for retrieving CGI queries, and sursis-html contains a set of utility functions to make it easier to compose HTML. Although they are meant to be complimentary, each may be used independently of the other.

[ Next: | Previous:Introduction | Up:Introduction ]

What does Le Sursis mean?

Le Sursis nominally stands for "Sane and Usable Response to Scripting Internet Sites." However, "le sursis" is also French for "the reprieve," meant here in the sense of "a reprieve from Perl." And, alas, while Le Sursis is indeed a reprieve from Perl, it is not a solution. If one has to work on a CGI script with others, it will almost certainly be necessary to use a language other than Lisp. But, when you can use it, what a reprieve!

Also, Le Sursis is a novel by Jean-Paul Sartre, the second in the three-part series Les Chemins de la LibertÚ ("The Paths to Freedom"). It is a great book, M. Sartre was an amazing author and philosopher, and I would encourage everyone to read his work. The remainder of this manual will consider only the software.

[ Next: | Previous:The Name | Up:Introduction ]

Basic Usage

All examples given here use the .lsp extension for lisp files. In most situations, you would want to compile the lisp files from this distribution. Any references to compiled files will use the .fas extension used by CLISP which is the Common Lisp implementation used by the author.

All lisp files intended to be used as CGI scripts are assumed to begin with:


or the appropriate for the Lisp system being used, and are assumed to have the appropriate executable permissions.

[ Next: | Previous:Basic Usage | Up:Introduction ]

Basic sursis usage

The sursis package provides Le Sursis' interface to CGI queries.

For the simplest scripts, the following should suffice:

(load "sursis.lsp")
  => (("name1" . "value1") ... ("nameN" . "valueN"))

get-query's value is an association list; or, if no input was given to the script, it's value is nil.

The next most useful function exported is probably format-query. format-query takes an a-list as an argument and its value is a matching query string. For example:

  => (("greeting" . "Hello world!") ("tone" . "emphatic"))
(cgi:format-query *)
  => "?greeting=Hello+world!&tone=emphatic"

This makes it easy to have a cgi script recur on itself. In fact, it was this behavior of the majority of my cgi scripts that lead me to write this package.

For more detail, see The sursis Package.

[ Next: | Previous:Using sursis | Up:Introduction ]

Basic sursis-html usage

The sursis-html package provides utility functions to make it easier to write HTML responses. It exports functions with names corresponding to most common HTML tags. A simple example of its use is:

(load "sursis-html.lsp")
(use-package 's-html)
   (title "Test page"))
  (body nil
   (h1 "Section 1")
   (p "paragraph 1")
   (h2 "Subsection 1.1")
   (p (i "and so on...")))))
  => "Content-type: text/html

<!-- Generated with help from Le Sursis <http://sursis.sourceforge.net/> -->
<head><title>Test page</title></head>
<h1>Section 1</h1>
<p>paragraph 1</p>
<h2>Subsection 1.1</h2>
<p><i>and so on...</i></p>


The resulting html varies in readability, but the assumption is that the user prefers easily readable lisp. All the tag functions take multiple arguments for their bodies and concatenate these to form the text between the two tags (or after the tag in the case of <p>, <li>, and some others). A typical use could be as follows:

(format t (http-response
             (title "Thank You!"))
             (h1 "Thank You!")
             "Thank you for your response."))))

Some tags, for example the <img> tag, take attribute values. The functions for these take a required a-list argument before any tag contents. Ex:

(img '(("src" . "le-sursis.png")
       ("alt" . "The Le Sursis banner")))
  => "<img src=\"le-sursis.png\" alt=\"The Le Sursis banner\">"
(table '(("border" . "on")) "...")
  => "<table border=\"on\">...</table>"

Also note that some tag functions, like img, do not accept any arguments for their body, as they don't have one.

For more detail, see The sursis-html Package.

[ Next: | Previous:Using sursis-html | Up:Top ]

The sursis Package

The sursis package (which is also available via the nickname cgi) is in sursis.lsp. It exports functions for retrieving cgi query data and for forming queries. It currently supports only CLISP, but it should be portable to any Common Lisp system with a one or two line change (CL doesn't provide any mechanism for accessing environmental variables).

Currently (as of Version 0.1) the sursis package only supports GET queries. Version 0.2 will add support for POST queries. Also, the functions in this package have not been optimized to be tail-recursive. Version 0.3--or possibly sooner--should see the re-writing of some functions to be tail-recursive where efficiency or any potential stack overflows could be a concern.

[ Next: | Previous:The sursis Package | Up:The sursis Package ]


get-query &optional reget

get-query's value is an association list containing the key-value pairs given to the cgi script, or nil if none were given. Normally, get-query reads the query data in once and returns the same list every time it is called. This improves efficiency and is necessary for POST queries. If a non-nil value is given for the optional argument reget, get-query will behave as if it has not yet been run. This behavior is almost never desired, except under the most pathological circumstances.

Sample usage:

  => (("message" . "Hello World!") ("tone" . "emphatic"))

[ Next: | Previous:sursis-get-query | Up:The sursis Package ]


format-query al

format-query takes an association list al and returns an appropriately encoded string to be used as a GET query. Note that it ignores repeats of keys, so it is safe to acons pairs onto the head of the list returned by get-query. Unless you care about order, in which case you'll have to use a more awkward idiom.

Sample usage:

  => (("message" . "Hello World!") ("tone" . "emphatic"))
(acons "tone" "blasÚ" *)
  => (("tone" . "blasÚ") ("message" . "Hello World!") ("tone" . "emphatic"))
(cgi:format-query *)
  => "?tone=blas%e9&message=Hello+World!"
(format nil "http://path/to/self~A" *)
  => "http://path/to/self?tone=blas%e9&message=Hello+World!"

[ Next: | Previous:sursis-format-query | Up:The sursis Package ]


get-environment &optional reget toget

get-environment's value is an association list of environmental variables describing the CGI environment. Under normal circumstances, it reads from the environment once and returns the same list every time it is called. If the optional argument reget is non-nil, it will return a newly-constructed list. The optional variable toget, which should be a list of strings, specifies the environmental variables to include in the list. As of this writing, toget defaults to ("REQUEST_METHOD" "QUERY_STRING" "CONTENT_LENGTH"). This function will eventually inspect all environmental variables in the CGI specification; the user may wish to inspect the definition of get-environment before passing it a custom list, in case the desired variable has been added to the defaults. When specifying a custom list in toget, reget should be set to non-nil, or the behavior may be other than what was desired.

A note on the a-list returned by get-environment:

  1. If an environmental variable is set, the cdr of its entry in the a-list will be its value: ( variable-name . value ).
  2. If it is not set, the cdr of its entry will be nil: ( variable-name ).
  3. If is is set to "", the cdr of its entry will be "": ( variable-name . "" ).
Be careful not to mistake the second case for the third.

Sample usage:

  => (("REQUEST_METHOD" . "GET")
      ("QUERY_STRING" . "message=Hello+World!&tone=emphatic")
(cgi:get-environment nil '("SCI" "WWW_HOME" "USERNAME"))
  => (("REQUEST_METHOD" . "GET")
      ("QUERY_STRING" . "message=Hello+World!&tone=emphatic")
(cgi:get-environment t '("SCI" "WWW_HOME" "USERNAME"))
  => (("SCI" . "/usr/lib/scilab-2.4.1/")
      ("WWW_HOME" . "/home/noc/lynx_bookmarks.html")
      ("USERNAME" . ""))

It is worth noting that sursis contains a definition for getenv, which is a thin wrapper around the current Lisp system's function to retrieve a single environmental variable (this is not a part of Common Lisp, so the function name varies from system to system). It takes a single string as an argument and returns a string, or nil if the variable is not set. It is not exported, but it may be useful to call to retrieve a single variable from the environment.

[ Next: | Previous:sursis-get-environment | Up:Top ]

The sursis-html Package

The sursis-html package (which is also available via the nickname s-html) is in sursis-html.lsp. It exports a large number of utility functions to make it easier to form HTML responses to CGI queries. It is written entirely in Common Lisp, using no extensions.

Unless one wishes to only use the sursis-html functions a few times in a given script, one should import the functions provided by sursis-html. So long as one avoids the names of common html tags, this name-space pollution should not be a problem, and the increased readability of the Lisp code should more than make up for it.

This package is optimized to be tail-recursive.

[ Next: | Previous:The sursis-html Package | Up:The sursis-html Package ]

sursis-html Overview

Nearly every exported function is based on one of the two generic tag functions: sa-tag and tag. These functions are primitives for creating a stand-alone tag, and a normal tag (with a <name> and a </name> portion), respectively. All tag functions except those for purely stand-alone tags (i.e., tags like <br>, as opposed to <p>, which may be viewed as having contents, even if it need not be closed) have a &rest argument for the contents of the tag. The tag functions take the ~D representations from format for all of their &rest arguments and concatenate them together for the body of the tag:

(html "The" " value of x is" 12)
  => "<html>The value of x is 12</html>"

This allows nesting of the tag functions, as in:

   (title "Example"))
  (body nil "Hi.")))
  => "Content-type: text/html

<!-- Generated with help from Le Sursis <http://sursis.sourceforge.net/> -->

The readability of the Lisp code given above is the point of this package.

Although the http-response function used in the example above does not produce an HTML tag, it is provided to be consistent with the philosophy of the package.

Note that generation of the recognition comment above is controlled by a constant set at the top of sursis-html.lsp, and may be disabled.

[ Next: | Previous:sursis-html Overview | Up:The sursis-html Package ]

Simple Tags

All these functions are of the form:

name &rest sl

And produce output of the form: <name>body</name>. The reader should note that some of these functions insert line breaks for readability.

[ Next: | Previous:Simple Tags | Up:The sursis-html Package ]

Un-closed Tags

All these functions are of the form:

name &rest sl
And produce output of the form: <name>body. This is always followed with a newline, except for dt which omits the newline to increase readability:
(dt "term" (dd "definition of term"))
  => "<dt>term<dd>definition of term

[ Next: | Previous:Un-closed Tags | Up:The sursis-html Package ]

Stand-alone Tags

None of the functions in this section accept arguments for a body. They do not have a general form, so they will be addressed one at a time.

[ Next: | Previous:Stand-alone Tags | Up:The sursis-html Package ]

Tags with Attributes


These functions are of the form:

name atrib &rest sl
And produce output of the form: <name a1="v1" ...>body</name>. As with the simple tag functions, some insert line breaks for readability.


No functions are currently in this section.

[ Next: | Previous:Tags with Attributes | Up:The sursis-html Package ]

Miscellaneous Functions

These functions do not have a general form, so they will be addressed one at a time.

[ Previous:Misc Tags | Up:Top ]



Table of Contents