A poster presentation at the 1998 International Conference on Functional Programming (ICFP'98)
Mt. Washington Conference Center, Baltimore, MD, 27-29 September 1998
The subject of this presentation is a particular CGI scripting framework that allows:
This framework has been used extensively for several months in a production environment.
CGI#A form
(CGI:define name default-value)
defines an obscure datum and binds it to a import promise. The form also defines a macro -- cgi#name -- to access this obscure datum and perform typecasts on request.
The import promise parses the QUERY_STRING or a POST message and caches the result. The promise uses it when looking up all values of a given form parameter.
The following names are pre-defined (pre-imported) in the CGI namespace: cgi#query-string, cgi#query-parms,
cgi#self-url
(cgi#keywords)
keywords, or #f
(cgi#keywords :as-list)
OPTIONs, or ()
(cgi#keywords :as-full-string)
""
(cgi#keywords :as-name-value-io)
NAME=keywords VALUE=valueIO
(cgi#keywords :set! new-value)
new-value is to be used when generating an updated cgi form
The following piece of code declares two CGI variables that are being used by the code below. These are import clauses from a CGI namespace into the Scheme environment. As a regular define, a CGI:define may appear both on the top lexical level and within a procedure/scope.
(CGI:define block_id #f)
(CGI:define name #f)
Note that this piece of code has an internal CGI:define
(with-catching-of-signals
(lambda ()
(CGI:define do-search 'absent)
(mode-show-form
(call-with-current-continuation
(lambda (show-cont)
(cond
((not (eq? (cgi#do-search) 'absent))
(mode-search show-cont))
(else "<P>")))))))
(define (mode-show-form arg-res)
(cout "Content-type: text/html"
"\n\n"
...
"<FORM METHOD=POST ACTION=" (cgi#self-url) ">\n"
"<H3 ALIGN=CENTER>Specify search parameters</H3>"
"<TABLE CELLPADDING=2 CELLSPACING=5 BORDER=0>\n"
"<TR><TH>Station Block ID<TD>"
"<INPUT TYPE=TEXT " (cgi#block_id :as-name-value-io)
" SIZE=6 MAXLENGTH=6>\n"
"<TR><TH>Station's full name<TD>"
"<INPUT TYPE=TEXT " (cgi#name :as-name-value-io)
" SIZE=19 MAXLENGTH=19>\n</TABLE>"
"<INPUT TYPE=SUBMIT NAME=do-search VALUE=\"Find\"><P>"
"</FORM><P><HR>\n"
(if (procedure? arg-res) arg-res "")
"</BODY></HTML>"))
This function executes a search request submitted by a user via the form above.
(define (mode-search esc-to-show)
...
(when (cgi#name)
(++! search-criteria-count)
(sql-buffer 'accum-sql!
" AND MS.name LIKE '"
(string-upcase (cgi#name :as-full-string)) "'"))
...
(if (zero? search-criteria-count)
(esc-to-show
"<P><B>Nothing to search for</B>"))
...
)
(define-macro (CGI:define name . init-value)
(let ((ext-name
(string->symbol (string-append "_:CGI:" (symbol->string name))))
(locname (gensym)))
`(begin
(define ,ext-name
(delay (_:CGI:lookup ',name ,@init-value)))
(define-macro
,(cons
(string->symbol (string-append "cgi#" (symbol->string name)))
'optional-arg)
`(let ((,',locname (force ,',ext-name)))
,(cond
((null? optional-arg)
`(and ,',locname (car ,',locname)))
((equal? optional-arg '(:as-full-string))
`(if ,',locname (apply string-append
(list-intersperse ,',locname " "))
""))
(else (##signal '##signal.syntax-error "cgi#" optional-arg)) ))))))
A one-page abstract of this presentation [.ps.gz, 5K]
Other approaches
http://www.eval-apply.com/Scheme/cgi.htm
Parsing of a QUERY_STRING or a POST action message and converting them into an associative list
http://pobox.com/~oleg/ftp/Scheme/web.html#parsing.query-string
This example's complete source code
http://pobox.com/~oleg/ftp/Scheme/web.html#search-mslib
oleg-at-pobox.com or oleg-at-okmij.org