Welcome to little lamb

Code » limb » commit 1271e84

Add salsat(), plus salst() and salstat() macros

author Olivier Brunel
2023-02-28 09:03:10 UTC
committer Olivier Brunel
2023-02-28 09:25:54 UTC
parent 1613caef547c935d4d33d8022bd4e46a356d6b2c

Add salsat(), plus salst() and salstat() macros

Add salsat() to append directory listing into an stralloc, similar to
sals(3) only with a fd for interpreting relative path relative to the
opened directory instead of cwd.

Also add macros salst() & salstat() (to sals() and salsat() resp.) with
offer a slightly different interface, namely put the stralloc argument
first.

doc/salsat.3.md +52 -0
include/limb/djbunix.h +4 -0
meta/libs/limb +1 -0
src/salsat.c +48 -0

diff --git a/doc/salsat.3.md b/doc/salsat.3.md
new file mode 100644
index 0000000..709c966
--- /dev/null
+++ b/doc/salsat.3.md
@@ -0,0 +1,52 @@
+% limb manual
+% salsat(3)
+
+# NAME
+
+salsat, salst, salstat - append directory listing into an stralloc
+
+# SYNOPSIS
+
+    #include <limb/djbunix.h>
+
+```pre hl
+int salsat(int <em>fd</em>, const char *<em>name</em>, stralloc *<em>sa</em>, size_t *<em>maxlen</em>)
+
+int salst(stralloc *<em>sa</em>, const char *<em>name</em>, size_t *<em>maxlen</em>)
+int salstat(stralloc *<em>sa</em>, int <em>fd</em>, const char *<em>name</em>, size_t *<em>maxlen</em>)
+```
+
+# DESCRIPTION
+
+The `salsat`() function appends the names of all files (except for `.` and `..`)
+in directory `name` into the specified stralloc `sa` as NUL-terminated strings.
+
+It is the equivalent to [sals](3) function except when `name` specifies a
+relative path, the directory to be opened is then determined relative to the
+directory associated with the file descriptor `fd` instead of the current
+working directory.
+
+If not NULL, `maxlen` will be set to the length of the longest file name added.
+(It will be 0 in case of empty directory.)
+
+`salst`() is a macro to [sals](3) with a slightly different interface, namely
+the stralloc `sa` as first argument.
+
+Similarly, `salstat`() is a macro to [salsat](3) with a slightly different
+interface as well.
+
+# RETURN VALUE
+
+Upon successful completion, the `salsat` functions returns the number of names
+added into `sa`. Otherwise, it returns -1 and sets `errno` to indicate the
+error.
+
+# ERRORS
+
+The `salsat`() function may fail if :
+
+: *ENOMEM*
+:: Out of memory to add names into `sa`
+
+It may also fail and set errno for any of the errors specified for the
+functions [opendirat](3) and [readdir](3).
diff --git a/include/limb/djbunix.h b/include/limb/djbunix.h
index 7c67b6f..54423f2 100644
--- a/include/limb/djbunix.h
+++ b/include/limb/djbunix.h
@@ -3,6 +3,10 @@
 
 #include <skalibs/stralloc.h>
 
+extern int salsat(int fd, const char *name, stralloc *sa, size_t *maxlen);
 extern int sareadlinkat(stralloc *sa, int fd, const char * restrict file);
 
+#define salst(sa,name,maxlen)       sals(name, sa,maxlen)
+#define salstat(sa,fd,name,maxlen)  salsat(fd, name, sa, maxlen)
+
 #endif /* LIMB_DJBUNIX_H */
diff --git a/meta/libs/limb b/meta/libs/limb
index 7883419..afdaa12 100644
--- a/meta/libs/limb
+++ b/meta/libs/limb
@@ -8,6 +8,7 @@ obj/open_exclat.o
 # direntry.h
 obj/opendirat.o
 # djbunix.h
+obj/salsat.o
 obj/sareadlinkat.o
 # buffer.h
 obj/buffer_putescall.o
diff --git a/src/salsat.c b/src/salsat.c
new file mode 100644
index 0000000..c334b84
--- /dev/null
+++ b/src/salsat.c
@@ -0,0 +1,48 @@
+#include <errno.h>
+#include <dirent.h>
+#include "limb/direntry.h"
+#include "limb/djbunix.h"
+
+int
+salsat(int fd, const char *name, stralloc *sa, size_t *mlen)
+{
+    size_t salen = sa->len;
+    size_t maxlen = 0;
+    int ret = 0;
+    DIR *dir = opendirat(fd, name);
+
+    if (!dir)
+        return (errno == ENOENT) ? 0 : -1;
+
+    for (;;)
+    {
+        direntry *de;
+
+        errno = 0;
+        de = readdir(dir);
+        if (!de)
+            break;
+
+        if (de->d_name[0] == '.') {
+            if (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))
+                continue;
+        }
+
+        size_t len = strlen(de->d_name);
+        if (len > maxlen)
+            maxlen = len;
+
+        if (!stralloc_catb(sa, de->d_name, len + 1))
+            break;
+
+        ++ret;
+    }
+    if (errno) {
+        ret = -1;
+        sa->len = salen;
+    } else if (mlen)
+        *mlen = maxlen;
+
+    dir_close(dir);
+    return ret;
+}