mirror of
https://github.com/PDP-10/its.git
synced 2026-05-02 14:30:41 +00:00
Added lots of new LSPLIB packages (and their sources).
This commit is contained in:
345
src/libdoc/lchstr.jlk25
Normal file
345
src/libdoc/lchstr.jlk25
Normal file
@@ -0,0 +1,345 @@
|
||||
;;; Chaosnet Streams for Maclisp
|
||||
|
||||
;;; todo: variable byte sizes for IN & OUT
|
||||
;;; improve efficiency of ARRAY-IN, ARRAY-OUT
|
||||
;;; make LSN's work
|
||||
;;; flush sfa-get/store in favor of SETF and ...?
|
||||
|
||||
;;; To generate a Chaosnet stream do (MAKE-CHAOSNET-STREAM). Then do
|
||||
;;; (OPEN <stream> '(HOST <host-address> CONTACT <contact-name>)).
|
||||
;;; Then use standard operations like TYI, UNTYI, TYO, IN, OUT, CLOSE, etc
|
||||
;;; or non-standard operations PACKET-IN, PACKET-OUT, ARRAY-IN, ARRAY-OUT
|
||||
;;; More documentation can be found before each operation handler (e.g. OPEN).
|
||||
|
||||
;;; Note: If you want reasonable error handling when running in a bare
|
||||
;;; LISP, you need a package like the one in MACSYMA (LIBMAX;MDEBUG >).
|
||||
|
||||
;;; Standard compile-time environment
|
||||
(include |dsk:libmax;gprelud >|)
|
||||
|
||||
(herald lchstr)
|
||||
|
||||
(eval-when (compile) (setq defmacro-for-compiling nil))
|
||||
|
||||
(eval-when (eval compile)
|
||||
(if (not (fboundp 'loop)) (load "dsk:liblsp;loop fasl")))
|
||||
|
||||
;;; Load the Chaosnet support package, if not already loaded
|
||||
(eval-when (load eval)
|
||||
(or (get 'lchnsp 'version) (load "dsk:lisp;lchnsp fasl")))
|
||||
|
||||
(defvar chaos-stream-id 0)
|
||||
(defvar default-window-size 10.)
|
||||
(defvar default-timeout 60.)
|
||||
|
||||
;;; See the file L;LCHNSP > for the %chaos routines
|
||||
|
||||
(declare (special chaos-internal-pkt-buffer)
|
||||
(*expr %chaos-open-channels %chaos-close-channels
|
||||
%chaos-request-connection %chaos-eof %chaos-allocate-buffer
|
||||
%chaos-pktiot %chaos-get-byte %chaos-put-byte
|
||||
%chaos-set-pkt-length %chaos-set-pkt-opcode
|
||||
%chaos-get-pkt-length %chaos-get-pkt-opcode))
|
||||
|
||||
;;; Compile time constants
|
||||
|
||||
(eval-when (eval compile)
|
||||
;;; Connection state symbols
|
||||
(setq %cscls 0 %csrfs 3 %csopn 4 %cslos 5 %csinc 6
|
||||
;;; Packet Opcode definitions
|
||||
%codat 200 %coeof 14 %cocls 3
|
||||
;;; Other constants
|
||||
max-connect-tries 5
|
||||
max-pkt-size-bytes 488.)
|
||||
;;; Stream slot indices (should be done as a structure, but sfa's don't win...)
|
||||
(let ((slot-index 0)) ;crock...
|
||||
(mapc #'(lambda(slot) (set slot (setq slot-index (1+ slot-index))))
|
||||
'(connection host-address contact-name request-or-listen
|
||||
byte-size window-size timeout
|
||||
untyi-list in-buffer out-buffer in-count out-count
|
||||
max-chaosnet-stream-slot)))) ;this must be last
|
||||
|
||||
;;; Generate a bare chaosnet-stream object
|
||||
(defun make-chaosnet-stream ()
|
||||
(let ((stream (sfa-create #'chaosnet-stream-function
|
||||
#.max-chaosnet-stream-slot
|
||||
(format nil "chaos-stream-object-~A"
|
||||
(setq chaos-stream-id (1+ chaos-stream-id))))))
|
||||
(sfa-store stream #.host-address nil)
|
||||
(sfa-store stream #.contact-name nil)
|
||||
(sfa-store stream #.request-or-listen t) ;default to RFC
|
||||
(sfa-store stream #.byte-size 8)
|
||||
(sfa-store stream #.window-size default-window-size)
|
||||
(sfa-store stream #.timeout default-timeout)
|
||||
(sfa-store stream #.in-count -1)
|
||||
(sfa-store stream #.out-count 0)
|
||||
(sfa-store stream #.in-buffer (%chaos-allocate-buffer))
|
||||
(sfa-store stream #.out-buffer (%chaos-allocate-buffer))
|
||||
stream))
|
||||
|
||||
;;; chaosnet-stream-function is at the end of the file because it depends on
|
||||
;;; the following macros.
|
||||
|
||||
|
||||
;;; These macros are only to be expanded inside chaosnet-stream-function
|
||||
|
||||
;;; OPEN msg handler. Format is (OPEN <stream> <option-list>) where
|
||||
;;; <stream> is a chaosnet stream as returned by (MAKE-CHAOSNET-STREAM) and
|
||||
;;; <option-list> is a list of keywords and values (keywd1 val1 keywd2 val2 ..)
|
||||
;;; Known options are: HOST (or ADDRESS or HOST-ADDRESS) - Chaosnet host addr
|
||||
;;; CONTACT-NAME (or CONTACT or NAME) - Contact name + JCL
|
||||
;;; REQUEST or LISTEN - same as CONTACT
|
||||
;;; BYTE-SIZE (or BYTE) - byte size (8)
|
||||
;;; WINDOW-SIZE (or WINDOW) - xmt window size
|
||||
;;; Note: HOST-ADDRESS and CONTACT-NAME are required.
|
||||
;;; [Should OPEN errors here be signaled in a special way to be compatible?]
|
||||
|
||||
;;; Map keywords into slot indices with an occassional side-effect.
|
||||
(defmacro chaosnet-stream-keyword-decode (stream keyword)
|
||||
`(caseq ,keyword
|
||||
((host address host-address host-number)
|
||||
#.host-address)
|
||||
((contact name contact-name request)
|
||||
(sfa-store ,stream #.request-or-listen T)
|
||||
#.contact-name)
|
||||
(listen
|
||||
(sfa-store ,stream #.request-or-listen NIL)
|
||||
#.contact-name)
|
||||
((byte byte-size) #.byte-size)
|
||||
((window window-size) #.window-size)
|
||||
(timeout #.timeout)
|
||||
(T (ferror nil "Unknown keyword in OPEN for ~A - ~A"
|
||||
,stream keyword))))
|
||||
|
||||
(defmacro chaosnet-stream-open (stream args)
|
||||
`(progn
|
||||
(loop for (keyword value) on ,args by #'cddr
|
||||
for index = (chaosnet-stream-keyword-decode ,stream keyword)
|
||||
do (sfa-store ,stream index value))
|
||||
(sfa-call ,stream 'close nil) ;make sure its closed
|
||||
(if (null (sfa-get ,stream #.host-address))
|
||||
(ferror nil
|
||||
"Error handling OPEN for ~A: No host address specified."
|
||||
,stream))
|
||||
(if (null (sfa-get ,stream #.contact-name))
|
||||
(ferror nil
|
||||
"Error handling OPEN for ~A: No contact name specified."
|
||||
,stream))
|
||||
(if (null (sfa-get ,stream #.connection)) ;create a connection,
|
||||
(sfa-store ,stream #.connection ;if needed
|
||||
(%chaos-open-channels (sfa-get ,stream #.window-size))))
|
||||
(loop ;repeat #.max-connect-tries ; would be nicer...
|
||||
for connect-tries from 1 to #.max-connect-tries and
|
||||
state =
|
||||
(*catch 'chaos-pktiot-error ;catch IOC errors
|
||||
(%chaos-request-connection
|
||||
(sfa-get ,stream #.connection)
|
||||
(sfa-get ,stream #.host-address)
|
||||
(sfa-get ,stream #.contact-name)
|
||||
(sfa-get ,stream #.request-or-listen)
|
||||
(sfa-get ,stream #.timeout)))
|
||||
until (= #.%csopn state)
|
||||
finally
|
||||
(if (not (= #.%csopn state))
|
||||
(error (get-chaosnet-error-msg ,stream)
|
||||
"some error from chaos site")))
|
||||
(sfa-call ,stream 'clear-input nil)
|
||||
(sfa-call ,stream 'clear-output nil)
|
||||
,stream))
|
||||
|
||||
;;; CLOSE msg handler. Shuts down the connection and frees up the channels.
|
||||
|
||||
(defmacro chaosnet-stream-close (stream)
|
||||
`(let ((conn (sfa-get ,stream #.connection)))
|
||||
(sfa-store ,stream #.connection nil)
|
||||
(unless (null conn)
|
||||
(*catch 'chaos-pktiot-error (%chaos-eof conn))
|
||||
(%chaos-close-channels conn))))
|
||||
|
||||
;;; Standard stream operations
|
||||
|
||||
;;; Define a wrapper to catch IOC errors and handle them nicely
|
||||
(defmacro chaosnet-op (stream &rest body)
|
||||
`(if (null (*catch 'chaos-pktiot-error ,@ body))
|
||||
(error (get-chaosnet-error-msg ,stream) "some error from chaos site"
|
||||
'fail-act
|
||||
)))
|
||||
|
||||
;;; TYI and TYO ignore BYTE-SIZE and always return/take 8-bit bytes.
|
||||
;;; UNTYI can take anything (and TYI after UNTYI will return anything).
|
||||
|
||||
(defmacro chaosnet-stream-tyi (stream eof)
|
||||
`(let ((utl (sfa-get ,stream #.untyi-list)))
|
||||
(if utl (prog1 (car utl) (sfa-store ,stream #.untyi-list (cdr utl)))
|
||||
(let ((ibuf (sfa-get ,stream #.in-buffer))
|
||||
(cnt (sfa-get ,stream #.in-count)))
|
||||
(when (<= cnt 0)
|
||||
(chaosnet-op ,stream
|
||||
(%chaos-pktiot
|
||||
(car (sfa-get ,stream #.connection))
|
||||
ibuf))
|
||||
(sfa-store ,stream #.in-count
|
||||
(setq cnt (%chaos-get-pkt-length ibuf))))
|
||||
(cond ((= #.%coeof (%chaos-get-pkt-opcode ibuf))
|
||||
(sfa-call ,stream 'clear-input nil)
|
||||
,eof)
|
||||
((= #.%cocls (%chaos-get-pkt-opcode ibuf))
|
||||
(error (get-chaosnet-error-msg ,stream T))) ;cls-flag
|
||||
((= 0 cnt) (sfa-call ,stream 'tyi ,eof))
|
||||
(T (sfa-store ,stream #.in-count (1- cnt))
|
||||
(%chaos-get-byte
|
||||
ibuf
|
||||
(- (%chaos-get-pkt-length ibuf) cnt))))))))
|
||||
|
||||
(defmacro chaosnet-stream-untyi (stream byte)
|
||||
`(sfa-store ,stream #.untyi-list
|
||||
(push ,byte (sfa-get ,stream #.untyi-list))))
|
||||
|
||||
(defmacro chaosnet-stream-tyo (stream byte)
|
||||
`(let ((cnt (sfa-get ,stream #.out-count)))
|
||||
(%chaos-put-byte (sfa-get ,stream #.out-buffer) ,byte)
|
||||
(setq cnt (1+ cnt))
|
||||
(if (> cnt #.(1- max-pkt-size-bytes)) (sfa-call ,stream 'force-output
|
||||
nil)
|
||||
(sfa-store ,stream #.out-count cnt))
|
||||
T))
|
||||
|
||||
;;; what should IN and OUT do? (pack arbitrary byte sizes into 16 bit words?)
|
||||
|
||||
(defmacro chaosnet-stream-in (stream eof)
|
||||
`(sfa-call ,stream 'tyi ,eof)) ;should do something better..
|
||||
|
||||
(defmacro chaosnet-stream-out (stream word)
|
||||
`(sfa-call ,stream 'tyo ,word))
|
||||
|
||||
(defmacro chaosnet-stream-force-output (stream)
|
||||
`(when (> (sfa-get ,stream #.out-count) 0)
|
||||
(chaosnet-op ,stream
|
||||
(%chaos-pktiot (cdr (sfa-get ,stream #.connection))
|
||||
(sfa-get ,stream #.out-buffer)))
|
||||
(sfa-call ,stream 'clear-output nil)))
|
||||
|
||||
(defmacro chaosnet-stream-clear-input (stream)
|
||||
`(loop with ary = chaos-internal-pkt-buffer and
|
||||
ichan = (car (sfa-get ,stream #.connection))
|
||||
for count = (lsh (nth 2 (syscall 3 'whyint ichan)) -18.)
|
||||
while (and (> count 0)
|
||||
(*catch 'chaos-pktiot-error (%chaos-pktiot ichan ary)))
|
||||
finally (sfa-store ,stream #.in-count -1) ;no packet
|
||||
(sfa-store ,stream #.untyi-list nil)
|
||||
(return T)))
|
||||
|
||||
(defmacro chaosnet-stream-clear-output (stream)
|
||||
`(let ((obuf (sfa-get ,stream #.out-buffer)))
|
||||
(sfa-store ,stream #.out-count 0)
|
||||
(%chaos-set-pkt-length obuf 0)
|
||||
(%chaos-set-pkt-opcode obuf #.%codat))) ;data opcode
|
||||
|
||||
;;; Non-standard stream operations
|
||||
|
||||
;;; Input a packet into an array
|
||||
(defmacro chaosnet-stream-packet-in (stream array)
|
||||
`(let ((ibuf (sfa-get ,stream #.in-buffer)))
|
||||
(chaosnet-op ,stream
|
||||
(%chaos-pktiot (car (sfa-get ,stream #.connection))
|
||||
ibuf)
|
||||
(fillarray ,array ibuf))
|
||||
T))
|
||||
|
||||
(defmacro chaosnet-stream-packet-out (stream array)
|
||||
`(let ((obuf (sfa-get ,stream #.out-buffer)))
|
||||
(chaosnet-op ,stream
|
||||
(fillarray obuf ,array) ;how big is obuf?
|
||||
(%chaos-pktiot (cdr (sfa-get ,stream #.connection))
|
||||
obuf))))
|
||||
|
||||
;;; These should probably be made more efficient someday...
|
||||
|
||||
(defmacro chaosnet-stream-array-in (stream array count)
|
||||
`(progn
|
||||
(dotimes (i ,count)
|
||||
(setf (arraycall fixnum ,array i) (sfa-call ,stream 'tyi 0)))
|
||||
T))
|
||||
|
||||
(defmacro chaosnet-stream-array-out (stream array count)
|
||||
`(progn
|
||||
(dotimes (i ,count)
|
||||
(sfa-call ,stream 'out (arraycall fixnum ,array i)))
|
||||
T))
|
||||
|
||||
(defmacro chaosnet-stream-eof (stream msg) ;hack the msg someday
|
||||
`(progn (sfa-call ,stream 'force-output nil)
|
||||
(chaosnet-op ,stream (%chaos-eof (sfa-get ,stream #.connection)))
|
||||
(sfa-call ,stream 'clear-output nil)))
|
||||
|
||||
;;; Dispatching function for Chaosnet streams
|
||||
(declare (*lexpr get-chaosnet-error-msg))
|
||||
|
||||
(defun chaosnet-stream-function (stream msg arg)
|
||||
(caseq msg
|
||||
(which-operations '(open close untyi tyi tyo in out force-output eof
|
||||
clear-input clear-output
|
||||
packet-in packet-out
|
||||
array-in array-out))
|
||||
;standard operations
|
||||
(open (chaosnet-stream-open stream arg))
|
||||
(close (chaosnet-stream-close stream))
|
||||
(untyi (chaosnet-stream-untyi stream arg))
|
||||
(tyi (chaosnet-stream-tyi stream arg))
|
||||
(tyo (chaosnet-stream-tyo stream arg))
|
||||
(in (chaosnet-stream-in stream arg))
|
||||
(out (chaosnet-stream-out stream arg))
|
||||
(force-output (chaosnet-stream-force-output stream))
|
||||
(clear-input (chaosnet-stream-clear-input stream))
|
||||
(clear-output (chaosnet-stream-clear-output stream))
|
||||
;non-standard operations
|
||||
(packet-in (chaosnet-stream-packet-in stream arg))
|
||||
(packet-out (chaosnet-stream-packet-out stream arg))
|
||||
(array-in (chaosnet-stream-array-in stream (car arg) (cadr arg)))
|
||||
(array-out (chaosnet-stream-array-out stream (car arg) (cadr arg)))
|
||||
(eof (chaosnet-stream-eof stream arg))
|
||||
(T (ferror nil "Unknown stream operation - ~A" msg))))
|
||||
|
||||
;;; Function forms of non-standard stream operations
|
||||
|
||||
;;; packet-in/out reads/writes a packet to/from a fixnum array
|
||||
;;; data is packed 32-bit to a word, left adjusted.
|
||||
|
||||
(defun packet-in (stream array)
|
||||
(sfa-call stream 'packet-in array))
|
||||
|
||||
(defun packet-out (stream array)
|
||||
(sfa-call stream 'packet-out array))
|
||||
|
||||
;;; Engorge or disgorge <n> numbers into or out of an array.
|
||||
;;; Packing is either 8,16, or 32 bit, depending on the mode of the OPEN.
|
||||
|
||||
(defun array-in (stream array count)
|
||||
(sfa-call stream 'array-in (list array count)))
|
||||
|
||||
(defun array-out (stream array count)
|
||||
(sfa-call stream 'array-out (list array count)))
|
||||
|
||||
;;; Read and stringify a message about why a connection is losing
|
||||
|
||||
(defun get-chaosnet-error-msg (stream &optional (cls-flag nil)
|
||||
&aux (ichan (car (sfa-get stream #.connection)))
|
||||
(ary (sfa-get stream #.in-buffer)))
|
||||
(let ((count (lsh (nth 2 (syscall 3 'whyint ichan)) -18.)))
|
||||
(if (not (or cls-flag
|
||||
(and (> count 0)
|
||||
(*catch 'chaos-pktiot-error (%chaos-pktiot ichan ary)))))
|
||||
"Chaosnet Lossage - cause undetermined."
|
||||
(maknam (loop for i from 4
|
||||
for word = (arraycall fixnum ary i)
|
||||
until (= 0 word)
|
||||
collect (load-byte word 28. 8)
|
||||
collect (load-byte word 20. 8)
|
||||
collect (load-byte word 12. 8)
|
||||
collect (load-byte word 4. 8))))))
|
||||
|
||||
|
||||
;; Local Modes:
|
||||
;; Mode: LISP
|
||||
;; Comment Col:40
|
||||
;; END:
|
||||
Reference in New Issue
Block a user