r5126: *** empty log message ***
[kmrcl.git] / web-utils.lisp
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          web-utils.lisp
6 ;;;; Purpose:       Basic web utility functions
7 ;;;; Programmer:    Kevin M. Rosenberg
8 ;;;; Date Started:  Apr 2000
9 ;;;;
10 ;;;; $Id: web-utils.lisp,v 1.13 2003/06/15 07:48:30 kevin Exp $
11 ;;;;
12 ;;;; This file, part of KMRCL, is Copyright (c) 2002 by Kevin M. Rosenberg
13 ;;;;
14 ;;;; KMRCL users are granted the rights to distribute and use this software
15 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
16 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
17 ;;;; *************************************************************************
18
19 (in-package #:kmrcl)
20
21
22 ;;; HTML/XML constants
23
24 (defvar *standard-xml-header* 
25   #.(format nil "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"yes\"?>~%"))
26
27 (defvar *standard-html-header* "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">")
28
29 (defvar *standard-xhtml-header*
30   #.(format nil "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"yes\"?>~%<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11\">"))
31
32
33 ;;; User agent functions
34
35 (defun user-agent-ie-p (agent)
36   "Takes a user-agent string and returns T for Internet Explorer."
37   (or (string-starts-with "Microsoft" agent)
38       (string-starts-with "Internet Explore" agent)
39       (search "MSIE" agent)))
40
41 ;;; URL Functions
42
43 (defvar *base-url* "")
44 (defun base-url! (url)
45   (setq *base-url* url))
46
47 (defun make-url (page-name &key (base-dir *base-url*) (format :html) (vars nil))
48   (let ((amp (case format
49                (:html
50                 "&")
51                ((:xml :ie-xml)
52                 "&amp;"))))
53     (concatenate 'string 
54       base-dir page-name
55       (if vars
56           (let ((first-var (first vars)))
57             (concatenate 'string 
58               "?"  (car first-var) "=" (cadr first-var)
59               (mapcar-append-string 
60                #'(lambda (var) 
61                    (when (and (car var) (cadr var))
62                      (concatenate 'string 
63                        amp (car var) "=" (cadr var))))
64                (rest vars))))
65         ""))))
66
67 (defun make-url-new (page-name &key (base-dir *base-url*) (format :html)
68                                (vars nil))
69   (let ((amp (ecase format
70                (:html "&")
71                ((:xml :ie-xml) "&amp;"))))
72     (concatenate 'string 
73          base-dir page-name
74          (if vars
75              (let ((first-var (first vars)))
76                (concatenate 'string 
77                             "?"  (car first-var) "=" (cadr first-var)
78                             (mapcar-append-string 
79                              #'(lambda (var) 
80                                  (when (and (car var) (cadr var))
81                                    (concatenate 'string 
82                                                 amp (car var) "=" (cadr var))))
83                              (rest vars))))
84            ""))))
85
86 (defun decode-uri-query-string (s)
87   "Decode a URI query string field"
88   (declare (simple-string s)
89            (optimize (speed 3) (safety 0) (space 0)))
90   (do* ((old-len (length s))
91         (new-len (- old-len (* 2 (count-string-char s #\%))))
92         (new (make-string new-len))
93         (p-old 0)
94         (p-new 0 (1+ p-new)))
95        ((= p-new new-len) new)
96     (declare (simple-string new)
97              (fixnum p-old p-new old-len new-len))
98          (let ((c (schar s p-old)))
99            (when (char= c #\+)
100              (setq c #\space))
101            (case c
102              (#\%
103               (unless (>= old-len (+ p-old 3))
104                 (error "#\% not followed by enough characters"))
105               (setf (schar new p-new)
106                     (code-char
107                      (parse-integer (subseq s (1+ p-old) (+ p-old 3))
108                                     :radix 16)))
109               (incf p-old 3))
110              (t
111               (setf (schar new p-new) c)
112               (incf p-old))))))