r10227: updates from phoview@lynx
[kmrcl.git] / web-utils.lisp
index 4fe21b9ab7e99a5c7800e2e7b872c5ff15e0a0df..da7d6b73918bdd50e21b27c9be90628eec154c54 100644 (file)
@@ -7,7 +7,7 @@
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Apr 2000
 ;;;;
-;;;; $Id: web-utils.lisp,v 1.7 2002/10/16 23:34:33 kevin Exp $
+;;;; $Id$
 ;;;;
 ;;;; This file, part of KMRCL, is Copyright (c) 2002 by Kevin M. Rosenberg
 ;;;;
 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
 ;;;; *************************************************************************
 
-(in-package :kmrcl)
-(declaim (optimize (speed 3) (safety 1) (compilation-speed 0) (debug 3)))
+(in-package #:kmrcl)
 
 
 ;;; HTML/XML constants
 
 (defvar *standard-xml-header* 
-  #.(format nil "<?xml version=\"1.0\" ?>~%<?xml-stylesheet type=\"text/css\" href=\"http://b9.com/umlsxml.css\" ?>~%~%"))
+  #.(format nil "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"yes\"?>~%"))
 
 (defvar *standard-html-header* "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">")
 
 (defvar *standard-xhtml-header*
-  #.(format nil "<?xml version=\"1.0\" standalone=\"yes\"?>~%<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"))
+  #.(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.dtd\">"))
+
+
+;;; User agent functions
+
+(defun user-agent-ie-p (agent)
+  "Takes a user-agent string and returns T for Internet Explorer."
+  (or (string-starts-with "Microsoft" agent)
+      (string-starts-with "Internet Explore" agent)
+      (search "Safari" agent)
+      (search "MSIE" agent)))
 
-  
 ;;; URL Functions
 
 (defvar *base-url* "")
 (defun base-url! (url)
   (setq *base-url* url))
 
-(defun make-url (page-name &key (base-dir *base-url*) (vars nil))
-  (concatenate 'string base-dir page-name
-              (if vars
-                  (string-trim-last-character
-                   (concatenate 'string "?"
-                                (mapcar-append-string 
-                                 #'(lambda (var) 
-                                     (when (and (car var) (cadr var))
-                                         (concatenate 'string 
-                                           (car var) "=" (cadr var) "&")))
-                                 vars)))
-                "")))
+(defun make-url (page-name &key (base-dir *base-url*) (format :html) vars anchor)
+  (let ((amp (case format
+              (:html
+               "&")
+              ((:xml :ie-xml)
+               "&amp;"))))
+    (concatenate 'string 
+      base-dir page-name
+      (if vars
+         (let ((first-var (first vars)))
+           (concatenate 'string 
+             "?"  (car first-var) "=" (cdr first-var)
+             (mapcar-append-string 
+              #'(lambda (var) 
+                  (when (and (car var) (cdr var))
+                    (concatenate 'string 
+                      amp (string-downcase (car var)) "=" (cdr var))))
+              (rest vars))))
+       "")
+      (if anchor
+         (concatenate 'string "#" anchor)
+       ""))))
+
+(defun decode-uri-query-string (s)
+  "Decode a URI query string field"
+  (declare (simple-string s)
+          (optimize (speed 3) (safety 0) (space 0)))
+  (do* ((old-len (length s))
+       (new-len (- old-len (* 2 (the fixnum (count-string-char s #\%)))))
+       (new (make-string new-len))
+       (p-old 0)
+       (p-new 0 (1+ p-new)))
+       ((= p-new new-len) new)
+    (declare (simple-string new)
+            (fixnum p-old p-new old-len new-len))
+        (let ((c (schar s p-old)))
+          (when (char= c #\+)
+            (setq c #\space))
+          (case c
+            (#\%
+             (unless (>= old-len (+ p-old 3))
+               (error "#\% not followed by enough characters"))
+             (setf (schar new p-new)
+                   (code-char
+                    (parse-integer (subseq s (1+ p-old) (+ p-old 3))
+                                   :radix 16)))
+             (incf p-old 3))
+            (t
+             (setf (schar new p-new) c)
+             (incf p-old))))))
+
+(defun split-uri-query-string (s)
+  (mapcar
+   (lambda (pair)
+     (let ((pos (position #\= pair)))
+       (when pos
+        (cons (subseq pair 0 pos)
+              (when (> (length pair) pos)
+                (decode-uri-query-string (subseq pair (1+ pos))))))))
+   (delimited-string-to-list s #\&)))