(module cgi-unit mzscheme (require (lib "unitsig.ss") (lib "etc.ss")) (require "cgi-sig.ss") (provide net:cgi@) (define net:cgi@ (unit/sig net:cgi^ (import) ;; type bindings = list ((symbol . string)) ;; -------------------------------------------------------------------- ;; Exceptions: (define-struct cgi-error ()) ;; chars : list (char) ;; -- gives the suffix which is invalid, not including the `%' (define-struct (incomplete-%-suffix cgi-error) (chars)) ;; char : char ;; -- an invalid character in a hex string (define-struct (invalid-%-suffix cgi-error) (char)) ;; -------------------------------------------------------------------- ;; query-chars->string : ;; list (char) -> string ;; -- The input is the characters post-processed as per Web specs, which ;; is as follows: ;; spaces are turned into "+"es and lots of things are turned into %XX, ;; where XX are hex digits, eg, %E7 for ~. The output is a regular ;; Scheme string with all the characters converted back. (define query-chars->string (lambda (chars) (list->string (let loop ((chars chars)) (if (null? chars) null (let ((first (car chars)) (rest (cdr chars))) (let-values (((this rest) (cond ((char=? first #\+) (values #\space rest)) ((char=? first #\%) (if (and (pair? rest) (pair? (cdr rest))) (values (integer->char (or (string->number (string (car rest) (cadr rest)) 16) (raise (make-invalid-%-suffix (if (string->number (string (car rest)) 16) (cadr rest) (car rest)))))) (cddr rest)) (raise (make-incomplete-%-suffix rest)))) (else (values first rest))))) (cons this (loop rest))))))))) ;; string->html : ;; string -> string ;; -- the input is raw text, the output is HTML appropriately quoted (define string->html (lambda (s) (apply string-append (map (lambda (c) (case c ((#\<) "<") ((#\>) ">") ((#\&) "&") (else (string c)))) (string->list s))))) (define default-text-color "#000000") (define default-bg-color "#ffffff") (define default-link-color "#cc2200") (define default-vlink-color "#882200") (define default-alink-color "#444444") ;; generate-html-output : ;; html-string x list (html-string) x ... -> () (define generate-html-output (opt-lambda (title body-lines (text-color default-text-color) (bg-color default-bg-color) (link-color default-link-color) (vlink-color default-vlink-color) (alink-color default-alink-color)) (let ((sa string-append)) (for-each (lambda (l) (display l) (newline)) `("Content-type: text/html" "" "" "" "
" ,(sa ""
,@(map
(lambda (bind)
(string-append
(symbol->string (car bind))
" --> "
(cdr bind)
"
"))
bindings)
"
")))
;; extract-bindings :
;; (string + symbol) x bindings -> list (string)
;; -- Extracts the bindings associated with a given name. The semantics
;; of forms states that a CHECKBOX may use the same NAME field multiple
;; times. Hence, a list of strings is returned. Note that the result
;; may be the empty list.
(define extract-bindings
(lambda (field-name bindings)
(let ((field-name (if (symbol? field-name) field-name
(string->symbol field-name))))
(let loop ((found null) (bindings bindings))
(if (null? bindings)
found
(if (equal? field-name (caar bindings))
(loop (cons (cdar bindings) found) (cdr bindings))
(loop found (cdr bindings))))))))
;; extract-binding/single :
;; (string + symbol) x bindings -> string
;; -- used in cases where only one binding is supposed to occur
(define extract-binding/single
(lambda (field-name bindings)
(let ((field-name (if (symbol? field-name) field-name
(string->symbol field-name))))
(let ((result (extract-bindings field-name bindings)))
(cond
((null? result)
(generate-error-output
`(,(string-append "No binding for field `"
(if (symbol? field-name)
(symbol->string field-name)
field-name)
"' in ") ,@(bindings-as-html bindings)))) ((null? (cdr result)) (car result)) (else (generate-error-output `(,(string-append "Multiple bindings for field `" (if (symbol? field-name) (symbol->string field-name) field-name) "' where only one was expected in
") ,@(bindings-as-html bindings))))))))) ;; get-cgi-method : ;; () -> string ;; -- string is either GET or POST (though future extension is possible) (define get-cgi-method (lambda () (getenv "REQUEST_METHOD"))) ;; generate-link-text : ;; string x html-string -> html-string (define generate-link-text (lambda (url anchor-text) (string-append "" anchor-text ""))) ;; ==================================================================== )))