Welcome to little lamb

Code » limb » commit 7c125f0

Add first code & doc

author Olivier Brunel
2023-01-16 16:05:51 UTC
committer Olivier Brunel
2023-01-16 20:40:54 UTC
parent be0977a859fa86455d621a7149d4c4657d61478c

Add first code & doc

.gitignore +3 -0
doc/die.3.md +58 -0
doc/open_createat.3.md +37 -0
doc/open_exclat.3.md +37 -0
doc/out.3.md +39 -0
doc/put.3.md +46 -0
doc/ret.3.md +28 -0
doc/warn.3.md +34 -0
include/limb/output.h +55 -0
include/limb/unix-transactional.h +9 -0
meta/deps-lib +1 -0
meta/deps/comain/version +1 -1
meta/deps/skalibs/get_version +2 -0
meta/deps/skalibs/git +1 -0
meta/deps/skalibs/incdir +1 -0
meta/deps/skalibs/include +0 -0
meta/deps/skalibs/libdir +1 -0
meta/deps/skalibs/library +1 -0
meta/deps/skalibs/version +1 -0
meta/desc +7 -0
project.mk +1 -7
src/open_createat.c +9 -0
src/open_exclat.c +9 -0
src/openc_createat.c +9 -0
src/openc_exclat.c +9 -0
src/put.c +34 -0

diff --git a/.gitignore b/.gitignore
index 7ccd516..fe2f03b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,6 @@
 *.o
 *.lo
 *.d
+liblimb.a
+liblimb.so
+/skalibs
diff --git a/doc/die.3.md b/doc/die.3.md
new file mode 100644
index 0000000..79eb6fe
--- /dev/null
+++ b/doc/die.3.md
@@ -0,0 +1,58 @@
+% limb manual
+% die(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+die, dief, diefu, diesys, diefsys, diefusys - write a message to stderr and terminate
+
+# SYNOPSIS
+
+    #include <limb/output.h>
+    extern const char *PROG;
+
+```pre hl
+void die(<em>e</em>, ...)
+void dief(<em>e</em>, ...)
+void diefu(<em>e</em>, ...)
+void diesys(<em>e</em>, ...)
+void diefsys(<em>e</em>, ...)
+void diefusys(<em>e</em>, ...)
+
+void dieusage(<em>e</em>, <em>usage</em>)
+void diehelp(<em>e</em>, <em>usage</em>, <em>help</em>)
+
+void dieversion(<em>version</em>, <em>year1</em>, <em>year2</em>, <em>author</em>, <em>url</em>, <em>license</em>)
+```
+
+# DESCRIPTION
+
+All of those are implemented as macros (to [put](3)) and will write the
+specified strings to /stderr/, with a new line added at the end, then terminate
+the calling process via [_exit](3) using `e`.
+
+All messages will be prefixed by the program's name (i.e. value of `PROG`), a
+colon and a space.
+
+`dief`() will add "fatal: " after the prefix and before the given strings.
+
+`diefu`() will also add "unable to " before the specified strings.
+
+The `diesys`(), `diefsys`() and `diefusys`() macros are similar, only the
+specified strings will be followed by a colon, a space and the error description
+provided by [strerror](3) according to `errno`.
+
+
+The `dieusage`() macro writes the word "usage: " followed by the program's name
+and a space as prefix, then the `usage` string.
+
+The `diehelp`() macro is similar to `dieusage`(), only adding two new lines
+followed by the string `help`.
+
+The `dieversion`() macro writes the program's name (i.e. value of `PROG`), the
+string " version " then the specified `version` and a new line.
+On a second line is written "Copyright (C) " then `year1`, followed by a dash
+and `year2` if it differs from `year1`, then ' - ' followed by `url`
+Lastly, if `license` is not `NULL` it is written, else on a new line a line for
+"License GPL-2.0" is written.
diff --git a/doc/open_createat.3.md b/doc/open_createat.3.md
new file mode 100644
index 0000000..edc0f45
--- /dev/null
+++ b/doc/open_createat.3.md
@@ -0,0 +1,37 @@
+% limb manual
+% open_createat(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+open_createat, openc_createat - open file relative to directory file descriptor
+
+# SYNOPSIS
+
+    #include <limb/unix-transactional.h>
+
+```pre hl
+int open_createat(int <em>fd</em>, const char *<em>file</em>);
+int openc_createat(int <em>fd</em>, const char *<em>file</em>);
+```
+
+# DESCRIPTION
+
+The `open_createat`() function opens a file for writing, creating it if it
+doesn't exist, in non-blocking mode.
+
+The `openc_createat`() function is similar, only with the *FD_CLOEXEC* flag set
+for the file descriptor.
+
+# RETURN VALUE
+
+Upon successful completion, these functions shall open the file and return a
+non-negative integer representing the lowest numbered unused file descriptor.
+Otherwise, these functions shall return -1 and set errno to indicate the error.
+If -1 is returned, no files shall be created or modified.
+
+# ERRORS
+
+These functions may fail and set errno for any of the errors specified for the
+routine [openat](2).
diff --git a/doc/open_exclat.3.md b/doc/open_exclat.3.md
new file mode 100644
index 0000000..f92f94a
--- /dev/null
+++ b/doc/open_exclat.3.md
@@ -0,0 +1,37 @@
+% limb manual
+% open_exclat(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+open_exclat, openc_exclat - create file relative to directory file descriptor
+
+# SYNOPSIS
+
+    #include <limb/unix-transactional.h>
+
+```pre hl
+int open_exclat(int <em>fd</em>, const char *<em>file</em>);
+int openc_exclat(int <em>fd</em>, const char *<em>file</em>);
+```
+
+# DESCRIPTION
+
+The `open_exclat`() function attempts to create a new file and open it for
+writing, in non-blocking mode, failing with *EEXIST* if it already exists.
+
+The `openc_exclat`() function is similar, only with the *FD_CLOEXEC* flag set
+for the file descriptor.
+
+# RETURN VALUE
+
+Upon successful completion, these functions shall open the file and return a
+non-negative integer representing the lowest numbered unused file descriptor.
+Otherwise, these functions shall return -1 and set errno to indicate the error.
+If -1 is returned, no files shall be created or modified.
+
+# ERRORS
+
+These functions may fail and set errno for any of the errors specified for the
+routine [openat](2).
diff --git a/doc/out.3.md b/doc/out.3.md
new file mode 100644
index 0000000..ba7b22c
--- /dev/null
+++ b/doc/out.3.md
@@ -0,0 +1,39 @@
+% limb manual
+% out(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+out, err, sys, outdie, errdie, sysdie - write text to standard output/error (and terminate process)
+
+# SYNOPSIS
+
+    #include <limb/output.h>
+
+```pre hl
+void out(...)
+void err(...)
+void sys(...)
+
+void outdie(<em>e</em>, ...)
+void errdie(<em>e</em>, ...)
+void sysdie(<em>e</em>, ...)
+```
+
+# DESCRIPTION
+
+All of those are implemented as macros (to [put](3)) and will write to
+either standard outpout or standard error, then maybe terminate the calling
+process or return.
+
+The macro `out`() writes given strings to /stdout/.
+
+The macro `err`() writes given strings to /stderr/.
+
+The macro `sys`() is similar to `err`() put will add a colon, a space and the
+error description from [strerror](3) on `errno`.
+
+Macros `outdie`(), `errdie`() and `sysdie`() are similar to `out`(), `err`() and
+`sys`() respectively but will terminate the calling process (via [_exit](3)
+using `e`).
diff --git a/doc/put.3.md b/doc/put.3.md
new file mode 100644
index 0000000..de872c5
--- /dev/null
+++ b/doc/put.3.md
@@ -0,0 +1,46 @@
+% limb manual
+% put(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+put - write text to standard output/error
+
+# SYNOPSIS
+
+    #include <limb/output.h>
+
+```pre hl
+void put(int <em>ret</em>, unsigned int <em>opts</em>, const char * const *<em>as</em>, unsigned int <em>n</em>)
+```
+
+# DESCRIPTION
+
+The `put`() function will write `n` strings, given in the array `as`, either to
+/stdout/ (by default) or /stderr/ if `PUT_ERR` was given in `opts`.
+
+If `PUT_SYS` was specified, a suffix composed of a colon and a space is added,
+followed by the text return by [strerror](3) for `errno`.
+
+A new line is always added at the end.
+
+If `PUT_DIE` was specified, the program then ends - calling [_exit](3) with
+the value of `ret`.
+
+# FLAGS
+
+Values for `opts` are constructed by a bitwise-inclusive OR of flags from the
+following list :
+
+: `PUT_OUT`
+:: Write to standard output. This is the default, unless `PUT_ERR` is specified.
+
+: `PUT_ERR`
+:: Write to standard error.
+
+: `PUT_SYS`
+:: Append a colon, a space, and the error string computed from `errno`
+
+: `PUT_DIE`
+:: Terminate the calling process, returning `ret & 0377` as exit status 
diff --git a/doc/ret.3.md b/doc/ret.3.md
new file mode 100644
index 0000000..c050fd5
--- /dev/null
+++ b/doc/ret.3.md
@@ -0,0 +1,28 @@
+% limb manual
+% ret(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+retw, retw, retwsys, retwusys - write a warning to standard error and return
+
+# SYNOPSIS
+
+    #include <limb/output.h>
+    extern const char *PROG;
+
+```pre hl
+int retw(<em>r</em>, ...)
+int retwu(<em>r</em>, ...)
+int retwsys(<em>r</em>, ...)
+int retwusys(<em>r</em>, ...)
+```
+
+# DESCRIPTION
+
+All of those are implemented as macros to write the specified strings as warning
+to /stderr/ with a new line added at the end (via [put](3)), then return `r`.
+
+All of then actually use [warn](3), [warnu](3), [warnsys](3) and [warnusys](3)
+macros before calling `return r`.
diff --git a/doc/warn.3.md b/doc/warn.3.md
new file mode 100644
index 0000000..3216978
--- /dev/null
+++ b/doc/warn.3.md
@@ -0,0 +1,34 @@
+% limb manual
+% warn(3)
+% limb 0.0.1
+% 2023.01.16
+
+# NAME
+
+warn, warnu, warnsys, warnusys - write a warning to standard error
+
+# SYNOPSIS
+
+    #include <limb/output.h>
+    extern const char *PROG;
+
+```pre hl
+void warn(..)
+void warnu(...)
+void warnsys(...)
+void warnusys(...)
+```
+
+# DESCRIPTION
+
+All of those are implemented as macros (to [put](3)) and will write the
+specified strings as warning to /stderr/, with a new line added at the end.
+
+All warnings will be prefixed by the program's name (i.e. value of `PROG`), the
+word "warning " in between colon and a space.
+
+`warnu`() will add "unable to " after the prefix and before the given strings.
+
+The `warnsys`() and `warnusys`() macros are similar, only the specified strings
+will be followed by a colon, a space and the error description provided by
+[strerror](3) according to `errno`.
diff --git a/include/limb/output.h b/include/limb/output.h
new file mode 100644
index 0000000..45d5094
--- /dev/null
+++ b/include/limb/output.h
@@ -0,0 +1,55 @@
+#ifndef LIMB_OUTPUT_H
+#define LIMB_OUTPUT_H
+
+enum {
+    PUT_OUT     =  0, /* implied default unless PUT_ERR is set */
+    PUT_ERR     = (1 << 0),
+    PUT_SYS     = (1 << 1),
+    PUT_DIE     = (1 << 2),
+};
+
+extern void put(int e, unsigned int opts, const char * const *as, unsigned int n);
+
+extern const char *PROG;
+
+#define outarray(...)       ((char const * const []) {__VA_ARGS__})
+#define outalen(...)        (sizeof(outarray(__VA_ARGS__)) / sizeof(char const *))
+
+#define out(...)            put(0, PUT_OUT, outarray(__VA_ARGS__), outalen(__VA_ARGS__))
+#define err(...)            put(0, PUT_ERR, outarray(__VA_ARGS__), outalen(__VA_ARGS__))
+#define sys(...)            put(0, PUT_ERR | PUT_SYS, outarray(__VA_ARGS__), outalen(__VA_ARGS__))
+#define outdie(e, ...)      put(e, PUT_OUT | PUT_DIE, outarray(__VA_ARGS__), outalen(__VA_ARGS__))
+#define errdie(e, ...)      put(e, PUT_ERR | PUT_DIE, outarray(__VA_ARGS__), outalen(__VA_ARGS__))
+#define sysdie(e, ...)      put(e, PUT_ERR | PUT_SYS | PUT_DIE, outarray(__VA_ARGS__), outalen(__VA_ARGS__))
+
+#define warn(...)           err(PROG, ": warning: ", __VA_ARGS__)
+#define warnu(...)          warn("unable to ", __VA_ARGS__)
+#define warnsys(...)        sys(PROG, ": warning: ", __VA_ARGS__)
+#define warnusys(...)       warnsys("unable to ", __VA_ARGS__)
+
+#define die(e, ...)         errdie(e, PROG, ": ", __VA_ARGS__)
+#define dief(e, ...)        die(e, "fatal: ", __VA_ARGS__)
+#define diefu(e, ...)       dief(e, "unable to ", __VA_ARGS__)
+#define diesys(e, ...)      sysdie(e, PROG, ": ", __VA_ARGS__)
+#define diefsys(e, ...)     diesys(e, "fatal: ", __VA_ARGS__)
+#define diefusys(e, ...)    diefsys(e, "unable to ", __VA_ARGS__)
+
+#define dieusage(e, u)      errdie(e, "usage: ", PROG, " ", u)
+#define diehelp(e, u, h)    errdie(e, "usage: ", PROG, " ", u, "\n\n", h)
+
+#define dieversion(v , yb, ye, a, u, l) \
+                            outdie(0, PROG, " version ", v, "\n", \
+                                   "Copyright (C) ", yb, \
+                                   ((strcmp(yb, ye)) ? "-" : ""), \
+                                   ((strcmp(yb, ye)) ? ye : ""), \
+                                   " ", a, " - ", u, \
+                                   (!l) ? "\nLicense GPL-2.0. This is free software: " \
+                                   "you are free to change and redistribute it.\n" \
+                                   "There is NO WARRANTY, to the extent permitted by law." : l)
+
+#define retw(r, ...)        do { warn(__VA_ARGS__);        return r; } while (0)
+#define retwu(r, ...)       do { warnu(__VA_ARGS__);       return r; } while (0)
+#define retwsys(r, ...)     do { warnsys(__VA_ARGS__);     return r; } while (0)
+#define retwusys(r, ...)    do { warnusys(__VA_ARGS__);    return r; } while (0)
+
+#endif /* LIMB_OUTPUT_H */
diff --git a/include/limb/unix-transactional.h b/include/limb/unix-transactional.h
new file mode 100644
index 0000000..9a5a8f1
--- /dev/null
+++ b/include/limb/unix-transactional.h
@@ -0,0 +1,9 @@
+#ifndef LIMB_UNIXTRANSACTIONAL_H
+#define LIMB_UNIXTRANSACTIONAL_H
+
+extern int openc_createat(int fd, const char *file);
+extern int open_createat(int fd, const char *file);
+extern int openc_exclat(int fd, const char *file);
+extern int open_exclat(int fd, const char *file);
+
+#endif /* LIMB_UNIXTRANSACTIONAL_H */
diff --git a/meta/deps-lib b/meta/deps-lib
new file mode 100644
index 0000000..a8be909
--- /dev/null
+++ b/meta/deps-lib
@@ -0,0 +1 @@
+limb: src/put.o src/open_exclat.o src/open_createat.o src/openc_exclat.o src/openc_createat.o skalibs
diff --git a/meta/deps/comain/version b/meta/deps/comain/version
index 77d6f4c..8acdd82 100644
--- a/meta/deps/comain/version
+++ b/meta/deps/comain/version
@@ -1 +1 @@
-0.0.0
+0.0.1
diff --git a/meta/deps/skalibs/get_version b/meta/deps/skalibs/get_version
new file mode 100755
index 0000000..55041f5
--- /dev/null
+++ b/meta/deps/skalibs/get_version
@@ -0,0 +1,2 @@
+#!/bin/sh
+grep SKALIBS_VERSION "$@/skalibs/config.h" | cut -d\" -f2
diff --git a/meta/deps/skalibs/git b/meta/deps/skalibs/git
new file mode 100644
index 0000000..5965139
--- /dev/null
+++ b/meta/deps/skalibs/git
@@ -0,0 +1 @@
+git://lila.oss/skalibs.git
diff --git a/meta/deps/skalibs/incdir b/meta/deps/skalibs/incdir
new file mode 100644
index 0000000..e4484e2
--- /dev/null
+++ b/meta/deps/skalibs/incdir
@@ -0,0 +1 @@
+src/include
diff --git a/meta/deps/skalibs/include b/meta/deps/skalibs/include
new file mode 100644
index 0000000..e69de29
diff --git a/meta/deps/skalibs/libdir b/meta/deps/skalibs/libdir
new file mode 100644
index 0000000..5baacc7
--- /dev/null
+++ b/meta/deps/skalibs/libdir
@@ -0,0 +1 @@
+skalibs
diff --git a/meta/deps/skalibs/library b/meta/deps/skalibs/library
new file mode 100644
index 0000000..39971a0
--- /dev/null
+++ b/meta/deps/skalibs/library
@@ -0,0 +1 @@
+skarnet
diff --git a/meta/deps/skalibs/version b/meta/deps/skalibs/version
new file mode 100644
index 0000000..0ab9020
--- /dev/null
+++ b/meta/deps/skalibs/version
@@ -0,0 +1 @@
+2.8.0.0
diff --git a/meta/desc b/meta/desc
new file mode 100644
index 0000000..71dcfbd
--- /dev/null
+++ b/meta/desc
@@ -0,0 +1,7 @@
+lila's core library
+
+A simple C library (based on [skalibs]) with common APIs used by all lila's
+software.
+
+
+[skalibs]: https://skarnet.org/software/skalibs
diff --git a/project.mk b/project.mk
index 0892fd9..63a3fe3 100644
--- a/project.mk
+++ b/project.mk
@@ -1,7 +1 @@
-$(error You need to edit project.mk)
-
-# binaries: -- don't forget to set meta/deps-bin with all deps & .o files
-BINS = 
-
-# librairies -- don't forget to set meta/deps-lib with all deps & .o files
-LIBS = 
+LIBS = limb
diff --git a/src/open_createat.c b/src/open_createat.c
new file mode 100644
index 0000000..fcc59fc
--- /dev/null
+++ b/src/open_createat.c
@@ -0,0 +1,9 @@
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+#include "limb/unix-transactional.h"
+
+int
+open_createat(int fd, const char *file)
+{
+    return open3_at(fd, file, O_WRONLY | O_CREAT | O_NONBLOCK, 0666);
+}
diff --git a/src/open_exclat.c b/src/open_exclat.c
new file mode 100644
index 0000000..bf5f89e
--- /dev/null
+++ b/src/open_exclat.c
@@ -0,0 +1,9 @@
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+#include "limb/unix-transactional.h"
+
+int
+open_exclat(int fd, const char *file)
+{
+    return open3_at(fd, file, O_WRONLY | O_CREAT | O_EXCL | O_NONBLOCK, 0666);
+}
diff --git a/src/openc_createat.c b/src/openc_createat.c
new file mode 100644
index 0000000..aca4886
--- /dev/null
+++ b/src/openc_createat.c
@@ -0,0 +1,9 @@
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+#include "limb/unix-transactional.h"
+
+int
+openc_createat(int fd, const char *file)
+{
+    return open3_at(fd, file, O_WRONLY | O_CREAT | O_NONBLOCK | O_CLOEXEC, 0666);
+}
diff --git a/src/openc_exclat.c b/src/openc_exclat.c
new file mode 100644
index 0000000..e3066b9
--- /dev/null
+++ b/src/openc_exclat.c
@@ -0,0 +1,9 @@
+#include <fcntl.h>
+#include <skalibs/unix-transactional.h>
+#include "limb/unix-transactional.h"
+
+int
+openc_exclat(int fd, const char *file)
+{
+    return open3_at(fd, file, O_WRONLY | O_CREAT | O_EXCL | O_NONBLOCK | O_CLOEXEC, 0666);
+}
diff --git a/src/put.c b/src/put.c
new file mode 100644
index 0000000..018d69f
--- /dev/null
+++ b/src/put.c
@@ -0,0 +1,34 @@
+#include <errno.h>
+#include <unistd.h> /* _exit() */
+#include <skalibs/buffer.h>
+#include <skalibs/strerr.h>
+#include "limb/output.h"
+
+void
+put(int r, unsigned int opts, const char * const *as, unsigned int n)
+{
+    int e = errno;
+    buffer *b = (opts & PUT_ERR) ? buffer_2 : buffer_1;
+
+    for(;;) {
+        unsigned int i;
+        for (i = 0; i < n; ++i)
+            if (as[i] && as[i][0] && !buffer_puts(b, as[i]))
+                break;
+        if (i < n)
+            break;
+
+        if ((opts & PUT_SYS)
+                && (!buffer_put(b, ": ", 2) || !buffer_puts(b, strerror(e)))
+           )
+            break;
+
+        if (!buffer_putflush(b, "\n", 1))
+            break;
+
+        errno = e;
+        if (opts & PUT_DIE) _exit(r);
+        return;
+    }
+    strerr_die6sys(55, PROG, ": fatal: ", "unable to ", "print to ", (opts & PUT_ERR) ? "stderr" : "stdout", ": ");
+}