#!/bin/sh
: ; exec klone $0 "$@"
; The above line finds the klone executable in the $PATH
;;Skeleton of a typical klone script

(setq args (getopts "USAGE: %0 [options] files...
Converts files and dirs to lowercase. Recurse in dirs
Aborts in error if it cannot rename.
"
    ("-u" () upper "converts to upper case instead")
    ("-%" () percent "converts %xx to _ in names instead of changing cases")
    ("-s" () spaces "converts spaces to _ in names instead of changing cases")
    ("-n" () nothing "do not perform renames")
    ("-v" () verbose "verbose operation")
    ("-w" () nocase "to use on case-insensitive (windows) filesystems
Put this option in case of errors like \"file identicals\"")
    ("-nr" () norecurse "do not recurse in dirs")
    ("-c" () caps "Puts into Caps mode: transforms foo.bar, FOO_BAR, foo bar,
foo-bar, into FooBar")
    ("-debug" () enter-debugger-on-error "enter klone debugger on error" 
      :hidden t)
    ("-stackdump" () stackdump-on-error "verbose stack dump on error"
      :hidden t)
))

(if (not args) (setq args '(".")))
(if enter-debugger-on-error (kdb t))
(if stackdump-on-error (stack-dump-on-error t))


(defun do-file (file rest &aux
    (lfile (convfunc file))
  )
  (if (/= "" file) (progn
      (dolist (f rest)
	(if (= lfile (convfunc f))
	  (abort "ERROR: files %0 and %1 exist together in %2" file f 
	    *current-directory*
      )))
      (if (/= file lfile) (progn
	  (verbose? "  %0  ==>  %1" file lfile)
	  (if (not nothing)
	    (if (not (rename-file file lfile))
	      (abort "ERROR: moving %0 into %1 in %2 failed" file lfile
		*current-directory*
))))))))

(defun do-dir (dir &aux
    (*current-directory* dir)
    (filelist (directory))
    (file (getn filelist 0))
  )
  (delete filelist 0)
  (while file
    (if (and (= 'directory (file-type file)) (not norecurse))
      (do-dir file)
    )
    (do-file file filelist)
    (setq file (getn filelist 0))
    (setq filelist (subseq filelist 1))
  )
)

(defun rename-file (f1 f2)
  (if nocase
    (and (= 0 (wait (system (list "mv" f1 "________.___"))))
      (= 0 (wait (system (list "mv" "________.___" f2))))
    )
    (= 0 (wait (system (list "mv" f1 f2))))
  )
)
(defun abort (&rest args)
  (apply print-format (+ (list *standard-error*) args))
  (write-line "ABORTING OPERATION NOW\n" *standard-error*)
  (exit 1)
)

(defun filepart (file &aux
    (re (regcomp "^(.*)[/]([^/]+)$"))
  )
  (if (regexec re file) (regsub re 2) file)
)

(defun dirpart (file &aux
    (re (regcomp "^(.*)[/]([^/]+)$"))
  )
  (if (regexec re file) (regsub re 1) ".")
)

(setq percent-re (regcomp "%[0-9a-fA-F][0-9a-fA-F]"))
(defun percent-conv (s &aux (res (copy s)))
  (replace-string res percent-re "_" :all t :quote t)
  res
)  

(setq spaces-re (regcomp " "))
(defun spaces-conv (s &aux (res (copy s)))
  (replace-string res spaces-re "_" :all t :quote t)
  res
)  

(defun caps-conv (s &aux (res (copy "")))
  (doregexp (re "([^ ._-])([^ ._-]*)" s)
    (nconc res (toupper (re 1)) (tolower (re 2)))
  )
  res
)

(defun main (&aux
  )
  (setq convfunc (if 
      percent percent-conv
      spaces spaces-conv
      caps caps-conv
      t (if upper toupper tolower)
  ))

  (dolist (file args)
    (if (and (not norecurse) (= 'directory (file-type file)))
      (do-dir file)
    )
    (with (*current-directory* (dirpart file)
	fl (directory)
      )
      (delete-item fl (filepart file))
      (do-file (filepart file) fl)
  ))
)

(main)

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

