;;; -*- Mode:LISP; Package:XDR; Readtable:CL; Base:10 -*- ;;; (c) LISP Machine, Inc. 1986 ;;; All Rights Reserved ;;; See filename "copyright.text" for ;;; further information. ;;; (C) Copyright 1987, LISP MACHINE INC ;;; See filename "Copyright.Text" for more information. ;;; ********************************************************* ;;; ********************************************************* ;;; *** NOTE: This is an EXAMPLE, not LMI supported code. *** ;;; *** information contained in this example is subject *** ;;; *** to change without notice. The ways of doing *** ;;; *** the things contained in the example may change *** ;;; *** between system releases. Some techniques which *** ;;; *** are mere examples in one release may become built *** ;;; *** in system features in the next release. Use good *** ;;; *** judgement when copying these techniques. Most *** ;;; *** examples have been motivated by specific customer *** ;;; *** requests, and may not be the best engineered *** ;;; *** or most efficient solution for someone else. *** ;;; ********************************************************* ;;; ********************************************************* ;;; Implementation of XDR in Common Lisp. ;;; Following the "External Data Representation Protocol Specification" ;;; Published by Sun Microsystems, Revision B of 17 February 1986. ;;; ;;; Design Discussion in "xdr.notes" ;;; 17-Jul-86 09:30:33 -George Carrette (defstruct (xdr (:conc-name xdr_) (:print-function xdr-print-function)) (op :free) ; may be also :ENCODE or :DECODE getlong putlong getbytes putbytes getpostn setpostn inline destroy) (defun xdr-print-function (object stream ignore) (format stream "#<~A ~S>" (type-of object) (xdr_op object))) (defstruct (xdrstdio (:conc-name xdrstdio_) (:include xdr)) stream) (defstruct (xdrmem (:conc-name xdrmem_) (:include xdr) (:print-function xdrmem-print-function)) array index length) (defstruct (xdrsize (:conc-name xdrsize_) (:include xdr) (:print-function xdrsize-print-function)) size) (defstruct (xdrrec (:conc-name xdrrec_) (:include xdr)) ) (defun xdrmem-print-function (object stream ignore) (format stream "#<~A ~S ~D ~D>" (type-of object) (xdr_op object) (xdrmem_index object) (xdrmem_length object))) (defun xdrsize-print-function (object stream ignore) (format stream "#" (xdrsize_size object))) (defun xdrstdio_create (x_op fp) "Returns an XDR object that writes or reads characters on FP" (let ((xdrs (make-xdrstdio :op x_op))) (setf (xdrstdio_stream xdrs) fp) (setf (xdr_inline xdrs) 'stdio-inline) (setf (xdr_destroy xdrs) 'stdio-destroy) (ecase x_op (:encode (setf (xdr_putlong xdrs) 'stdio-putlong) (setf (xdr_putbytes xdrs) 'stdio-putbytes)) (:decode (setf (xdr_getlong xdrs) 'stdio-getlong) (setf (xdr_getbytes xdrs) 'stdio-getbytes))) xdrs)) (defun xdrmem_create (x_op array &optional (start 0) (end (length array))) "returns an XDR object to write data into array" (let ((xdrs (make-xdrmem :op x_op))) (setf (xdrmem_array xdrs) array) (setf (xdrmem_index xdrs) start) (setf (xdrmem_length xdrs) end) (setf (xdr_inline xdrs) 'mem-inline) (setf (xdr_destroy xdrs) 'mem-destroy) (setf (xdr_getpostn xdrs) 'mem-getpostn) (ecase x_op (:encode (setf (xdr_putlong xdrs) 'mem-putlong) (setf (xdr_putbytes xdrs) 'mem-putbytes)) (:decode (setf (xdr_getlong xdrs) 'mem-getlong) (setf (xdr_getbytes xdrs) 'mem-getbytes))) xdrs)) (defun xdrsize_create () "returns an XDR object to find the size of data" (let ((xdrs (make-xdrsize :op :encode))) (setf (xdrsize_size xdrs) 0) (setf (xdr_putlong xdrs) 'size-putlong) (setf (xdr_putbytes xdrs) 'size-putbytes) (setf (xdr_getpostn xdrs) 'size-getpostn) (setf (xdr_setpostn xdrs) 'size-setpostn) xdrs)) (defun xdrrec_create (sendsize recvsize iohandle readproc writeproc) sendsize recvsize iohandle readproc writeproc (error "unimplemented")) (defun xdrrec_endofrecord (xdrs flushnow) (check-type xdrs xdrrec) flushnow (error "unimplemented")) (defun xdrrec_skiprecord (xdrs) (check-type xdrs xdrrec) (error "unimplemented")) (defun exdrrec_eof (xdrs) (check-type xdrs xdrrec) (error "unimplemented")) (defun xdr_destroy (xdrs) (check-type xdrs xdr) (funcall (xdr_destroy xdrs) xdrs)) (defun xdr_inline (xdrs) (check-type xdrs xdr) (funcall (xdr_inline xdrs) xdrs)) (defun xdr_getpos (xdrs) (check-type xdrs xdr) (funcall (or (xdr_getpostn xdrs) (error "operation not handled")) xdrs)) (defun xdr_setpos (xdrs n) (check-type xdrs xdr) (funcall (or (xdr_setpostn xdrs) (error "operation not handled")) xdrs n)) ;;; xdr stream implementation. (defun stdio-getlong (xdrs) (let ((stream (xdrstdio_stream xdrs))) (dpb (read-byte stream) (byte 8 24) (dpb (read-byte stream) (byte 8 16) (dpb (read-byte stream) (byte 8 8) (read-byte stream)))))) (defun stdio-putlong (xdrs x) (let ((stream (xdrstdio_stream xdrs))) (write-byte (ldb (byte 8 24) x) stream) (write-byte (ldb (byte 8 16) x) stream) (write-byte (ldb (byte 8 8) x) stream) (write-byte (ldb (byte 8 0) x) stream))) (defun stdio-putbytes (xdrs string start end) ;; whats the CL equivalent of string-out ? #+LMI (send (xdrstdio_stream xdrs) :string-out string start end) #-LMI (do ((j start (1+ start))) ((= j end)) (write-char (aref string j) (xdrstdio_stream xdrs)))) (defun stdio-getbytes (xdrs string start end) #+LMI (send (xdrstdio_stream xdrs) :string-in nil string start end) #-LMI (do ((j start (1+ start))) ((= j end)) (setf (aref string j) (read-char (xdrstdio_stream xdrs))))) (defun stdio-inline (xdrs) xdrs ()) (defun stdio-destroy (xdrs) (force-output (xdrstdio_stream xdrs)) (setf (xdr_op xdrs) :free)) (defun mem-getlong (xdrs) (let ((i (xdrmem_index xdrs)) (a (xdrmem_array xdrs))) (prog1 (dpb (char-code (aref a i)) (byte 8 24) (dpb (char-code (aref a (setq i (1+ i)))) (byte 8 16) (dpb (char-code (aref a (setq i (1+ i)))) (byte 8 8) (char-code (aref a (setq i (1+ i))))))) (setf (xdrmem_index xdrs) (1+ i))))) (defun mem-putlong (xdrs x) (let ((i (xdrmem_index xdrs)) (a (xdrmem_array xdrs))) (aset (ldb (byte 8 24) x) a i) (aset (ldb (byte 8 16) x) a (setq i (1+ i))) (aset (ldb (byte 8 8) x) a (setq i (1+ i))) (aset (ldb (byte 8 0) x) a (setq i (1+ i))) (setf (xdrmem_index xdrs) (1+ i)))) (defun mem-putbytes (xdrs string start end) (let ((i (xdrmem_index xdrs))) (copy-array-portion string start end (xdrmem_array xdrs) i (setq i (+ (- end start) i))) (setf (xdrmem_index xdrs) i))) (defun mem-getbytes (xdrs string start end) (let ((i (xdrmem_index xdrs))) (copy-array-portion (xdrmem_array xdrs) i (setq i (+ (- end start) i)) string start end) (setf (xdrmem_index xdrs) i))) (defun mem-inline (xdrs) xdrs ()) (defun mem-destroy (xdrs) xdrs (setf (xdr_op xdrs) :free)) (defun mem-getpostn (xdrs) (xdrmem_index xdrs)) (defun size-putlong (xdrs x) x (incf (xdrsize_size xdrs) 4)) (defun size-putbytes (xdrs string start end) string (incf (xdrsize_size xdrs) (- end start))) (defun size-getpostn (xdrs) (xdrsize_size xdrs)) (defun size-setpostn (xdrs n) (setf (xdrsize_size xdrs) n)) ;; XDR encode/decode procedures (defun get-xdr-property (type kind) (etypecase type (symbol (or (get type kind) (error "Undefined XDR type: ~S" type))) (cons (get-xdr-property (car type) kind)))) (defun xdr_transmit (xdrs object type) (check-type xdrs xdr) (funcall (get-xdr-property type 'xdr-transmit) xdrs object type)) (defun xdr_receive (xdrs type) (check-type xdrs xdr) (funcall (get-xdr-property type 'xdr-receive) xdrs type)) (defun (void xdr-transmit) (xdrs object type) xdrs object type nil) (defun (void xdr-receive) (xdrs type) xdrs type ()) (defun (int xdr-transmit) (xdrs object type) type (funcall (xdr_putlong xdrs) xdrs (int->long object))) (defun int->long (int) (cond ((minusp int) (cond ((< int (- (expt 2 31))) (error "number too small to be an int: ~S" int)) ('else (+ int (expt 2 32))))) ((< int (expt 2 31)) int) ('else (error "number too large to be an int: ~S" int)))) (defun long->int (long) (cond ((> long (expt 2 31)) (- long (expt 2 32))) ('else long))) (defun (int xdr-receive) (xdrs type) type (long->int (funcall (xdr_getlong xdrs) xdrs))) (defun (u_int xdr-transmit) (xdrs object type) type (funcall (xdr_putlong xdrs) xdrs object)) (defun (u_int xdr-receive) (xdrs type) type (funcall (xdr_getlong xdrs) xdrs)) (defun (float xdr-receive) (xdrs type) xdrs type (error "unimplemented")) (defun (double xdr-receive) (xdrs type) xdrs type (error "unimplemented")) (defun (float xdr-transmit) (xdrs object type) xdrs object type (error "unimplemented")) (defun (double xdr-transmit) (xdrs object type) xdrs object type (error "unimplemented")) (defun xdr_enumeration (type alist &key relaxed) (let ((marker (intern (format nil "xdr_marker-~A" type) "XDR")) (max (apply #'max (mapcar #'cadr alist)))) (when (record-xdr-source type) (setf (get type 'enumeration-marker) marker) (cond (relaxed (setf (get type 'xdr-transmit) 'relaxed-enumeration-xdr-transmit) (setf (get type 'xdr-receive) 'relaxed-enumeration-xdr-receive)) ('else (setf (get type 'xdr-transmit) 'enumeration-xdr-transmit) (setf (get type 'xdr-receive) 'enumeration-xdr-receive))) (do ((l alist (cdr l)) (array (make-array (1+ max)))) ((null l) (setf (get type 'enumeration-table) array)) (let ((symbol (caar l)) (value (cadr (car l)))) (setf (aref array value) symbol) (setf (get symbol marker) value))) type))) (defun enumeration-xdr-transmit (xdrs object type) (funcall (xdr_putlong xdrs) xdrs (enumeration->long object type))) (defun enumeration-xdr-receive (xdrs type) (long->enumeration (funcall (xdr_getlong xdrs) xdrs) type)) (defun enumeration->long (object type) (or (get object (get type 'enumeration-marker)) (error "Not an element of the ~S enumeration: ~S" type object))) (defun long->enumeration (object type) (aref (get type 'enumeration-table) object)) (defun relaxed-enumeration-xdr-transmit (xdrs object type) (funcall (xdr_putlong xdrs) xdrs (etypecase object (symbol (enumeration->long object type)) (number object)))) (defun relaxed-enumeration-xdr-receive (xdrs type) (let ((object (funcall (xdr_getlong xdrs) xdrs)) (table (get type 'enumeration-table))) (cond ((< object (length table)) (or (aref table object) object)) ('else object)))) (defvar *bytesink* (make-string 4)) (defun padbytes-transmit (xdrs n) (let ((pad (- 4 (mod n 4)))) (cond ((= pad 4)) ('else (funcall (xdr_putbytes xdrs) xdrs *bytesink* 0 pad))))) (defun padbytes-receive (xdrs n) (let ((pad (- 4 (mod n 4)))) (cond ((= pad 4)) ('else (funcall (xdr_getbytes xdrs) xdrs *bytesink* 0 pad))))) (defun (string xdr-transmit) (xdrs object type) (let ((n (length object))) (or (atom type) (<= n (cadr type)) (error "string longer than ~D: ~S" (cadr type) object)) (funcall (xdr_putlong xdrs) xdrs n) (funcall (xdr_putbytes xdrs) xdrs object 0 n) (padbytes-transmit xdrs n))) (defun (string xdr-receive) (xdrs type) (let ((n (funcall (xdr_getlong xdrs) xdrs)) (s)) (or (atom type) (<= n (cadr type)) (error "string longer than ~D" (cadr type))) (setq s (make-string n)) (funcall (xdr_getbytes xdrs) xdrs s 0 n) (padbytes-receive xdrs n) s)) (defun (opaque xdr-transmit) (xdrs object type) (let ((n (cadr type))) (funcall (xdr_putbytes xdrs) xdrs object 0 n) (padbytes-transmit xdrs n))) (defun (opaque xdr-receive) (xdrs type) (let* ((n (cadr type)) (s (make-string n))) (funcall (xdr_getbytes xdrs) xdrs s 0 n) (padbytes-receive xdrs n) s)) (defun (array xdr-transmit) (xdrs object type) (let ((n (length object)) (max (or (caddr type) 10000))) (if (> n max) (error "array longer than ~D" max)) (xdr_transmit xdrs n 'int) (dotimes (j n) (xdr_transmit xdrs (aref object j) (cadr type))))) (defun (array xdr-receive) (xdrs type) (let ((n (xdr_receive xdrs 'int)) (a) (max (or (caddr type) 10000))) (if (> n max) (error "array longer than ~D" max)) (setq a (make-array n)) (dotimes (j n) (setf (aref a j) (xdr_receive xdrs (cadr type)))) a)) (defstruct (descriminated-union (:conc-name "") (:print-function print-descriminated-union)) descriminator descriminated-value) (defun xdr_make_descrimination (descriminator value) (make-descriminated-union :descriminator descriminator :descriminated-value value)) (defun print-descriminated-union (object stream ignore) (format stream "#" (descriminator object) (descriminated-value object))) (defun xdr_descriminated_union (typename descrim alist) (when (record-xdr-source typename) (setf (get typename 'xdr-transmit) 'descriminated-union-xdr-transmit) (setf (get typename 'xdr-receive) 'descriminated-union-xdr-receive) (setf (get typename 'descriminated-union) (cons descrim alist)) typename)) (defun descriminated-union-xdr-transmit (xdrs object type) (check-type object descriminated-union) (let ((info (get type 'descriminated-union))) (xdr_transmit xdrs (descriminator object) (car info)) (xdr_transmit xdrs (descriminated-value object) (cadr (or (assq (descriminator object) (cdr info)) (assq 'default (cdr info))))))) (defun descriminated-union-xdr-receive (xdrs type) (let* ((info (get type 'descriminated-union)) (descriminator (xdr_receive xdrs (car info)))) (make-descriminated-union :descriminator descriminator :descriminated-value (xdr_receive xdrs (cadr (or (assq descriminator (cdr info)) (assq 'default (cdr info)))))))) ;; sometimes it is not worth given a name for a descrimination ;; so we say (descrimination dtype . cases) (defun (descrimination xdr-transmit) (xdrs object type) (check-type object descriminated-union) (let ((d (descriminator object)) (info (cdr type))) (xdr_transmit xdrs d (car info)) (xdr_transmit xdrs (descriminated-value object) (cadr (or (assq d (cdr info)) (assq 'default (cdr info))))))) (defun (descrimination xdr-receive) (xdrs type) (let* ((info (cdr type)) (descriminator (xdr_receive xdrs (car info)))) (make-descriminated-union :descriminator descriminator :descriminated-value (xdr_receive xdrs (cadr (or (assq descriminator (cdr info)) (assq 'default (cdr info)))))))) (defstruct (xdr_structure (:print-function print-xdr-structure) (:constructor cons-xdr-structure (type array))) type array) (defun print-xdr-structure (object stream ignore) (format stream "#<~S" (xdr_structure-type object)) (do ((j 0 (1+ j)) (l (get (xdr_structure-type object) 'xdr-structure-slots) (cdr l))) ((null l)) (format stream " ~S ~S" (car l) (aref (xdr_structure-array object) j))) (princ ">" stream)) (defun xdr_make_structure (type &rest elements) (let* ((slots (or (get type 'xdr-structure-slots) (error "unknown structure type: ~S" type))) (array (make-array (length slots)))) (do ((l elements (cddr l))) ((null l) (cons-xdr-structure type array)) (setf (aref array (or (find-position-in-list (car l) slots) (error "no slot named ~S in ~S structure" (car l) type))) (cadr l))))) (defun xdr_structure_ref (object slotname) (aref (xdr_structure-array object) (or (find-position-in-list slotname (get (xdr_structure-type object) 'xdr-structure-slots)) (error "no slot named ~S in ~S structure" slotname (xdr_structure-type object))))) (defsetf xdr_structure_ref xdr_structure_set) (defun xdr_structure_set (object slotname value) (setf (aref (xdr_structure-array object) (find-position-in-list slotname (get (xdr_structure-type object) 'xdr-structure-slots))) value)) (defun xdr_structure (typename elements) "Elements is a list of (slot-name slot-type)" (when (record-xdr-source typename) (setf (get typename 'xdr-transmit) 'structure-xdr-transmit) (setf (get typename 'xdr-receive) 'structure-xdr-receive) (setf (get typename 'xdr-structure) (mapcar #'cadr elements)) (setf (get typename 'xdr-structure-slots) (mapcar #'car elements)) typename)) (defun structure-xdr-transmit (xdrs object type) (check-type object xdr_structure) (do ((j 0 (1+ j)) (l (get type 'xdr-structure) (cdr l)) (array (xdr_structure-array object))) ((null l)) (xdr_transmit xdrs (aref array j) (car l)))) (defun structure-xdr-receive (xdrs type) (let ((types (get type 'xdr-structure))) (do ((array (make-array (length types))) (j 0 (1+ j)) (l types (cdr l))) ((null l) (cons-xdr-structure type array)) (setf (aref array j) (xdr_receive xdrs (car l)))))) (defun (list xdr-transmit) (xdrs object type) (let ((element-type (cadr type))) (dolist (element object) (xdr_transmit xdrs t 'boole) (xdr_transmit xdrs element element-type)) (xdr_transmit xdrs nil 'boole))) (defun (list xdr-receive) (xdrs type) (do ((element-type (cadr type)) (list nil (cons (xdr_receive xdrs element-type) list))) ((null (xdr_receive xdrs 'boole)) (nreverse list)))) (defun xdr_typedef (type definition) (when (record-xdr-source type) (setf (get type 'xdr_typedef) definition) (setf (get type 'xdr-transmit) 'typedef-xdr-transmit) (setf (get type 'xdr-receive) 'typedef-xdr-receive) type)) (defun typedef-xdr-transmit (xdrs object type) (xdr_transmit xdrs object (get type 'xdr_typedef))) (defun typedef-xdr-receive (xdrs type) (xdr_receive xdrs (get type 'xdr_typedef))) (defun record-xdr-source (type) #+LMI (si:record-source-file-name type 'xdr) #-LMI t) (xdr_enumeration 'boole '((nil 0) (t 1)))