Scanning directories

Posted by Nick Gammon on Sun 13 Nov 2005 01:11 AM — 2 posts, 9,335 views.

Australia Forum Administrator #0
Version 3.69 of MUSHclient adds a new function to the "utils" table, which reads an entire directory on your PC into a Lua table, based on the wildcard you supply.

For example:



t, e = utils.readdir ("c:/mushclient/plugins/*.xml")

assert (t, e) -- raises error on failure

for k, v in pairs (t) do
  Tell (k)
  if (v.directory) then
    Tell (" (dir) ")
  end -- if directory
  Tell (" size ", v.size, " bytes, ")
  Note (os.date ("%c", v.write_time))
end -- for



Example output:



ShowActivity.xml size 1429 bytes, 03/23/04 11:06:54
Slow_speedwalk.xml size 9655 bytes, 10/24/05 08:58:07
Automap.xml size 19944 bytes, 03/26/04 14:20:11


If the directory specification is matched, the result from the call is a table of directory items, keyed by the filename. If the directory specification cannot be matched, or is invalid, it returns nil followed by an error message. You can simply test for non-nil, or call "assert" to report the error.

For each file in the directory (that matches the wildcard) the following is returned:


  • size - file size in bytes
  • create_time - creation time (except for FAT filesystems, where it is omitted)
  • access_time - last access time (except for FAT filesystems, where it is omitted)
  • write_time - time written
  • archive - true if archive. Set whenever the file is changed, and cleared by the BACKUP command.
  • hidden - hidden file. Not normally seen with the DIR command
  • normal - normal file. File can be read or written to without restriction.
  • readonly - read-only. File cannot be opened for
    writing, and a file with the same name cannot be created.
  • directory - Subdirectory.
  • system - system file. Not normally seen with the DIR command.


By detecting suddirectories you could conceivably recurse and find the contents of subdirectories as well.

Amended on Mon 14 Nov 2005 07:45 PM by Nick Gammon
Australia Forum Administrator #1
In case anyone wants to incorporate the code I used into their own projects, here it is ...


#include "../lua/lua.h"
#include "../lua/lauxlib.h"
#include <io.h>
#include <errno.h>

// make number table item
static void MakeNumberTableItem (lua_State *L, const char * name, const double n)
  {
  lua_pushstring (L, name);
  lua_pushnumber (L, n);
  lua_rawset(L, -3);
  }

// make boolean table item
static void MakeBoolTableItem (lua_State *L, const char * name, const int b)
  {
  if (b)
    {
    lua_pushstring (L, name);
    lua_pushboolean (L, b != 0);
    lua_rawset(L, -3);
    }
  }

static int getdirectory (lua_State *L)
  {
  // get directory name (eg. C:\mushclient\*.doc)
  size_t dirLength;
  const char * dirname = luaL_checklstring (L, 1, &dirLength);

  struct _finddatai64_t fdata;

  int h = _findfirsti64 (dirname, &fdata); // get handle

  if (h == -1L)    // no good?
    {
    lua_pushnil (L);

    switch (errno)
      {
      case EINVAL: lua_pushstring (L, "Invalid filename specification"); break;
      default:     lua_pushstring (L, "File specification could not be matched"); break;
      }
    return 2;   // return nil, error message
    }

  lua_newtable(L);    // table of entries
  
  do
    {

    lua_pushstring (L, fdata.name); // file name (will be key)
    lua_newtable(L);                // table of attributes

    // inside this new table put the file attributes

    MakeNumberTableItem (L, "size", (double) fdata.size);
    if (fdata.time_create != -1)    // except FAT
     MakeNumberTableItem (L, "create_time", fdata.time_create);
    if (fdata.time_access != -1)    // except FAT
      MakeNumberTableItem (L, "access_time", fdata.time_access);
    MakeNumberTableItem (L, "write_time",  fdata.time_write);
    MakeBoolTableItem   (L, "archive", fdata.attrib & _A_ARCH);
    MakeBoolTableItem   (L, "hidden", fdata.attrib & _A_HIDDEN);
    MakeBoolTableItem   (L, "normal", fdata.attrib & _A_NORMAL);
    MakeBoolTableItem   (L, "readonly", fdata.attrib & _A_RDONLY);
    MakeBoolTableItem   (L, "directory", fdata.attrib & _A_SUBDIR);
    MakeBoolTableItem   (L, "system", fdata.attrib & _A_SYSTEM);

    lua_rawset(L, -3);              // set key of table item (ie. file name)

    } while (_findnexti64 ( h, &fdata ) == 0);

  _findclose  (h);

  return 1;  // one table of entries
  } // end of getdirectory

// table of operations
static const struct luaL_reg utilslib [] = 
  {

  {"readdir", getdirectory},
 
  {NULL, NULL}
  };

// register library

LUALIB_API int luaopen_compress(lua_State *L)
  {
  luaL_openlib(L, "utils", utilslib, 0);
  return 1;
  }