141 lines
3.4 KiB
Lua
141 lines
3.4 KiB
Lua
|
#!/bin/env lua
|
||
|
-- Basic Unix-style directory listing.
|
||
|
-- Demonstrates low-level raw use of a Dir, in order to list even . and .. to
|
||
|
-- output.
|
||
|
--
|
||
|
-- NOTE: the simplistic argument parser doesn't handle merged options like -ht.
|
||
|
--
|
||
|
-- Example uses:
|
||
|
-- lua ls.lua
|
||
|
-- lua ls.lua -a ..
|
||
|
-- lua ls.lua -a -h src
|
||
|
-- lua ls.lua -a -t a.dir b.dir c.dir
|
||
|
--
|
||
|
-- Author: Lorenzo Cogotti, The DoubleFourteen Code Forge
|
||
|
|
||
|
local osx = require 'osx'
|
||
|
local io = require 'io'
|
||
|
local write = io.write
|
||
|
|
||
|
local sep = osx.sep
|
||
|
local aflag = false -- list hidden
|
||
|
local tflag = false -- sort by time
|
||
|
local Sflag = false -- sort by size
|
||
|
local hflag = false -- print size, human readable (equivalent to -sh)
|
||
|
|
||
|
local function parseargs(...)
|
||
|
local args = {}
|
||
|
|
||
|
for i = 1,select('#', ...) do
|
||
|
local arg = select(i, ...)
|
||
|
|
||
|
if arg == '-a' then
|
||
|
aflag = true
|
||
|
elseif arg == '-t' then
|
||
|
tflag, Sflag = true, false
|
||
|
elseif arg == '-S' then
|
||
|
Sflag, tflag = true, false
|
||
|
elseif arg == '-h' then
|
||
|
hflag = true
|
||
|
else
|
||
|
args[#args+1] = arg
|
||
|
end
|
||
|
end
|
||
|
if #args == 0 then
|
||
|
args = { "." } -- current directory by default
|
||
|
end
|
||
|
return args
|
||
|
end
|
||
|
|
||
|
local function ksize(sz)
|
||
|
sz = sz / 1024
|
||
|
|
||
|
if sz > 0 then
|
||
|
return ("%.1fK"):format(sz)
|
||
|
else
|
||
|
return "0"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function listfilenames(filenames, bufs, total)
|
||
|
table.sort(filenames) -- always sort by name
|
||
|
|
||
|
if Sflag then
|
||
|
table.sort(filenames, function (a, b)
|
||
|
a, b = bufs[a], bufs[b]
|
||
|
|
||
|
local asize = a.size or -1
|
||
|
local bsize = b.size or -1
|
||
|
return asize > bsize -- sort by size, largest first
|
||
|
end)
|
||
|
elseif tflag then
|
||
|
table.sort(filenames, function(a, b)
|
||
|
a, b = bufs[a], bufs[b]
|
||
|
|
||
|
local atime = a.mtime or -1
|
||
|
local btime = b.mtime or -1
|
||
|
return atime > btime -- sort by time, latest first
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
if hflag then
|
||
|
write(ksize(total), " total\n")
|
||
|
end
|
||
|
for _, filename in ipairs(filenames) do
|
||
|
local buf = bufs[filename]
|
||
|
|
||
|
if hflag then
|
||
|
write(ksize(buf.size or 0), " ")
|
||
|
end
|
||
|
write(filename, '\n')
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function ls(path)
|
||
|
local dir, err = osx.opendir(path)
|
||
|
if not dir then
|
||
|
io.stderr:write(err, "\n")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local filenames = {}
|
||
|
local bufs = {}
|
||
|
local total = 0
|
||
|
|
||
|
while true do
|
||
|
:: nextfilename ::
|
||
|
local filename, err = dir:readdir()
|
||
|
if err then
|
||
|
-- Report, but tolerate error
|
||
|
io.stderr:write(path, ": ", err, "\n")
|
||
|
end
|
||
|
if not filename then
|
||
|
break -- done with this dir
|
||
|
end
|
||
|
if filename:sub(1, 1) == '.' and not aflag then
|
||
|
goto nextfilename -- skip hidden
|
||
|
end
|
||
|
|
||
|
-- stat() file, update counters and store for listing
|
||
|
local filepath = path..sep..filename
|
||
|
local buf, err = osx.stat(filepath)
|
||
|
if not buf then
|
||
|
io.stderr:write(filepath, ": ", err, "\n")
|
||
|
goto nextfilename
|
||
|
end
|
||
|
|
||
|
total = total + (buf.size or 0)
|
||
|
filenames[#filenames+1] = filename
|
||
|
bufs[filename] = buf
|
||
|
end
|
||
|
|
||
|
-- Print file list
|
||
|
listfilenames(filenames, bufs, total)
|
||
|
dir:close() -- NOTE: could have marked this with <close>
|
||
|
end
|
||
|
|
||
|
local args = parseargs(...)
|
||
|
for _,path in ipairs(args) do
|
||
|
ls(path)
|
||
|
end
|