#!/bin/sh
: ; exec klone $0 "$@"
; The above line finds the klone executable in the $PATH
;;Skeleton of a typical klone script
;;(stack-dump-on-error t)
;;(kdb t)

(setq args (getopts "USAGE: cdromsize devices...
returns the number of readable bytes on a seekable device which you cannot
query for size, e.g. a cdrom. Although the algorithm is tuned for for cdroms,
it can size any seekable device.
If no device is specified, /dev/cdrom is assumed
Warning: cdromsize will generate read of bad sectors errors on the console, 
that you can turn off under linux by dmesg -n 4
"
    ("-s" () slow "optimize for slow (<4x) CD drives")
    ("-v" () verbose "verbose operation")
))

(load "verbose-p")

(if slow (progn
    ;; Values for old, slow CDROMs (2x)
    (setq start-delta (** 2 27)) ;; 128M
    (setq stop-delta (** 2 17)) ;; 128k
    (setq divide-delta (** 2 2)) ;; divide by 4 each time
  ) (progn
    ;; Values for modern ones (>8x)
    (setq start-delta (** 2 25)) ;; 32M
    (setq stop-delta (** 2 21)) ;; 2M
    (setq divide-delta (** 2 4)) ;; divide by 16 each time
))

(defun main (&aux
  )
  (if (not args) (setq args '("/dev/cdrom")))
  (dolist (dev args)
    (catch 'ABORT (find-size dev))
  )
)

(defun find-size (devname &aux
    (fd (open devname :error ()))
    (pos 0)
    end-pos
len
    (delta start-delta)
  )
  (if (not fd)
    (throw 'ABORT (PF "Error, could not open file %0, reason %1\n"
	devname *errno*
      ))
    (= 0 (length (read-chars-n 1 fd)))
    (throw 'ABORT (PF "Strange, file %0, is empty???\n" devname))
  )
  (setq end-pos *maxint*)
  
  (while (>= delta stop-delta)
    (setq pos (find-end fd pos delta end-pos))
    (setq end-pos (+ pos delta))
    (setq delta (/ delta divide-delta))
  )
  (file-position fd pos)
  (verbose? :n "reading the last %0 bytes from %1 ... " 
    (showable-num (* divide-delta delta)) pos)
  (incf pos (setq len (length (read-chars-n (* divide-delta delta) fd))))
  (verbose? "%0 read" len)
  (if (> (length args) 1)
    (PF "%0: %1\n" devname pos)
    (PF "%0\n" pos)
  )
  (file-position fd 0)			;rewind
  (read-chars-n 1 fd)
)

(defun find-end (fd pos delta &optional (end *maxint*))
  (verbose? :n "step by %0: " (showable-num delta))
  (catch 'END
    (incf pos delta)			;suppose pos was OK
    (while (< pos end)
      (file-position fd pos)
      (verbose? :n ".")
      (if (= 0 (length (read-chars-n 1 fd)))
	(throw 'END 
	  (verbose? " [ %0 < size <= %1 ]" (showable-num (- pos delta))
	    (showable-num pos))
	  (- pos delta))
      )
      (incf pos delta)
    )
    (verbose? " [ %0 < size <= %1 ]" (showable-num (- pos delta))
      (showable-num pos))
    (- pos delta)
))
  
(defun showable-num (n)
  (if (> n (** 2 21))
    (PF String "%0M" (/ n (** 2 20)))
    (> n 2048)
    (PF String "%0k" (/ n 1024))
    (PF String "%0" n)
  )
)

(defun read-chars-n (n fd &aux (res ""))
  (catch 'EOF (setq res (read-chars n fd)))
)

(defun verbose? (&rest args &aux nonewline)
  (if verbose (progn
      (if (= :n (getn args 0)) (progn
          (setq nonewline t)
          (setq args (subseq args 1))
      ))
      (apply print-format (+ (list *standard-error*) args))
      (if (not nonewline) (print-format *standard-error* "\n"))
      (flush *standard-error*)
)))

(main)

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

