anchor.diff:               (t (report-unknown-escape terminal)))))
     nil)
   
  -(defun xterm-saw-bracket-question (terminal byte)
  +(defun adjust-dec-private-mode (terminal mode value)
  +  "Set a DEC private mode. '<Esc>[?Pn;Pm...h' or '<Esc>[?Pn;Pm...l'"
  +  (case mode
  +    (1 ;; DECCKM.
  +     ;; Send application sequences to the host when set, ANSI cursor sequences when reset.
  +     )
  +    (3 ;; DECCOLM.
  +     ;; Select 132 (true) or 80 (false) columns per page.
  +     ;; Don't care about the value now, because there's no way to resize.
  +     ;; Changing DECCOLM resets the scrolling margins, erases all data in page memory,
  +     ;; resets the vertical split mode (DECLRMM) to unavailable,
  +     ;; and clears data from the status line if set to host-writable.
  +     (setf (scroll-start terminal) 0
  +           (scroll-end terminal) nil)
  +     (clear terminal 0 (terminal-height terminal)))
  +    (4 ;; DECSCLM. Select scrolling mode.
  +     ;; Smooth scrolling (true, default) or jump scrolling (false).
  +     )
  +    (12 ;; att610. Start/stop blinking cursor.
  +     )
  +    (25 ;; DECTCEM. Show/hide cursor.
  +     )
  +    (1049 ;; Save or restore cursor & switch screens.
  +     (cond (value
  +            ;; Save the cursor. Switch to the alternate screen and clear it.
  +            (save-cursor terminal))
  +           (t ;; Restore the cursor and switch to the normal screen.
  +            (restore-cursor terminal))))
  +    (t (format t "Unsupported DEC private mode ~D.~%" mode))))
  +
  +(defun xterm-saw-bracket-exclaim (terminal char)
  +  "Saw '<Esc>[!'"
  +  (case char
  +    (#\p ; DECSTR.
  +     (soft-reset terminal))
  +    (t (report-unknown-escape terminal)))
  +  nil)
  +
  +(defun xterm-saw-bracket-question (terminal char)
     "Saw '<Esc>[?'"
  -  (cond ((eql (code-char byte) #\;)
  +  (cond ((eql char #\;)
            (cond ((slot-value terminal 'current-number)
                   (push (slot-value terminal 'current-number) (slot-value terminal 'parameters))
                   (setf (slot-value terminal 'current-number) nil))
                  (t (push 0 (slot-value terminal 'parameters))))
            'xterm-saw-bracket-question)
  -        ((digit-char-p (code-char byte))
  +        ((digit-char-p char)
            (unless (slot-value terminal 'current-number)
              (setf (slot-value terminal 'current-number) 0))
            (setf (slot-value terminal 'current-number) (+ (* (slot-value terminal 'current-number) 10)
  -                                                      (- byte (char-code #\0))))
  +                                                      (- (char-code char) (char-code #\0))))
            'xterm-saw-bracket-question)
           (t (when (slot-value terminal 'current-number)
                (push (slot-value terminal 'current-number) (slot-value terminal 'parameters))
                (setf (slot-value terminal 'current-number) nil))
  -           (case (code-char byte)
  -             (#\h) ; DEC private mode set **
  -             (#\l) ; DEC private mode clear **
  +           (case char
  +             (#\h
  +              (dolist (p (nreverse (slot-value terminal 'parameters)))
  +                (adjust-dec-private-mode terminal p t)))
  +             (#\l
  +              (dolist (p (nreverse (slot-value terminal 'parameters)))
  +                (adjust-dec-private-mode terminal p nil)))
                (t (report-unknown-escape terminal)))
              nil)))
   
  -(defun xterm-saw-close-bracket (terminal byte)
  -  "Saw '<Esc>('/OSC."
  -  (report-unknown-escape terminal)
  +(defun xterm-saw-close-bracket (terminal char)
  +  "Saw '<Esc>]'/OSC and maybe some digits and semicolons."
  +  (cond ((eql char #\;)
  +         (cond ((slot-value terminal 'current-number)
  +                (push (slot-value terminal 'current-number) (slot-value terminal 'parameters))
  +                (setf (slot-value terminal 'current-number) nil))
  +               (t (push 0 (slot-value terminal 'parameters))))
  +         (return-from xterm-saw-close-bracket 'xterm-saw-close-bracket))
  +        ((digit-char-p char)
  +         (unless (slot-value terminal 'current-number)
  +           (setf (slot-value terminal 'current-number) 0))
  +         (setf (slot-value terminal 'current-number) (+ (* (slot-value terminal 'current-number) 10)
  +                                                        (- (char-code char) (char-code #\0))))
  +         (return-from xterm-saw-close-bracket 'xterm-saw-close-bracket))
  +        (t (report-unknown-escape terminal)))
     nil)
   
  -(defun xterm-saw-paren (terminal byte)
  +(defun xterm-saw-paren (terminal char)
     "Saw '<Esc>(', expecting a character set identifier."
     ;; Set G0 character set.
  -  (case (code-char byte)
  -    (#\B (setf (charset terminal) :usascii))
  +  (case char
  +    (#\B (setf (charset terminal) :us-ascii))
       (#\0 (setf (charset terminal) :dec))
  -    (t (setf (charset terminal) :usascii)
  +    (t (setf (charset terminal) :us-ascii)
          (report-unknown-escape terminal)))
     nil)
   
  -(defun xterm-saw-close-paren (terminal byte)
  +(defun xterm-saw-close-paren (terminal char)
     "Saw '<Esc>)', expecting a character set identifier."
     ;; Set G1 character set.
  -  (case (code-char byte)
  -    (#\B #+nil(setf (charset terminal) :usascii))
  +  (case char
  +    (#\B #+nil(setf (charset terminal) :us-ascii))
       (#\0 #+nil(setf (charset terminal) :dec))
  -    (t #+nil(setf (charset terminal) :usascii)
  +    (t #+nil(setf (charset terminal) :us-ascii)
          (report-unknown-escape terminal)))
     nil)
   
  -(defmethod sys.gray:stream-write-byte ((stream xterm-terminal) byte)
  -  (push byte (slot-value stream 'escape-sequence))
  -  (let ((new-state (funcall (terminal-state stream) stream byte)))
  -    (cond (new-state
  -           (setf (terminal-state stream) new-state))
  -          (t (setf (terminal-state stream) 'xterm-initial
  -                   (slot-value stream 'current-number) nil
  -                   (slot-value stream 'parameters) '()
  -                   (slot-value stream 'escape-sequence) '())))))
  +(defun utf-8-code-point-length (code-point)
  +  "Return the number of bytes required to encode CODE-POINT or NIL if it can't be encoded."
  +  (cond ((<= code-point #x7F)
  +         1)
  +        ((<= #x80 code-point #x7FF)
  +         2)
  +        ;; UTF-16 surrogates can't be encoded.
  +        ((or (<= #x800 code-point #xD7FF)
  +             (<= #xE000 code-point #xFFFF))
  +         3)
  +        ((<= #x10000 code-point #x10FFFF)
  +         4)))
  +
  +(defmethod sys.gray:stream-write-byte ((terminal xterm-terminal) byte)
  +  (with-simple-restart (continue "Ignore this byte.")
  +    (cond ((utf-8-state terminal)
  +           ;; Some bytes to go.
  +           ;; Each remaining byte must have the top two bits set to #b10.
  +           (when (not (eql (ldb (byte 2 6) byte) #b10))
  +             (write-char #\REPLACEMENT_CHARACTER terminal)
  +             ;; Restart decode from this byte.
  +             (setf (utf-8-state terminal) nil)
  +             (return-from sys.gray:stream-write-byte
  +               (sys.gray:stream-write-char terminal byte)))
  +           (setf (utf-8-accumulator terminal) (logior (ash (utf-8-accumulator terminal) 6)
  +                                                      (ldb (byte 6 0) byte)))
  +           (when (zerop (decf (utf-8-state terminal)))
  +             ;; Finish up.
  +             (let ((code-point (utf-8-accumulator terminal)))
  +               (if (or (> code-point #x0010FFFF)
  +                       (<= #xD800 code-point #xDFFF)
  +                       (not (eql (utf-8-length terminal)
  +                                 (utf-8-code-point-length code-point))))
  +                   (write-char #\REPLACEMENT_CHARACTER terminal)
  +                   (write-char (code-char code-point) terminal)))
  +             (setf (utf-8-state terminal) nil)))
  +          (t ;; Starting a UTF-8 sequence.
  +           (multiple-value-bind (remaining-bytes partial-code-point)
  +               (sys.net::utf-8-decode-leader byte)
  +             (case remaining-bytes
  +               (0 (write-char (code-char partial-code-point) terminal))
  +               ((1 2 3)
  +                (setf (utf-8-state terminal) remaining-bytes
  +                      (utf-8-length terminal) (1+ remaining-bytes)
  +                      (utf-8-accumulator terminal) partial-code-point))
  +               (t (write-char #\REPLACEMENT_CHARACTER terminal))))))))
  +
  +(defmethod sys.gray:stream-write-char ((stream xterm-terminal) char)
  +  (push char (slot-value stream 'escape-sequence))
  +  (with-simple-restart (continue "Ignore this character.")
  +    (let ((new-state (funcall (terminal-state stream) stream char)))
  +      (cond (new-state
  +             (setf (terminal-state stream) new-state))
  +            (t (setf (terminal-state stream) 'xterm-initial
  +                     (slot-value stream 'current-number) nil
  +                     (slot-value stream 'parameters) '()
  +                     (slot-value stream 'escape-sequence) '()))))))
   
   (defvar *xterm-translations*
     (list (list (name-char "Up-Arrow")    '(#\Esc #\[ #\A))
  
positive.code:    (underline :initarg :underline :accessor underline)
     (character-set :initarg :charset :accessor charset)
     (saved-x :initform 0 :accessor saved-x)
     (saved-y :initform 0 :accessor saved-y))
    (:default-initargs
     :interrupt-character nil
     :queued-bytes '()
  
negative.code:    :bold nil
     :inverse nil
     :underline nil
     :charset :us-ascii
     :scroll-start 0
     :scroll-end nil
     :x 0 :y 0))
  
  (defun soft-reset (terminal)
    "Reset the terminal to the default state."
    (setf (autowrap terminal) nil))
  
  (defmethod sys.gray:stream-element-type ((stream xterm-terminal))
    '(unsigned-byte 8))
  