#!/bin/sh
: ; exec klone $0 "$@"
; The above line allows not to embed the exact path of the klone executable

;;Skeleton of a typical klone script

(setq args (getopts "USAGE: %0 [options] bin-file iso-file
filters a .bin cdrwin image into an ISO one, only the data part, no audio
use -1 for MODE1 files, -2 for MODE2 files
%0 will try to guess mode from .cue file if present
if iso-file is '-' outputs it on stdout
"
    ("-1" () force-mode1 "MODE1 .bin file")
    ("-2" () force-mode2 "MODE2 .bin file")
    ("-v" () verbose "verbose operation")
    ("-nc" () nocheck "dont verify file length")
    ("-debug" () enter-debugger-on-error "enter klone debugger on error")
    ("-stackdump" () stackdump-on-error "verbose stack dump on error")
))

(if enter-debugger-on-error (kdb t))
(if stackdump-on-error (stack-dump-on-error t))
(if (not (= 2 (length args))) (getopts :usage))
(setq cuemode ())			;read from .cue: 1, 2 or ()

(defun main ()
;; a fix first, most .bin are not readable:
  (wait (system (list "chmod" "a+r,u+w" (0 args))
      :output "/dev/null" :error "/dev/null"))
  (setq in (open (0 args)))
  (setq cuemode (find-cue (0 args)))
  (if force-mode1 (setq cuemode 1))
  (if force-mode2 (setq cuemode 2))
  (when (not cuemode)
    (if (not (try-bin2iso (0 args))) (progn
	(PFE "Could not find an understandable cue file, you MUST specify mode!\n")
	(exit 1)
      )
      (exit 0)
  ))
  (setq out (if (= "-" (1 args)) *standard-output*
      (open (1 args) :direction :output :if-exists :supersede))
  )
  (bin2iso in out cuemode)
)

(defmacro PFE (&rest args)
  `(print-format *standard-error* ,@args)
)

(defun find-cue (binfile &aux
    (re (regcomp "^((.*[/\\])?[^/\\]+)[.]([bB][iI][nN])$"))
    (space "[ \t\n\r]*")
    (recue-partial (regcomp (+ "^FILE ([\"][^\"]*[\"]|[^\" ]*) BINARY" space
	  "TRACK 01 MODE([12])[/]2352" space
	  "(FLAGS DCP)?" space
	  "INDEX 01 00:00:00" space
    )))
    (recue-modepos 2)
    (recue (regcomp (+ recue-partial "$")))
    cuefile cuefd cue cuemode
  )
  (when (regexec re binfile)
    (setq cuefile (+ (regsub re 1) "." (if 
	  (= (regsub re 3) "BIN") "CUE"
	  (= (regsub re 3) "Bin") "Cue"
	  "cue"
    )))
    (setq find-cue:cuefile cuefile)
    (setq cuefd (open cuefile :error ()))
    (unless cuefd (PFE "  .cue file %0 not found\n" cuefile))
    (setq cue (String cuefd))
    (if (regexec recue cue)
      (setq cuemode (if (= (regsub recue recue-modepos) "1") 1 2))
      (regexec recue-partial cue)
      (PFE "  .cue file has more than an iso track!\n")
    )
  )
  (unless cuemode
    (PFE "*** WARNING!!! *** No understandable cuefile found.
  ISO image may be bad, proceed with caution!\n")
  )
  cuemode
)

(defun bin2iso (in out mode &aux len nb b buffer skip)
  (setq len (get (file-stats (0 args)) 'size))
  (setq show-every 1000)
  (setq skip (if (= mode 1) 16 24))	; sector header

  (if (and (not nocheck) (/= 0 (mod len 2352)))
    (fatal-error 1 ".bin file %0 length not a multiple of 2352!\n")
  )
  (setq nb (/ len 2352))
  (setq b 0)
  (PFE "Writing ISO file in MODE%0\n" mode)

  (while (< b nb)
    (setq buffer (read-chars 2352 in))
    (if (/= 2048 (write-chars buffer 2048 out skip))
      (fatal-error 1 "Write error! (disk full?)\n")
    )
    (if (= 0 (mod b show-every))
      (if (= 0 b)
	(ascii-progress-bar-with-speed 0 (* nb 2048))
	(ascii-progress-bar-with-speed (* b 2048))
    ))
    (incf b)
  )
  (ascii-progress-bar-with-speed (* b 2048))
  (PFE "\n")
)

(defun try-bin2iso (binfile &aux)
  (if find-cue:cuefile (progn
      (PFE "Trying normal bin2iso: bin2iso %0 %1 D\n" 
	binfile find-cue:cuefile )
      (= 0 (wait (system (list "bin2iso" binfile find-cue:cuefile "D"))))
  ))
)

(main)

;;; EMACS MODES
;;; Local Variables: ***
;;; mode:lisp ***
;;; End: ***

