+ (process-cmd-text cmd-string line cmd-args-string)))))
+
+(defun process-cmd-numeric (cmd-string cmd-args-string)
+ "Process a numeric cmd, such as ':123'"
+ (let* ((first-char (char cmd-string 0))
+ (number-string (if (digit-char-p first-char)
+ cmd-string
+ (subseq cmd-string 1)))
+ (is-minus (char= first-char #\-))
+ (raw-number (read-from-string number-string))
+ (number (if is-minus
+ (- *cmd-number* raw-number)
+ raw-number))
+ (cmd (get-history number)))
+ (when (eq cmd *null-cmd*)
+ (return-from process-cmd-numeric
+ (make-user-cmd :func :history-error :input (read-from-string
+ cmd-string))))
+ (maybe-return-history-cmd cmd cmd-args-string)))
+
+(defun maybe-return-history-cmd (cmd cmd-args-string)
+ (format *output* "~A~%" (user-cmd-input cmd))
+ (let ((dont-redo
+ (when (and (stringp cmd-args-string)
+ (plusp (length cmd-args-string))
+ (char= #\? (char cmd-args-string 0)))
+ (do ((line nil (read-line *input*)))
+ ((and line (or (zerop (length line))
+ (string-equal line "Y")
+ (string-equal line "N")))
+ (when (string-equal line "N")
+ t))
+ (when line
+ (format *output* "Type \"y\" for yes or \"n\" for no.~%"))
+ (format *output* "redo? [y] ")
+ (force-output *output*)))))
+ (if dont-redo
+ *null-cmd*
+ (make-user-cmd :func (user-cmd-func cmd)
+ :input (user-cmd-input cmd)
+ :args (user-cmd-args cmd)
+ :hnum *cmd-number*))))
+
+
+(defun find-history-matching-pattern (cmd-string)
+ "Return history item matching cmd-string or NIL if not found"
+ (dolist (his *history* nil)
+ (let* ((input (user-cmd-input his))
+ (string-input (if (stringp input)
+ input
+ (write-to-string input))))
+ (when (search cmd-string string-input :test #'string-equal)
+ (return-from find-history-matching-pattern his)))))
+
+(defun process-history-search (pattern cmd-args-string)
+ (let ((cmd (find-history-matching-pattern pattern)))
+ (unless cmd
+ (format *output* "No match on history list with pattern ~S~%" pattern)
+ (return-from process-history-search *null-cmd*))
+ (maybe-return-history-cmd cmd cmd-args-string)))
+
+
+(defun process-cmd-text (cmd-string line cmd-args-string)
+ "Process a text cmd, such as ':ld a b c'"
+ (flet ((parse-args (parsing args-string)
+ (case parsing
+ (:string
+ (if (zerop (length args-string))
+ nil
+ (list args-string)))
+ (t
+ (let ((string-stream (make-string-input-stream args-string))
+ (eof (cons nil *eof-marker*))) ;new cons for eq uniqueness
+ (loop as arg = (read string-stream nil eof)
+ until (eq arg eof)
+ collect arg))))))
+ (let ((cmd-entry (find-cmd cmd-string)))
+ (unless cmd-entry
+ (return-from process-cmd-text
+ (make-user-cmd :func :cmd-error :input cmd-string)))
+ (make-user-cmd :func (cmd-table-entry-func cmd-entry)
+ :input line
+ :args (parse-args (cmd-table-entry-parsing cmd-entry)
+ cmd-args-string)
+ :hnum *cmd-number*))))