
(defun custom-read-line (stream &key (max 512))
  (let ((line (make-array max
			  :element-type 'character
			  :adjustable t
			  :fill-pointer 0)))
    (flet ((add-char (c)
	     (declare (type character c))
	     (vector-push c line))
	   (finalize-line ()
	     (let ((len (length line)))
	       (when (and (> len 0)
			  (char= #\Return (aref line (1- len))))
		 (vector-pop line)))
	     line))
      (loop
	  do
	   (let (
		 ;; No way to determine invalid octet values with old ECL,
		 ;; Return an unknown character code
		 (c #+old-ecl(handler-case
			     (read-char stream)
			   (simple-error ()
			     #\UFFFD))
		    ;; SBCL provides invalid octets which we can import and
		    ;; then issue an ATTEMPT-RESYNC restart to resume
		    #+sbcl(handler-bind
			      ((sb-int:stream-decoding-error
				#'(lambda (e)
				    ;; Treat invalid UTF-8 octets as
				    ;; ISO-8859 characters.
				    (mapcar #'(lambda (c)
						(when (> c 127)
						  (add-char (code-char c))))
					    (sb-int:character-decoding-error-octets e))
				    (invoke-restart 'sb-int:attempt-resync))))
			    (read-char stream))
		    ;; Test with new ECL
		    #+ecl(handler-bind
			     ((si::stream-decoding-error ; Internal
			       #'(lambda (e)
				   (mapcar #'(lambda (c)
					       (format t "~%~A~%" c)
					       (when (> c 127)
						 ;; Never happens
						 (add-char (code-char c))))
					   ;; Not advertized interface?
					   (si:character-decoding-error-octets e))
				   ;; No restart function?
				   ;; USE-VALUE not found, ATTEMPT-RESYNC
				   ;; either...
				   ;(invoke-restart 'si:use-value #\?)
				   )))
			   (read-char stream)))
		 )
	     (when (char= #\Newline c)
	       (return (values (finalize-line) t)))
	     (add-char c))))))

(defun test ()
  (with-open-file (stream "/tmp/InvalidUTF8.txt")
    (loop
       do
	 (let ((line (handler-case
			 (custom-read-line stream)
		       (end-of-file ()
			 (loop-finish)))))
	   (format t "~A~%" line)))))
