diff --git a/examples/ls.lua b/examples/ls.lua new file mode 100644 index 0000000..abd847e --- /dev/null +++ b/examples/ls.lua @@ -0,0 +1,140 @@ +#!/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 +end + +local args = parseargs(...) +for _,path in ipairs(args) do + ls(path) +end