commit 27e26e49f891db1b5593c33ec4abe498964527c9
parent f1a790c2efb29a7e1a29c04330c52d8e8883f3f0
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sat, 10 Aug 2013 19:03:29 +0200
io refactored into cl-rw
Diffstat:
| M | cl-ipp.asd |  |  | 2 | +- | 
| M | ipp.lisp |  |  | 225 | ++++++++++++++++++++----------------------------------------------------------- | 
2 files changed, 58 insertions(+), 169 deletions(-)
diff --git a/cl-ipp.asd b/cl-ipp.asd
@@ -33,6 +33,6 @@
   :author "Tomas Hlavaty"
   :maintainer "Tomas Hlavaty"
   :licence "MIT"
-  :depends-on ()
+  :depends-on (:cl-rw)
   :serial t
   :components ((:file "ipp")))
diff --git a/ipp.lisp b/ipp.lisp
@@ -27,56 +27,6 @@
 
 (in-package :ipp)
 
-(defvar *input-stream*)
-(defvar *output-stream*)
-
-(defun read-octet ()
-  (let ((s *input-stream*))
-    (etypecase s
-      (stream (read-byte s))
-      (function (let ((x (funcall s)))
-                  (assert (<= 0 x 256))
-                  x)))))
-
-(defun write-octet (x)
-  (assert (<= 0 x #. (1- (expt 2 8))))
-  (let ((s *output-stream*))
-    (etypecase s
-      (stream (write-byte x s))
-      (function (funcall s x)))))
-
-(defun read-ushort ()
-  (logior (ash (read-octet) 8) (read-octet)))
-
-(defun write-ushort (x)
-  (assert (<= 0 x #.(1- (expt 2 16))))
-  (write-octet (ash x -8))
-  (write-octet (logand #xff x)))
-
-(defun read-dword ()
-  (logior (ash (read-ushort) 16) (read-ushort)))
-
-(defun write-dword (x)
-  (assert (<= 0 x #.(1- (expt 2 32))))
-  (write-ushort (ash x -16))
-  (write-ushort (logand #xffff x)))
-
-(defun copy-stream ()
-  (when *input-stream*
-    (handler-case (loop (write-octet (read-octet)))
-      (end-of-file ()))))
-
-(defun read-octets (n)
-  (let ((x (make-array n :element-type '(unsigned-byte 8) :initial-element 0)))
-    (read-sequence x *input-stream*)
-    x))
-
-(defun write-octets (x)
-  (etypecase x
-    (stream (let ((*input-stream* x)) (copy-stream)))
-    (list (mapc 'write-octet x))
-    (vector (map 'vector 'write-octet x))))
-
 (defun string-to-octets (x) ;; TODO encoding
   (ccl:encode-string-to-octets x))
 
@@ -138,8 +88,8 @@
 
 ;;(attribute-name :attributes-charset)
 
-(defun read-attribute ()
-  (let ((tag (read-octet)))
+(defun read-attribute (reader)
+  (let ((tag (rw:next-u8 reader)))
     (if (member tag (mapcar 'tag ;; TODO optimize
                             '(:operation-attributes-tag
                               :job-attributes-tag
@@ -147,47 +97,49 @@
                               :printer-attributes-tag
                               :unsupported-attributes-tag)))
         tag
-        `(,tag ;;(tag (attribute-tag k))
-          ,(octets-to-string (read-octets (read-ushort)))
-          , (case tag ;; TODO handle more cases
-              ((33 35)
-               (assert (= 4 (read-ushort)))
-               (read-dword))
-              (t (octets-to-string (read-octets (read-ushort)))))))))
-
-(defun read-groups ()
+        (flet ((text ()
+                 (octets-to-string
+                  (rw:next-octets reader (rw:next-u16 reader)))))
+          `(,tag ;;(tag (attribute-tag k))
+            ,(text)
+            , (case tag ;; TODO handle more cases
+                ((33 35)
+                 (assert (= 4 (rw:next-u16 reader)))
+                 (rw:next-u32 reader))
+                (t (text))))))))
+
+(defun read-groups (reader)
   (let ((sentinel (tag :end-of-attributes-tag)) ;; TODO optimize
-        (x (read-octet)))
+        (x (rw:next-u8 reader)))
     (loop
        until (= sentinel x)
        collect `(,x
                  ,@(loop
-                      while (consp (setq x (read-attribute)))
+                      while (consp (setq x (read-attribute reader)))
                       collect x)))))
 
 #+nil
-(with-open-file (*input-stream* "response.dat" :element-type '(unsigned-byte 8))
-  (read-ipp 314))
+(with-open-file (s "response.dat" :element-type '(unsigned-byte 8))
+  (read-ipp (rw:byte-reader s) 314))
 
-(defun write-group (group)
+(defun write-group (writer group)
   (destructuring-bind (group-id &rest plist) group
     (when (loop
              for (k v) on plist by #'cddr
              when v
              do (return t))
-      (write-octet group-id)
+      (rw:write-u8 writer group-id)
       (loop
          for (k v) on plist by #'cddr
          when v
          do (let ((%k (string-to-octets (attribute-name k)))
                   (%v (string-to-octets v)))
               ;; TODO additional value (when v is list)
-              (write-octet (tag (attribute-tag k)))
-              (write-ushort (length %k))
-              (write-octets %k)
-              (write-ushort (length %v))
-              (write-octets %v))))))
-
+              (rw:write-u8 writer (tag (attribute-tag k)))
+              (rw:write-u16 writer (length %k))
+              (rw:write-octets writer %k)
+              (rw:write-u16 writer (length %v))
+              (rw:write-octets writer %v))))))
 
 (defun operation-code (operation)
   (cdr (assoc operation '((:print-job 1 0 #x0002)
@@ -233,43 +185,44 @@
 
 ;;(operation-code :print-job)
 
-(defun write-ipp (data-file request-id operation groups)
+(defun write-ipp (writer data-file request-id operation groups)
   (destructuring-bind (major minor code) (operation-code operation)
-    (write-octet major)
-    (write-octet minor)
-    (write-ushort code)
-    (write-dword request-id)
-    (mapc 'write-group groups)
-    (write-octet (tag :end-of-attributes-tag))
+    (rw:write-u8 writer major)
+    (rw:write-u8 writer minor)
+    (rw:write-u16 writer code)
+    (rw:write-u32 writer request-id)
+    (dolist (i groups)
+      (write-group writer i))
+    (rw:write-u8 writer (tag :end-of-attributes-tag))
     (when data-file
-      (with-open-file (*input-stream* data-file :element-type '(unsigned-byte 8))
-        (copy-stream)))))
+      (with-open-file (s data-file :element-type '(unsigned-byte 8))
+        (rw:copy (rw:byte-reader s) writer)))))
 
-(defun read-ipp (request-id)
+(defun read-ipp (reader request-id)
   `(:ipp-response
-    :major ,(read-octet)
-    :minor ,(read-octet)
-    :code ,(read-ushort)
-    :request-id , (let ((x (read-dword)))
+    :major ,(rw:next-u8 reader)
+    :minor ,(rw:next-u8 reader)
+    :code ,(rw:next-u16 reader)
+    :request-id , (let ((x (rw:next-u32 reader)))
                     (assert (= x request-id))
                     x)
-    :groups ,(read-groups)))
+    :groups ,(read-groups reader)))
 
 #+nil
-(with-open-file (*input-stream* "response.dat" :element-type '(unsigned-byte 8))
-  (read-ipp 314))
+(with-open-file (s "response.dat" :element-type '(unsigned-byte 8))
+  (read-ipp (rw:byte-reader s) 314))
 
 (defun ipp (ipp-client printer-uri request-file response-file
             data-file request-id operation groups)
-  (with-open-file (*output-stream* request-file
-                                   :element-type '(unsigned-byte 8)
-                                   :direction :output
-                                   :if-exists :supersede
-                                   :if-does-not-exist :create)
-    (write-ipp data-file request-id operation groups))
+  (with-open-file (s request-file
+                     :element-type '(unsigned-byte 8)
+                     :direction :output
+                     :if-exists :supersede
+                     :if-does-not-exist :create)
+    (write-ipp (rw:byte-writer s) data-file request-id operation groups))
   (funcall ipp-client "application/ipp" printer-uri request-file response-file)
-  (with-open-file (*input-stream* response-file :element-type '(unsigned-byte 8))
-    (read-ipp request-id)))
+  (with-open-file (s response-file :element-type '(unsigned-byte 8))
+    (read-ipp (rw:byte-reader s) request-id)))
 
 (defun print-job (ipp-client
                   printer-uri
@@ -313,92 +266,28 @@
            :job-impressions ,job-impressions
            :job-media-sheets ,job-media-sheets))))
 
-(defun stream (x &optional (start 0))
-  (etypecase x
-    (list
-     (dotimes (i start)
-       (pop x))
-     (lambda ()
-       (pop x)))
-    (vector
-     (let ((i start)
-           (n (length x)))
-       (lambda ()
-         (when (< i n)
-           (prog1 (aref x i)
-             (incf i))))))))
-
-(defun char-stream (x &optional (start 0))
-  (dotimes (i start)
-    (read-char x nil nil))
-  (lambda ()
-    (read-char x nil nil)))
-
-(defun byte-stream (x &optional (start 0))
-  (dotimes (i start)
-    (read-byte x nil nil))
-  (lambda ()
-    (read-byte x nil nil)))
-
-(defun next (stream)
-  (funcall stream))
-
-(defun peek (stream)
-  (funcall stream 'peek))
-
-(defun peek-stream (stream)
-  (let (x)
-    (lambda (&optional msg)
-      (ecase msg
-        (peek (or x (setq x (next stream))))
-        ((nil) (prog1 (if x x (next stream))
-                 (setq x nil)))))))
-
-(defun till (stream &optional markers)
-  (let (x)
-    (loop
-       until (member (setq x (next stream)) (or markers '(nil)))
-       collect x)))
-
-;;(till (stream '(0 1 2 3 4) 1) '(3))
-;;(till (stream #(0 1 2 3 4) 1) '(3))
-;;(with-open-file (s "printers.html") (till (char-stream s) '(#\>)))
-
-(defun search-stream (stream needle)
-  (let ((all (till stream)) ;; TODO optimize? use kmp algorithm
-        (start 0))
-    (lambda ()
-      (let ((i (search needle all :start2 start)))
-        (when i
-          (setq start (1+ i))
-          (values i all))))))
-
-#+nil
-(with-open-file (s "printers.html")
-  (till (search-stream (char-stream s) '#.(coerce "/printers/" 'list))))
-
-(defun printer-search-stream (stream)
+(defun printer-search-reader (reader)
   (let* ((k '#.(coerce "\"/printers/" 'list)) ;; TODO #\' as attribute quote
          (n (length k))
-         (s (search-stream stream k)))
+         (s (rw:search-reader reader k)))
     (lambda ()
       (block found
         (loop
            (multiple-value-bind (i all) (funcall s)
              (unless i
-               (return-from found))
-             (let ((z (till (stream all (+ i n)) '(#\"))))
+               (return-from found nil))
+             (let ((z (rw:till (rw:reader all (+ i n)) '(#\"))))
                (when (and z (char/= #\? (car z)))
                  (return-from found (coerce z 'string))))))))))
 
 #+nil
 (with-open-file (s "printers.html")
-  (till (printer-search-stream (char-stream s))))
+  (rw:till (printer-search-reader (rw:char-reader s))))
 
 (defun list-printers (ipp-client printer-uri response-file)
   (funcall ipp-client nil printer-uri nil response-file)
   (with-open-file (s response-file)
-    (till (printer-search-stream (char-stream s)))))
+    (rw:till (printer-search-reader (rw:char-reader s)))))
 
 (defpackage :ipp.wget
   (:use :cl)