lua-osx/examples/ls.lua

147 lines
3.6 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
--
-- Supported options:
-- -a list hidden files
-- -t sort by time, most recent first
-- -S sort by size, largest first
-- -h print size next to each file in kilobytes (1024)
--
-- 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