root/trunk/thirdparty/cl-qprint/base.lisp

Revision 3534, 3.9 kB (checked in by hans, 6 months ago)

update cl-qprint to version 0.2.1

Line 
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;;;; base.lisp: The Program
3 ;;;; Copyright (C) 2004 Robert Marlow <rob@bobturf.org>
4 ;;;;
5 ;;;; This library is free software; you can redistribute it and/or
6 ;;;; modify it under the terms of the GNU Library General Public
7 ;;;; License as published by the Free Software Foundation; either
8 ;;;; version 2 of the License, or (at your option) any later version.
9 ;;;;
10 ;;;; This library is distributed in the hope that it will be useful,
11 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 ;;;; Library General Public License for more details.
14 ;;;;
15 ;;;; You should have received a copy of the GNU Library General Public
16 ;;;; License along with this library; if not, write to the
17 ;;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 ;;;; Boston, MA  02111-1307, USA.
19 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20
21
22 (defpackage cl-qprint
23   (:use :cl)
24   (:nicknames :qprint)
25   (:export :encode
26            :decode))
27
28
29 (in-package :cl-qprint)
30
31 (defun decode (input)
32   "INPUT must be a string or a stream. Reads quoted-printable encoding
33 from INPUT and produces the equivalent decoded string"
34   (let ((out-stream (make-string-output-stream))
35         (in-stream
36          (etypecase input
37            (string (make-string-input-stream input))
38            (stream input))))
39     (do ((char (read-char in-stream nil 'eof)
40                (read-char in-stream nil 'eof)))
41         ((eql char 'eof)
42          (get-output-stream-string out-stream))
43       (princ (if (char= char #\=)
44                  (let ((char2 (read-char in-stream)))
45                    ;; Check for and convert all newlines (LF or CRLF)
46                    ;; to nothing. The = indicates a soft line break.
47                    (if (member char2 '(#\return #\linefeed)
48                                :test #'char=)
49                        (let ((char3 (read-char in-stream nil 'eof)))
50                          (cond
51                            ((eql char3 'eof) "")
52                            ((and (char= char3 #\linefeed)
53                                  (char= char2 #\return)) "")
54                            (t char3)))
55                        ;; If not a newline the = indicates encoding
56                        (code-char (parse-integer
57                                    (format nil "~C~C"
58                                            char2
59                                            (read-char in-stream nil 'eof))
60                                    :radix 16))))
61                  char)
62              out-stream))))
63
64
65 (defun cr-lf (stream)
66   "Prints a CRLF sequence to STREAM. RFC 2045 mandates CRLF for newlines"
67   (princ #\return stream)
68   (princ #\linefeed stream))
69
70
71 (defun encode (input &key columns encode-newlines)
72   "INPUT must be either a string or a stream. Reads from INPUT and produces
73 a quoted-printable encoded string"
74   (let ((out-stream (make-string-output-stream))
75         (in-stream
76          (etypecase input
77            (string (make-string-input-stream input))
78            (stream input)))
79         (last-line-break 0)
80         (ws nil))
81    
82     (do ((c (read-char in-stream nil 'eof)
83             (read-char in-stream nil 'eof))
84          (position 0 (file-position out-stream)))
85         ((eql c 'eof)
86          (get-output-stream-string out-stream))
87
88       ;; Put in a soft line break if the line's gotten too long
89       (when (and columns
90                  (>= (- position last-line-break) (1- columns)))
91         (princ #\= out-stream)
92         (cr-lf out-stream)
93         (setf last-line-break position))
94      
95       ;; ws on the end of a line must be encoded
96       (when ws
97         (if (char= c #\newline)
98             (format out-stream "=~2,'0X" (char-code ws))
99             (princ ws out-stream)))
100      
101       (cond
102
103         ;; Ensure newlines are CR-LF
104         ((char= c #\newline)
105          (if encode-newlines
106            (format out-stream "=0D=0A")
107            (cr-lf out-stream))
108          (setf last-line-break position))
109
110         ;; Keep track of whitespace in case of following newlines
111         ((member c '(#\space #\tab) :test #'char=)
112          (setf ws c))
113        
114         ;; Encode non-printable characters and =
115         ((or (char< c #\!)
116              (char> c #\~)
117              (char= c #\=))
118          (format out-stream "=~2,'0X" (char-code c)))
119
120         ;; Else just print the character.
121         (t (princ c out-stream)))
122
123       ;; Keep track of whitespace in case we hit a newline
124       (unless (member c '(#\space #\tab) :test #'char=)
125         (setf ws nil)))))
126
127      
Note: See TracBrowser for help on using the browser.