aboutsummaryrefslogtreecommitdiffhomepage
path: root/core/lfs_ext.lua
blob: 1c19e389ff77c5410aef0e7b0a77e6c6a3bf7c0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
-- Copyright 2007-2013 Mitchell mitchell.att.foicica.com. See LICENSE.

--[[ This comment is for LuaDoc.
---
-- Extends the `lfs` library to find files in directories.
module('lfs')]]

---
-- The filter table containing common binary file extensions and version control
-- directories to exclude when iterating over files and directories using
-- `dir_foreach` when its `exclude_FILTER` argument is `false`.
-- @see dir_foreach
-- @class table
-- @name FILTER
lfs.FILTER = {
  extensions = {
    'a', 'bmp', 'bz2', 'class', 'dll', 'exe', 'gif', 'gz', 'jar', 'jpeg', 'jpg',
    'o', 'png', 'so', 'tar', 'tgz', 'tif', 'tiff', 'zip'
  },
  folders = {'%.bzr$', '%.git$', '%.hg$', '%.svn$', 'CVS$'}
}

-- Determines whether or not the given file matches the given filter.
-- @param file The filename.
-- @param filter The filter table.
-- @return boolean `true` or `false`.
local function exclude(file, filter)
  if not filter then return false end
  local ext = filter.extensions
  if ext and ext[file:match('[^%.]+$')] then return true end
  for i = 1, #filter do
    local patt = filter[i]
    if patt:sub(1, 1) ~= '!' then
      if file:find(patt) then return true end
    else
      if not file:find(patt:sub(2)) then return true end
    end
  end
  return false
end

---
-- Iterates over all files and sub-directories in directory *dir*, calling
-- function *f* with each file found.
-- Files passed to *f* do not match any pattern in string or table *filter*,
-- and, unless *exclude_FILTER* is `true`, `FILTER` as well. A filter table
-- contains Lua patterns that match filenames to exclude, an optional `folders`
-- sub-table that contains patterns matching directories to exclude, and an
-- optional `extensions` sub-table that contains raw file extensions to exclude.
-- Any patterns starting with '!' exclude files and directories that do not
-- match the pattern that follows.
-- @param dir The directory path to iterate over.
-- @param f Function to call with each full file path found. If *f* returns
--   `false` explicitly, iteration ceases.
-- @param filter Optional filter for files and directories to exclude.
-- @param exclude_FILTER Optional flag indicating whether or not to exclude the
--   default filter `FILTER` in the search. If `false`, adds `FILTER` to
--   *filter*.
--   The default value is `false` to include the default filter.
-- @param recursing Utility flag indicating whether or not this function has
--   been recursively called. This flag is used and set internally, and should
--   not be set otherwise.
-- @see FILTER
-- @name dir_foreach
function lfs.dir_foreach(dir, f, filter, exclude_FILTER, recursing)
  if not recursing then
    -- Convert filter to a table from nil or string arguments.
    if not filter then filter = {} end
    if type(filter) == 'string' then filter = {filter} end
    -- Add FILTER to filter unless specified otherwise.
    if not exclude_FILTER then
      for k, v in pairs(lfs.FILTER) do
        if not filter[k] then filter[k] = {} end
        local filter_k = filter[k]
        for i = 1, #v do filter_k[#filter_k + 1] = v[i] end
      end
    end
    -- Create file extension filter hash table for quick lookups.
    local ext = filter.extensions
    if ext then for i = 1, #ext do ext[ext[i]] = true end end
  end
  local lfs_attributes = lfs.attributes
  for file in lfs.dir(dir) do
    if not file:find('^%.%.?$') then -- ignore . and ..
      file = dir..(not WIN32 and '/' or '\\')..file
      local type = lfs_attributes(file, 'mode')
      if type == 'directory' and not exclude(file, filter.folders) then
        lfs.dir_foreach(file, f, filter, nil, true)
      elseif type == 'file' and not exclude(file, filter) then
        if f(file) == false then return end
      end
    end
  end
end