diff --git a/CLAUDE.md b/CLAUDE.md index 374fc40..a82ae12 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -112,7 +112,7 @@ Common Lispでは同じパッケージ内で同名関数を再定義すると警 すべての出力ファイル名生成関数が`opts`を第一引数として受け取るAPIに統一され、 テストスイートでの検証とバイナリビルドでの動作確認も完了。 -#### GIFモードのオプション制限強化 +#### GIFモードのオプション制限強化 ✅ **完了** GIFモードで`--input`オプションとの組み合わせエラーが適切に処理されていない問題を修正: **問題:** diff --git a/src/package.lisp b/src/package.lisp index 9f69c1f..39364dc 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -28,15 +28,14 @@ :validate-codec :validate-mono :validate-speed - :parse-speed-float :validate-options :validate-output :dispatch-validation ;; util.lisp :input-extension - :parse-float - :safe-parse-float + :parse-number + :parse-number-or-exit :parse-frame-rate :resolution-from-key :parse-dimensions diff --git a/src/util.lisp b/src/util.lisp index 212d0fb..1981b60 100644 --- a/src/util.lisp +++ b/src/util.lisp @@ -1,28 +1,28 @@ (in-package :visp) -(defun parse-float (str) - "Parse a string as a float. Returns NIL if not parsable." - (handler-case - (let ((val (read-from-string str))) - (if (floatp val) - val - (coerce val 'float))) ; int → float に変換 - (error () nil))) +(defun parse-number (str) + "Parse string to number. Returns nil on failure. Secure version with *read-eval* disabled." + (let ((*read-eval* nil)) + (handler-case + (let ((result (with-input-from-string (s str) (read s)))) + (if (numberp result) result nil)) + (error () nil)))) + +(defun parse-number-or-exit (str &optional (context "number")) + "Parse string to number. Exit with error message on failure." + (let ((result (parse-number str))) + (unless result + (format t "~a Invalid ~a value: ~a~%" (log-tag "error") context str) + (uiop:quit 1)) + result)) -(defun safe-parse-float (str) - (let ((val (parse-float str))) - (if val - val - (progn - (format t "~a Invalid float value: ~a~%" (log-tag "error") str) - (uiop:quit 1))))) (defun parse-frame-rate (rate) (handler-case (let ((parts (uiop:split-string rate :separator "/"))) (if (= (length parts) 2) - (/ (parse-float (first parts)) (parse-float (second parts))) - (parse-float rate))) + (/ (parse-number (first parts)) (parse-number (second parts))) + (parse-number rate))) (error () nil))) (defun input-extension (filename) diff --git a/src/validate.lisp b/src/validate.lisp index 2ece37c..e2a0891 100644 --- a/src/validate.lisp +++ b/src/validate.lisp @@ -285,23 +285,12 @@ (when (member codec '("prores" "hap") :test #'string=) (error "The --mono option is not supported with codec ~A." codec))))) -(defun parse-speed-float (string) - "Parse a string as a float for speed validation. Throws an error if not a valid number." - (let ((*read-eval* nil) - (result nil)) - (with-input-from-string (s string) - (setf result (read s))) - ;; 読み取った結果が数値でない場合はエラー - (unless (numberp result) - (error "Not a valid number: ~a" string)) - result)) (defun validate-speed (opts) "Validate that --speed is a positive number if specified." (let ((speed (visp-options-speed opts))) (when speed - (let ((speedf (handler-case (parse-speed-float speed) - (error () nil)))) + (let ((speedf (parse-number speed))) ;; speedは必ず0より大きい数値 (unless (and (numberp speedf) (> speedf 0)) (format t "~a --speed must be a positive number, but got '~a'.~%" diff --git a/src/video.lisp b/src/video.lisp index 3722761..c1850a5 100644 --- a/src/video.lisp +++ b/src/video.lisp @@ -25,9 +25,9 @@ (parts (uiop:split-string output :separator "/"))) (cond ((= (length parts) 2) - (/ (safe-parse-float (first parts)) (safe-parse-float (second parts)))) + (/ (parse-number-or-exit (first parts) "fps") (parse-number-or-exit (second parts) "fps"))) ((= (length parts) 1) - (safe-parse-float (first parts))) + (parse-number-or-exit (first parts) "fps")) (t (format t "~a Failed to extract FPS from input: ~a~%" (log-tag "error") output) (uiop:quit 1))))) @@ -65,7 +65,7 @@ `(:width ,(when width (parse-integer (cdr width))) :height ,(when height (parse-integer (cdr height))) :fps ,(when rate (parse-frame-rate (cdr rate))) - :duration ,(when duration (parse-float (cdr duration))) + :duration ,(when duration (parse-number (cdr duration))) :has-audio ,has-audio :audio-codec ,(if has-audio audio-codec nil) :video-codec ,(when codec (cdr codec)))))) diff --git a/t/test-validate.lisp b/t/test-validate.lisp index 5ddef44..6da6bb7 100644 --- a/t/test-validate.lisp +++ b/t/test-validate.lisp @@ -2,23 +2,23 @@ (:use :cl :rove) (:import-from :visp :make-visp-options - :parse-speed-float + :parse-number :validate-speed :validate-gif-mode)) (in-package :visp.test.validate) -(deftest parse-speed-float-tests - (testing "Parses valid float strings" - (ok (= (visp:parse-speed-float "2.0") 2.0)) - (ok (= (visp:parse-speed-float "0.5") 0.5)) - (ok (= (visp:parse-speed-float "1") 1.0)) - (ok (= (visp:parse-speed-float "3.14159") 3.14159))) +(deftest parse-number-tests + (testing "Parses valid number strings" + (ok (= (visp:parse-number "2.0") 2.0)) + (ok (= (visp:parse-number "0.5") 0.5)) + (ok (= (visp:parse-number "1") 1.0)) + (ok (= (visp:parse-number "3.14159") 3.14159))) - (testing "Throws error for invalid strings" - (ok (signals (visp:parse-speed-float "invalid"))) - (ok (signals (visp:parse-speed-float "abc"))) - (ok (signals (visp:parse-speed-float ""))))) + (testing "Returns NIL for invalid strings" + (ok (null (visp:parse-number "invalid"))) + (ok (null (visp:parse-number "abc"))) + (ok (null (visp:parse-number ""))))) (deftest validate-speed-tests (testing "Validates positive float values"