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

;(trace-all t)
(PF "ARGUMENTS: %r0\n" *arguments*)

(setq dirs (getopts
    "ll2le - A filter to convert the result of a ls -ltRr (or ls -lR)
into a le-like format
usage: ll2le [options] [dir]
if dir is \".\", current dir is taken
if dir is not given, or is \"-\", then take output of a ls -lR as stdin"
    ("-n" () (sort-by date name)  "sorted by name")
    ("-N" () (sort-by date name-nocase)
      "sorted by name, but case-insensitive")
    ("-t" () (sort-by date date)
      "(default) sorted by date, most recent first")
    ("-s" () (sort-by date size) "sorted by size, biggest fisrt")
    ("-d" () include-dirs "include directories in listing (default only files)")
    ("-r" () sort-reverse "reverse sort")
    ("-v" () verbose "verbose - only use for debug")
))

(require 'records)
(require 'cur-date)

(if (= *machine* 'amiga)(setq TIMEZONE 0))

(if (not (boundp '*machine*))
  (if (not (getenv "SHELL")) (setq *machine* 'amiga) (setq *machine* 'UNIX))
)
(setq ls-command (if (= *machine* 'amiga) "u:ls -lREGI" "ls -lR"))

(setq cur-year (+ "19" (String (get (cur-date) 0))))

(setq re-total (regcomp "^total [0-9]+$"))
(setq re-dir (regcomp "^([.][/])?([^ ]+):$"))
(setq re-entry-amiga (regcomp "^(.)[^ ]+[ ]+[0-9]+[ ]+([0-9]+)[ ]+([A-Z][a-z][a-z])[ ]+([0-9]+)[ ]+([^ ]+)[ ]+([^ ]+)$"
))
(setq re-entry-bsd (regcomp "^(.)[^ ]+[ ]+[0-9]+[ ]+[^ ]+[ ]+([0-9]+)[ ]+([A-Z][a-z][a-z])[ ]+([0-9]+)[ ]+([^ ]+)\[ ]+([^ ]+)$"
))
(setq re-entry-sysv (regcomp
    "^(.)[^ ]+[ ]+[0-9]+[ ]+[^ ]+[ ]+[^ ]+[ ]+([0-9]+)[ ]+([A-Z][a-z][a-z])[ ]+([0-9]+)[ ]+([^ ]+)\[ ]+([^ ]+)$"
))
(setq re-entry re-entry-bsd)

(defrecord FileEntry name dir type size date time)
;; name = string
;; dir = current dir, with / appended
;; type = d - or else... (string of one char)
;; size in bytes
;; date in days since 1900
;; time = string HH:MM

(if (or (not dirs) (= "-" (getn dirs 0)))
  (setq fdin *standard-input*)
  (if (= "." (getn dirs 0))
    (system ls-command :output 'fdin)
    (system (+ ls-command " " (get dirs 0 "")) :output 'fdin)
))

(setq curdir "")
(setq files (list))

;; parses all ls lines, and build up the files database with them
(defun parse-files ()
  (while (setq line (read-line fdin ()))
    (if
      (regexec re-entry line)		;a normal file description
      (if (or include-dirs (/= #\d (getn line 0)))
	(put files -1
	  (make-record 'FileEntry
	    (regsub re-entry "\\6")
	    curdir
	    (regsub re-entry "\\1")
	    (regsub re-entry "\\2")
	    (make-date (regsub re-entry "\\3") (regsub re-entry "\\4")
	      (regsub re-entry "\\5"))
	    (make-time (regsub re-entry "\\5"))
      )))
      
      (regexec re-dir line)		;we go into a new directory
      (setq curdir (regsub re-dir "\\2/"))
      
					;SYSV ls
      (regexec re-entry-sysv line) (progn
	(setq re-entry re-entry-sysv)
	(if (or include-dirs (/= #\d (getn line 0)))
	  (put files -1
	    (make-record 'FileEntry
	      (regsub re-entry "\\6")
	      curdir
	      (regsub re-entry "\\1")
	      (regsub re-entry "\\2")
	      (make-date (regsub re-entry "\\3") (regsub re-entry "\\4")
		(regsub re-entry "\\5"))
	      (make-time (regsub re-entry "\\5"))
      ))))
      
					;AMIGA ls
      (regexec re-entry-amiga line) (progn
	(setq re-entry re-entry-amiga)
	(if (or include-dirs (/= #\d (getn line 0)))
	  (put files -1
	    (make-record 'FileEntry
	      (regsub re-entry "\\6")
	      curdir
	      (regsub re-entry "\\1")
	      (regsub re-entry "\\2")
	      (make-date (regsub re-entry "\\3") (regsub re-entry "\\4")
		(regsub re-entry "\\5"))
	      (make-time (regsub re-entry "\\5"))
	)))
      )
      
      (regexec re-total line)		;subtotal "Total" line
      ()
      (= "" line)			;blank line
      ()
					; ignore not recognized entries
      verbose
      (print-format "***Not recognized line: %r0\n" line)
    )
))

(setq make-date:re-time (regcomp "^([0-9]+):([0-9]+)$"))
(setq make-date:re-last2 (regcomp "(..)$"))
(defun make-date (month day time)
  (if (regexec make-date:re-time time)
      (setq year cur-year)
      (setq year time)
  )
  (+ (Int day)
    (* 100 (get '("Jan" 01 "Feb" 02 "Mar" 03 "Apr" 04 "May" 05 "Jun" 06
	"Jul" 07 "Aug" 08 "Sep" 09 "Oct" 10 "Nov" 11 "Dec" 12
      ) month 00))
    (* 10000 (Int year) 1900)
  )
)

(defun make-time (time)
  (if (regexec make-date:re-time time) 
    time
    "00:00"
))

(parse-files)

(PF "sort-reverse = %0, sort-by = %1, include-dirs = %2\n"
	      sort-reverse sort-by include-dirs)
(setq sort-function (if
    sort-reverse 
    (if					;sort-reverse

      (= sort-by 'date)
      (lambda (f1 f2) (if (= (getn f1 FileEntry-date) (getn f2 FileEntry-date))
	  (compare (getn f1 FileEntry-time) (getn f2 FileEntry-time))
	  (> (getn f1 FileEntry-date) (getn f2 FileEntry-date))
	  1 -1
      ))
    )
    (if					; NOT sort-reverse

      (= sort-by 'date)
      (lambda (f2 f1) (if (= (getn f1 FileEntry-date) (getn f2 FileEntry-date))
	  (compare (getn f1 FileEntry-time) (getn f2 FileEntry-time))
	  (> (getn f1 FileEntry-date) (getn f2 FileEntry-date))
	  1 -1
      ))
)))

(PF "sort-function = %0\n" sort-function)
(pp sort-function)
(write-line "")

(sort files sort-function)

(dolist (file files)
  (if (= "d" (get file FileEntry-type))
    (setq k "-----")
    (progn
      (setq k (String (setq s
	    (/ (+ (Int (get file FileEntry-size 0)) 1023) 1024))))
      (if (< s 10000)
	(nconc k "K")
	(setq k (+ (String (/ s 1000)) "M"))
  )))
  (print-format "%0 %4%1  %2%3\n"
    (getn file FileEntry-date)
    k
    (getn file FileEntry-dir)
    (getn file FileEntry-name)
    (get '("     " "    " "   " "  " " ") (length k) "")
))
