From 7db6401dfb0604e92946ac4f7c76d541498e6ebb Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Mon, 3 Jan 2022 16:49:58 -0600
Subject: add scan_directory()

---
 src/argent.c   |  3 +-
 src/bindings.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/bindings.h |  4 +++
 3 files changed, 94 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/argent.c b/src/argent.c
index b83f851..c4738d4 100644
--- a/src/argent.c
+++ b/src/argent.c
@@ -33,7 +33,8 @@ int main(int argc, char **argv)
    argent_log(DEBUG, "create argent table");
    hs_create_table
       (L,
-       hs_str_cfunc("markdown", markdown)
+       hs_str_cfunc("markdown", markdown),
+       hs_str_cfunc("scanDirectory", scan_directory)
        );
    lua_setglobal(L, "argent");
 
diff --git a/src/bindings.c b/src/bindings.c
index b02911b..2988685 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -1,6 +1,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <lua.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
 
 #include "honeysuckle.h"
 #include "md4c-html.h"
@@ -76,3 +79,88 @@ int markdown(lua_State *L)
    argent_log(DEBUG, "finish markdown parsing");
    return 1;
 }
+
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static void throw_directory_error(lua_State *L, char *dir_name);
+static struct dirent *read_dir(lua_State *L, DIR *directory);
+
+int scan_directory(lua_State *L)
+{
+   argent_log(DEBUG, "begin scan_directory()");
+   char *dir_name;
+   hs_parse_args(L, hs_str(dir_name));
+
+   DIR *directory = opendir(dir_name);
+   if (directory == NULL)
+      throw_directory_error(L, dir_name);
+
+   lua_newtable(L);
+   int directory_table = lua_gettop(L);
+   int directory_index = 1;
+   lua_newtable(L);
+   int file_table = lua_gettop(L);
+   int file_index = 1;
+
+   struct dirent *entry;
+   while ((entry = read_dir(L, directory)) != NULL) {
+      lua_pushstring(L, entry->d_name);
+      if (entry->d_type == DT_DIR) {
+	 lua_rawseti(L, directory_table, directory_index);
+	 directory_index += 1;
+      }
+      else {
+	 lua_rawseti(L, file_table, file_index);
+	 file_index += 1;
+      }
+   }
+
+   closedir(directory);
+   argent_log(DEBUG, "end scan_directory()");
+
+   return 2;
+}
+
+
+static void throw_directory_error(lua_State *L, char *dir_name)
+{
+   argent_log(ERROR, "failed to open directory: %d\n", errno);
+   switch(errno) {
+   case EACCES:
+      hs_throw_error(L, "read %s: permission denied", dir_name);
+      break;
+
+   case EMFILE:
+      hs_throw_error(L, "read %s: this process has too many open files", dir_name);
+      break;
+
+   case ENFILE:
+      hs_throw_error(L, "read %s: this file system cannot support any more open files", dir_name);
+      break;
+
+   case ENOMEM:
+      hs_throw_error(L, "read %s: Not enough memory", dir_name);
+      break;
+
+   default:
+      hs_throw_error(L, "read %s: unknown error", dir_name);
+      break;
+   }
+}
+
+
+static struct dirent *read_dir(lua_State *L, DIR *directory)
+{
+   // can't tell if a NULL was EOF or error without this
+   errno = 0;
+   struct dirent *entry = readdir(directory);
+
+   if (entry == NULL && errno != 0) {
+      argent_log(ERROR, "attempted to read invalid dirstream");
+      closedir(directory);
+      hs_throw_error(L, "attempted to read invalid dirstream");
+   }
+
+   return entry;
+}
diff --git a/src/bindings.h b/src/bindings.h
index 3ee3a1a..853f0c0 100644
--- a/src/bindings.h
+++ b/src/bindings.h
@@ -5,4 +5,8 @@
 
 int markdown(lua_State *L);
 
+// return two arrays, one containing filenames for all directories in the dir
+// and the other containing filenames for all regular files
+int scan_directory(lua_State *L);
+
 #endif
-- 
cgit v1.2.1