(in-package #:sync-music/libcue) (defmacro with-read-file ((var path) &body body) "Bind VAR to the result of an fopen on PATH while executing BODY." (once-only (path) `(let ((,var (fopen (uiop:native-namestring ,path) "r"))) (declare (dynamic-extent ,var)) (when (cffi:null-pointer-p ,var) (error "Failed to open file `~A` with errno ~A." ,path +errno+)) (unwind-protect (progn ,@body) (fclose ,var))))) (defmacro with-ignore-stderr (&body body) "Execute BODY without printing anything into stderr. Only works on Unix systems with a /dev/fd/ filesystem." #+unix (with-gensyms (old-stderr) `(progn (finish-output *error-output*) (let ((,old-stderr (dup +stderr-fileno+))) (freopen "/dev/null" "w" +stderr+) (unwind-protect (progn ,@body) (freopen (format nil "/dev/fd/~D" ,old-stderr) "a" +stderr+))))) #-unix `(progn ,@body)) (defmacro with-cue ((var type data) &body body) "Bind VAR to the result of a cue_parse_* while executing BODY. If TYPE is :FILE, use cue_parse_file with fopen on DATA. If TYPE is :STRING, use cue_parse_string directly." (once-only (data) `(let ((,var (with-ignore-stderr ,(ecase type (:file (with-gensyms (file) `(with-read-file (,file ,data) (cue-parse-file ,file)))) (:string `(cue-parse-string ,data)))))) (declare (dynamic-extent ,var)) (unless (cffi:null-pointer-p ,var) (unwind-protect (progn ,@body) (cd-delete ,var)))))) (defun get-rem (type data) (rem-get (cffi:foreign-enum-value 'rem-type type) data)) (defun get-cd-text (type data) (cd-text-get (cffi:foreign-enum-value 'pti type) data)) (defun cd-get-mode (cd) (cffi:foreign-enum-keyword 'disc-mode (%cd-get-mode cd))) (defun track-get-mode (track) (cffi:foreign-enum-keyword 'track-mode (%track-get-mode track))) (defun track-get-sub-mode (track) (cffi:foreign-enum-keyword 'track-sub-mode (%track-get-sub-mode track))) (defun track-flag-set-p (track flag) (%track-flag-set-p track (cffi:foreign-enum-keyword 'track-flag flag))) (defun ensure-nonempty (val) "Ensure a null value returned by a libcue function is NIL." (unless (etypecase val (null t) (string (emptyp val)) (integer (minusp val))) val))