;;;-*- Mode:LISP; Package:USER; Fonts:(CPTFONT TR12I); Base:8; Readtable:ZL -*-

;1;;This defines new reader syntax for ASCII hacking.*

;1;; *#1 allows entry of ASCII printing characters, like *#/1 does for Lisp Machine characters.*
;1;; *#1 allows entry of ASCII control, etc. characters, like *#\1 does for Lisp Machine characters.*
;1;; All the usual names for ASCII characters are accepted, both in long form and in the standard*
;1;; two and three letter abbreviations.*
;1;; The form *Control-X1 is also accepted, where the *X1 is any letter or the characters @[\]^_ .*

(set-syntax-/#-macro-char #/ 'ascii-char-fixnum)
(set-syntax-/#-macro-char #/ 'ascii-control-char-fixnum)

(defvar ascii-sail-translation-table (make-array 32.)
  "Each element is the ASCII character corresponding to a Lisp Machine character.")

(fillarray ascii-sail-translation-table
	   '(nil				;1center-dot*
	     nil				;1down arrow*
	     nil				;1alpha*
	     nil				;1beta*
	     nil				;1and-sign*
	     nil				;1not-sign*
	     nil				;1epsilon*
	     nil				;1pi*
	     nil				;1lambda*
	     nil				;1gamma*
	     nil				;1delta*
	     nil				;1uparrow*
	     nil				;1plus-minus*
	     nil				;1circle-plus*
	     nil				;1infinity*
	     nil				;1partial delta*
	     nil				;1left horseshoe*
	     nil				;1right horseshoe*
	     nil				;1up horseshoe*
	     nil				;1down horseshoe*
	     nil				;1universal quantifier*
	     nil				;1existential quantifier*
	     nil				;1circle-X*
	     nil				;1double-arrow*
	     nil				;1left arrow*
	     nil				;1right arrow*
	     nil				;1not-equals*
	     33					;1diamond (altmode)*
	     nil				;1less-or-equal*
	     nil				;1greater-or-equal*
	     nil				;1equivalence*
	     nil				;1or*
	     ))

(defvar ascii-named-char-list
	'((:Null . 0)				;1NUL (Control-@)*
	  (:NUL . 0)
	  (:Start-of-Heading . 1)		;1SOH (Control-A)*
	  (:SOH . 1)
	  (:Start-of-Text . 2)			;1STX (Control-B)*
	  (:STX . 2)
	  (:End-of-Text . 3)			;1ETX (Control-C)*
	  (:ETX . 3)
	  (:End-of-Transmission . 4)		;1EOT (Control-D)*
	  (:EOT . 4)
	  (:Enquiry . 5)			;1ENQ (Control-E)*
	  (:ENQ . 5)
	  (:Acknowledge . 6)			;1ACK` (Control-F)*
	  (:ACK . 6)
	  (:Bell . 7)				;1BEL (Control-G)*
	  (:BEL . 7)
	  (:Backspace . 10)			;1BS (Control-H)*
	  (:Overstrike . 10)
	  (:BS . 10)
	  (:Tab . 11)				;1HT (Control-I)*
	  (:Horizontal-Tabulation . 11)
	  (:HT . 11)
	  (:Line-Feed . 12)			;1LF (Control-J)*
	  (:Linefeed . 12)
	  (:Line . 12)
	  (:LF . 12)
	  (:Vertical-Tabulation . 13)		;1VT (Control-K)*
 	  (:VT . 13)
	  (:Form-Feed . 14)			;1FF (Control-L)*
	  (:Formfeed . 14)
	  (:Form . 14)
	  (:Clear-Screen . 14)
	  (:FF . 14)
	  (:Return . 15)			;1CR (Control-M)*
	  (:Carriage-Return . 15)
	  (:CR . 15)
	  (:Shift-Out . 16)			;1SO (Control-N)*
	  (:SO . 16)
	  (:Shift-In . 17)			;1SI (Control-O)*
	  (:SI . 17)
	  (:Data-Link-Escape . 20)		;1DLE (Control-P)*
	  (:DLE . 20)
	  (:Device-Control-1 . 21)		;1DC1 (Control-Q)*
	  (:DC1 . 21)
	  (:Device-Control-2 . 22)		;1DC2 (Control-R)*
	  (:DC2 . 22)
	  (:Device-Control-3 . 23)		;1DC3 (Control-S)*
	  (:DC3 . 23)
	  (:Device-Control-4 . 24)		;1DC4 (Control-T)*
	  (:DC4 . 24)
	  (:Negative-Acknowledge . 25)		;1NAK (Control-U)*
	  (:NAK . 25)
	  (:Synchronous-Idle . 26)		;1SYN (Control-V)*
	  (:SYN . 26)
	  (:End-of-Transmission-Block . 27)	;1ETB (Control-W)*
	  (:ETB . 27)
	  (:Cancel . 30)			;1CAN (Control-X)*
	  (:CAN . 30)
	  (:End-of-Medium . 31)			;1EM (Control-Y)*
	  (:EM . 31)
	  (:Substitute . 32)			;1SUB (Control-Z)*
	  (:SUB . 32)
	  (:Altmode . 33)			;1ESC (Control-[)*
	  (:Escape . 33)
	  (:ALT . 33)
	  (:ESC . 33)
	  (:File-Separator . 34)		;1FS (Control-\)*
	  (:FS . 34)
	  (:Group-Separator . 35)		;1GS (Control-])*
	  (:GS . 35)
	  (:Record-Separator . 36)		;1RS (Control-^)*
	  (:RS . 36)
	  (:Unit-Separator . 37)		;1US (Control-_)*
	  (:US . 37)
	  (:Rubout . 177)			;1DEL (Rubout)*
	  (:Delete . 177)
	  (:DEL . 177)))

;1;; Note -- this is a modified version of this function for use in Systems 94 (with patches) and later.*
;1;; It uses SI:XR-XRTYI where appropriate so everything in the reader will work correctly.*
;1;; Since this won't work in earlier systems, it just uses the TYI message in old software.*
(defun ascii-char-fixnum (ignore stream)
  (let* ((char (cond ((< (si:get-system-version) 94.) (send stream ':tyi))
		     (t (si:xr-xrtyi stream nil t))))
	 (ascii-char (cond ((< 37 char 200) char)
			   ((< char 40) (aref ascii-sail-translation-table char))
			   (t nil))))
    (when (null ascii-char)
      (cerror ':no-action nil 'sys:read-error-1 "~C is not a valid ASCII character." char))
    ascii-char))

(defun ascii-control-char-fixnum (ignore stream)
  (pkg-bind "USER"
    (let ((name (read stream)))
      (unless (typep name ':SYMBOL)
	(cerror ':no-action nil 'sys:read-error-1
		"# followed by ~A, which is not a symbol." name))
      (cond ((string-equal name "CONTROL-" :start1 0 :start2 0 :end1 8 :end2 8)
	     (when ( (string-length name) 9.)
	       (cerror ':no-action nil 'sys:read-error-1
		       "#Control- followed by ~A, which is not a single character."
		       (substring name 8.)))
	     (let ((control-char (char-upcase (aref (string name) 8.))))
	       (unless (< 77 control-char 140)
		 (cerror ':no-action nil 'sys:read-error-1
		    "#Control- followed by ~C, which is not an ASCII control character."
		    control-char))
	       (- control-char 100)))
	    (t (cdr (cond ((assq (intern-soft name "KEYWORD") ascii-named-char-list))
			  (t (cerror ':no-action nil 'sys:read-error-1
				     "#~A is not an ASCII character." name)))))))))
