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

;; option parsing

(setq dirlist (getopts
"USAGE: %0 [options] dirs...
    lists all the files (not directories) recursively from dirs (defaults to
    current dir),and prints a list globally sorted by time by default
"
("-v" 0 Verbose "verbose: lists subdirectories entered")
("-r" 0 Reverse "sorts in reverse (most recent/bigger first)")
("-l" 0 FollowLinks "follow symbolic links")
("-n" 0 DontSort "do not sort by time: natural order, depth first")
("-a" 0 AlphaSort "sort alphabetically, case unsensitive, depth first")
("-s" 0 SizeSort "sort on size")
("-d" 0 DirSort "sort alphabetically, depth last (for each dir lists files then subdirs)")
("-u" 0 AccessTime "sort by read (access) time instead of last modification")
("-c" 0 StatusTime "sort by status change time instead of last modification")
("-1" 0 OnlyNames "print only file names, no times nor size info")
))

(if (not dirlist) (setq dirlist '("")))
(setq files (list))			;list of strings
(setq all-files (list))
(setq curdir "")
(setq size-files (list))
(setq DontFollowLinks (not FollowLinks))
(if DirSort (setq AlphaSort t))
(if AlphaSort (setq DontSort t))
(if SizeSort (setqn AlphaSort () DirSort () DontSort ()))
(setq timeslot 'mtime)
(if AccessTime (setq timeslot 'atime))
(if StatusTime (setq timeslot 'ctime))

(setq re (regcomp "^(.*)[/]$"))
(setq dirlist (map List 
    '(lambda (s) (if (regexec re s) (regsub re 1) s))
    dirlist
))

(defun le-file (f st &aux y)
  (if (setq s (seconds-to-date (getn st timeslot)))
    (le-file:print
      (+
	(if (< (setq y (mod (getn s 0) 100)) 10) "0" "")
	(String y)
	(if (< (setq sn (getn s 1)) 10) "0" "")
	(String sn)
	(if (< (setq sn (getn s 2)) 10) "0" "")
	(String sn)
	","
	(if (< (setq sn (getn s 3)) 10) "0" "")
	(String sn)
;	":"
	(if (< (setq sn (getn s 4)) 10) "0" "")
	(String sn)
	(progn 
	  (setq size (/ (+ 1023 (getn st 'size)) 1024))
	  (setq size (if (< size 10000)
	      (+ (String size) "k ")
	      (< size 101376)
	      (+ (String (/ size 1024)) "." 
		(String (/ (* 10 (mod size 1024)) 1024)) "M " 
	      )
	      (+ (String (/ size 1024)) "M ")
	  ))
	  " "
	)
        (subseq "      " (length size))
	size
	curdir
	f
))))

(defun le-dir (dir &aux
    (curdir (if (= "" dir) "" (+ curdir dir "/")))
    (*current-directory* *current-directory*)
    (to-dir (if (= dir "") "." dir))
    pos
    st
    contents
  )
  (if (trap-error 'Errors:BadDirectory (setq *current-directory* to-dir))
    (progn
      (if Verbose (print-format *standard-error*
	  "lr: parsing directory %0\n" curdir))
      (setq contents (directory))
      (if AlphaSort (sort contents nocase-compare))
      (le-dir:subdir-init)
      (if SizeSort
	(dolist (f contents)
	  (if (= S_IFREG (logand S_IFMT (get (setq st (file-stats f 
		      DontFollowLinks)) 'mode 0))
	    )
	    (progn (le-file f st)
	      (lappend size-files (list (getn st 'size) (get files -1)))
	    )
	    (= S_IFDIR (logand S_IFMT (get st 'mode 0))) (le-dir:subdir f)
	))
	(dolist (f contents)
	  (if (= S_IFREG (logand S_IFMT (get (setq st (file-stats f 
		      DontFollowLinks)) 'mode 0))
	    )
	    (le-file f st)
	    (= S_IFDIR (logand S_IFMT (get st 'mode 0))) (le-dir:subdir f)
	))
      )
      (le-dir:subdir-done)
    )
    (print-format *standard-error* "lr: cannot go into directory: %0\n"
      to-dir
)))

(if DirSort (progn
    (defun le-dir:subdir-init () (setq  le-dir:subdir-list (list)))
    (defun le-dir:subdir (d) (lappend le-dir:subdir-list d))
    (defun le-dir:subdir-done ()
      (dolist (d le-dir:subdir-list) (le-dir d))
    )
  ) (progn
    (setq le-dir:subdir le-dir)
    (setq le-dir:subdir-done ())
    (setq le-dir:subdir-init ())
))
	
(setq re-name (regcomp "^[^ ]+[ ]+[^ ]+[ ]+(.*)$"))
(defun output-only-name (s)
  (if (regexec re-name s)
    (write-line (regsub re-name 1))
))

(setq output-line (if OnlyNames output-only-name write-line))
	
(if DontSort
  (setq le-file:print output-line)
  (defun le-file:print (f) (lappend files f))
)

;; y2k fix
(setq re-2k (regcomp "^[0-6]"))

(defun r-compare (o1 o2) (- (compare o1 o2)))
(defun n-compare (o1 o2) 
  (if (regexec re-2k o1)
    (if (regexec re-2k o2)
      (compare o1 o2)
      1
    )
    (if (regexec re-2k o2)
      -1
      (compare o1 o2)
    )
))
(defun r-compare (o1 o2) (- (n-compare o1 o2)))

(defun s-compare (o1 o2) (compare (0 o1) (0 o2)))
(defun rs-compare (o1 o2) (compare (0 o2) (0 o1)))
(if Reverse
  (defun nocase-compare (o1 o2) (compare (tolower o2) (tolower o1)))
  (defun nocase-compare (o1 o2) (compare (tolower o1) (tolower o2)))
)

(if (> (length dirlist) 1) (progn
    (dolist (dir dirlist)
      (setq curdir "")
      (le-dir dir)
      (lappend all-files files)
      (setq files (list))
    )
    (setq files (apply + all-files))
  )
  (le-dir (getn dirlist 0))
) 

(if (not DontSort) 
  (if SizeSort (progn
      (sort size-files (if Reverse rs-compare s-compare))
      (dolist (f size-files) (output-line (1 f)))
    )
    (progn
      (sort files (if Reverse r-compare n-compare))
      (dolist (f files) (output-line f))
)))

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

