summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-04-13 12:29:32 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2021-04-13 12:29:32 -0400
commit69789c042460e012ec3054cc2e6ceeff25e394b9 (patch)
tree0bb6fcd54a4e0f85ba430a2e3e2c54af258d797d
parent2007d299916be6b079e6b97aea7c4d2835e23bd0 (diff)
change fs_list_directory to include entry types directly
-rw-r--r--filesystem-posix.c70
-rw-r--r--filesystem-win.c26
-rw-r--r--filesystem.h13
-rw-r--r--main.c2
-rw-r--r--ui.c13
5 files changed, 79 insertions, 45 deletions
diff --git a/filesystem-posix.c b/filesystem-posix.c
index 8af0bf2..6a52732 100644
--- a/filesystem-posix.c
+++ b/filesystem-posix.c
@@ -4,16 +4,21 @@
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
+
+static FsType statbuf_path_type(const struct stat *statbuf) {
+ if (S_ISREG(statbuf->st_mode))
+ return FS_FILE;
+ if (S_ISDIR(statbuf->st_mode))
+ return FS_DIRECTORY;
+ return FS_OTHER;
+}
FsType fs_path_type(char const *path) {
struct stat statbuf = {0};
if (stat(path, &statbuf) != 0)
return FS_NON_EXISTENT;
- if (S_ISREG(statbuf.st_mode))
- return FS_FILE;
- if (S_ISDIR(statbuf.st_mode))
- return FS_DIRECTORY;
- return FS_OTHER;
+ return statbuf_path_type(&statbuf);
}
FsPermission fs_path_permission(char const *path) {
@@ -28,32 +33,49 @@ bool fs_file_exists(char const *path) {
return fs_path_type(path) == FS_FILE;
}
-char **fs_list_directory(char const *dirname) {
- char **ret = NULL;
+FsDirectoryEntry **fs_list_directory(char const *dirname) {
+ FsDirectoryEntry **entries = NULL;
DIR *dir = opendir(dirname);
if (dir) {
struct dirent *ent;
- char **filenames = NULL;
size_t nentries = 0;
- size_t filename_idx = 0;
-
- while (readdir(dir)) ++nentries;
- rewinddir(dir);
- filenames = (char **)calloc(nentries+1, sizeof *filenames);
-
- while ((ent = readdir(dir))) {
- char const *filename = ent->d_name;
- size_t len = strlen(filename);
- char *filename_copy = (char *)malloc(len+1);
- if (!filename_copy) break;
- strcpy(filename_copy, filename);
- if (filename_idx < nentries) // this could actually fail if someone creates files between calculating nentries and here.
- filenames[filename_idx++] = filename_copy;
+ int fd = dirfd(dir);
+ if (fd != -1) {
+ while (readdir(dir)) ++nentries;
+ rewinddir(dir);
+ entries = (FsDirectoryEntry **)calloc(nentries+1, sizeof *entries);
+ if (entries) {
+ size_t idx = 0;
+ while ((ent = readdir(dir))) {
+ char const *filename = ent->d_name;
+ size_t len = strlen(filename);
+ FsDirectoryEntry *entry = (FsDirectoryEntry *)calloc(1, sizeof *entry + len + 1);
+ if (!entry) break;
+ memcpy(entry->name, filename, len);
+ switch (ent->d_type) {
+ case DT_REG:
+ entry->type = FS_FILE;
+ break;
+ case DT_DIR:
+ entry->type = FS_DIRECTORY;
+ break;
+ case DT_LNK: // we need to dereference the link
+ case DT_UNKNOWN: { // information not available directly from dirent, we need to get it ourselves
+ struct stat statbuf = {0};
+ fstatat(fd, filename, &statbuf, 0);
+ entry->type = statbuf_path_type(&statbuf);
+ } break;
+ default:
+ entry->type = FS_OTHER;
+ }
+ if (idx < nentries) // this could actually fail if someone creates files between calculating nentries and here.
+ entries[idx++] = entry;
+ }
+ }
}
- ret = filenames;
closedir(dir);
}
- return ret;
+ return entries;
}
int fs_mkdir(char const *path) {
diff --git a/filesystem-win.c b/filesystem-win.c
index c6c64dd..d0aef37 100644
--- a/filesystem-win.c
+++ b/filesystem-win.c
@@ -25,9 +25,9 @@ bool fs_file_exists(char const *path) {
return fs_path_type(path) == FS_FILE;
}
-char **fs_list_directory(char const *dirname) {
+FsDirectoryEntry **fs_list_directory(char const *dirname) {
char file_pattern[256] = {0};
- char **ret = NULL;
+ FsDirectoryEntry **files = NULL;
WIN32_FIND_DATA find_data;
HANDLE fhandle;
assert(*dirname);
@@ -43,25 +43,33 @@ char **fs_list_directory(char const *dirname) {
}
FindClose(fhandle);
// now, fill out files array
- files = malloc((nfiles + 1) * sizeof *files);
+ files = calloc(nfiles + 1, sizeof *files);
if (files) {
fhandle = FindFirstFileA(file_pattern, &find_data);
if (fhandle != INVALID_HANDLE_VALUE) {
do {
if (idx < nfiles) {
- char *dup = _strdup(find_data.cFileName);
- if (dup) {
- files[idx++] = dup;
+ const char *filename = find_data.cFileName;
+ size_t len = strlen(filename);
+ FsDirectoryEntry *entry = calloc(1, sizeof *entry + len + 1);
+ if (entry) {
+ DWORD attrs = find_data.dwFileAttributes;
+ if (attrs & FILE_ATTRIBUTE_NORMAL)
+ entry->type = FS_FILE;
+ else if (attrs & FILE_ATTRIBUTE_DIRECTORY)
+ entry->type = FS_DIRECTORY;
+ else
+ entry->type = FS_OTHER;
+ memcpy(entry->name, filename, len);
+ files[idx++] = entry;
} else break; // stop now
}
} while (FindNextFile(fhandle, &find_data));
- files[idx] = NULL;
FindClose(fhandle);
- ret = files;
}
}
}
- return ret;
+ return files;
}
int fs_mkdir(char const *path) {
diff --git a/filesystem.h b/filesystem.h
index 6325bd7..be57323 100644
--- a/filesystem.h
+++ b/filesystem.h
@@ -14,15 +14,20 @@ enum {
};
typedef u8 FsPermission;
+typedef struct {
+ FsType type;
+ char name[];
+} FsDirectoryEntry;
+
// returns what kind of thing this is.
FsType fs_path_type(char const *path);
FsPermission fs_path_permission(char const *path);
// Does this file exist? Returns false for directories.
bool fs_file_exists(char const *path);
-// Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist.
-// When you're done with the file names, call free on each one, then on the array.
-// NOTE: The files aren't returned in any particular order!
-char **fs_list_directory(char const *dirname);
+// Returns a NULL-terminated array of the files/directories in this directory, or NULL if the directory does not exist/out of memory.
+// When you're done with the entries, call free on each one, then on the array.
+// NOTE: The files/directories aren't returned in any particular order!
+FsDirectoryEntry **fs_list_directory(char const *dirname);
// Create the directory specified by `path`
// Returns:
// 1 if the directory was created successfully
diff --git a/main.c b/main.c
index 0b9aaef..1f8a13b 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,6 @@
// @TODO:
// - terminate process not working on windows?
-// - auto-regenerate tags (if no tag found/line number tag found)
+// - auto-regenerate tags (if tag not found)
// - comment/uncomment selection
#include "base.h"
no_warn_start
diff --git a/ui.c b/ui.c
index a01b99f..dc413c3 100644
--- a/ui.c
+++ b/ui.c
@@ -152,7 +152,7 @@ static void selector_render(Ted *ted, Selector *s) {
// clear the entries in the file selector
static void file_selector_clear_entries(FileSelector *fs) {
for (u32 i = 0; i < fs->n_entries; ++i) {
- free(fs->entries[i].name);
+ free(fs->entries[i].name - offsetof(FsDirectoryEntry, name)); // yes this is kinda hacky; oh well
free(fs->entries[i].path);
}
free(fs->entries);
@@ -400,7 +400,7 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) {
// free previous entries
file_selector_clear_entries(fs);
// get new entries
- char **files;
+ FsDirectoryEntry **files;
// if the directory we're in gets deleted, go back a directory.
for (u32 i = 0; i < 100; ++i) {
files = fs_list_directory(cwd);
@@ -423,9 +423,9 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) {
bool increment = true;
for (u32 i = 0; i < nfiles; i += increment, increment = true) {
// remove if the file name does not contain the search term,
- bool remove = search_term && *search_term && !stristr(files[i], search_term);
+ bool remove = search_term && *search_term && !stristr(files[i]->name, search_term);
// or if this is just the current directory
- remove |= streq(files[i], ".");
+ remove |= streq(files[i]->name, ".");
if (remove) {
// remove this one
free(files[i]);
@@ -444,8 +444,9 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) {
if (fs->sel.cursor >= fs->n_entries) fs->sel.cursor = nfiles - 1;
fs->entries = entries;
for (u32 i = 0; i < nfiles; ++i) {
- char *name = files[i];
+ char *name = files[i]->name;
entries[i].name = name;
+ entries[i].type = files[i]->type;
// add cwd to start of file name
size_t path_size = strlen(name) + strlen(cwd) + 3;
char *path = ted_calloc(ted, 1, path_size);
@@ -454,10 +455,8 @@ static char *file_selector_update(Ted *ted, FileSelector *fs) {
cwd[strlen(cwd) - 1] == PATH_SEPARATOR ? "" : PATH_SEPARATOR_STR,
name);
entries[i].path = path;
- entries[i].type = fs_path_type(path);
} else {
entries[i].path = NULL; // what can we do?
- entries[i].type = FS_NON_EXISTENT;
}
}
}