;;; Copyright (c) 1993, 1994 by Olin Shivers.
;;; #! comment read-macro
;;; no case-folding
;;; -flag is a symbol

;;; #! means: skip chars until newline-bang-splat-newline. 
;;; For Unix script headers.

(define script-skip
  (lambda (c port)
    (read-char port)
    (let lp ((state 0))
      (let ((advance-if (lambda (look-for)
			  (let ((c (read-char port)))
			    (if (eof-object? c)
				(error 
			 "EOF inside block comment -- #! missing a closing !#")
				(lp (cond ((char=? c look-for) (+ state 1))
					  ((char=? c #\newline) 1)
					  (else 0))))))))
	(case state
	  ((0) (advance-if #\newline))
	  ((1) (advance-if #\!))	; Found \n
	  ((2) (advance-if #\#))	; Found \n!
	  ((3) (advance-if #\newline))	; Found \n!#
	  ((4) (read port)))))))	; Found \n!#\n -- done.
;         was sub-read ^

(define-sharp-macro #\! script-skip)


;;; Readme and readme are distinct symbols.

(define preferred-case (lambda (x) x))

;;; These are now OK symbols: .. -geometry -O2 9x15 80x5+5+5 +Wn

(define (parse-token string port)
  (if (let ((c (string-ref string 0)))
	(or (char-numeric? c) (char=? c #\+) (char=? c #\-) (char=? c #\.)))
      (cond ((string->number string))
	    ((string=? string ".") dot)
	    (else (string->symbol string)))
      (string->symbol string)))


;;; | is now an OK symbol (for pipes).

(set-standard-syntax! #\| #f
		      (lambda (c port)
			(parse-token (sub-read-token c port) port)))

(define bel (ascii->char 7))
(define bs  (ascii->char  8))
(define ff  (ascii->char 12))
(define cr  (ascii->char 13))
(define ht  (ascii->char  9))
(define vt  (ascii->char 11))

;;; Full ANSI C strings:
;;; - read as themselves: \\ \? \" \'
;;; - control chars:
;;;   \a alert (bell -- ^g)
;;;   \b backspace (^h)
;;;   \f form feed (^l)
;;;   \n newline (^j)
;;;   \r carriage return (^m)
;;;   \t tab (^i)
;;;   \v vertical tab (^k)
;;; - octal escapes \nnn
;;; - hex escapes \xnn

;;; Is this the elegant thing to do? Too much might make it hard to shift
;;; to Unicode implementations. How about \^g for embedding control chars?
;;; And I haven't done anything about chars (as opposed to strings).

(set-standard-read-macro! #\" #t
  (lambda (c port)
    c ;ignored
    (let* ((readc (lambda ()
		    (let ((c (read-char port)))
		      (if (eof-object? c)
			  (reading-error port "end of file within a string")
			  c))))
	   (read-digit (lambda (base base-name)
			 (let* ((c (readc))
				(d (- (char->ascii c) (char->ascii #\0))))
			   (if (and (<= 0 d) (< d base)) d
			       (reading-error port
					      (string-append "invalid "
							     base-name
							     " code in string.")
					      d))))))

      (let loop ((l '()) (i 0))
	(let ((c (readc)))
	  (cond ((char=? c #\\)
		 (let* ((c (readc))
			(rc (case c
			      ((#\\ #\" #\? #\') c)
			      ((#\a) bel)
			      ((#\b) bs)
			      ((#\f) ff)
			      ((#\n) #\newline)
			      ((#\r) cr)
			      ((#\t) ht)
			      ((#\v) vt)
			      ((#\0 #\1 #\2 #\3)
			       (let* ((d1 (- (char->ascii c) (char->ascii #\0)))
				      (d2 (read-digit 8 "octal"))
				      (d3 (read-digit 8 "octal")))
				 (ascii->char (+ (* 64 d1) (+ (* 8 d2) d3)))))
			      ((#\x)
			       (let ((d1 (read-digit 16 "hex"))
				     (d2 (read-digit 16 "hex")))
				 (ascii->char (+ (* 16 d1) d2))))
			      (else
			       (reading-error port
					      "invalid escaped character in string"
					      c)))))
		   (loop (cons rc l) (+ i 1))))
		((char=? c #\")
		 (reverse-list->string l i))
		(else
		 (loop (cons c l) (+ i 1)))))))))
