Welcome to little lamb

Code » limb » commit 61a448e

Add obuffers.h and related functions

author Olivier Brunel
2023-03-21 18:31:01 UTC
committer Olivier Brunel
2023-03-21 18:31:01 UTC
parent 3c31dae50b5449e818d49bbbd12d96f17c8c5717

Add obuffers.h and related functions

These are what will be used from output.h macros. They allow to easily
send/write "messages" (an array of strings) to a buffer, given that the
message's level is the same or lower than the buffer's.

Additionally, out_putmsg() and err_putmsg() will write respectively to
obuffer_1 (wrapper around buffer_1) and obuffer_2 (wrapper around
buffer_2), as well as all the extra output buffers set up (if any).

The idea is that one can easily add such buffers (e.g. via
obuffers_addlog() for simply duplicating stdout/stderr, or via
obuffers_adddbg() to do so on a buffer at OLVL_DEBUG, thus easily having
an output for a debugging log) and any and all messages will
automatically be duplicated/sent to all applicable buffers at once.

doc/obuffers.h.0.md +67 -0
doc/obuffers_addextra.3.md +42 -0
doc/obuffers_addlog.3.md +51 -0
doc/out_putmsg.3.md +54 -0
include/limb/obuffers.h +33 -0
meta/libs/limb +13 -0
src/dbg_putmsg.c +18 -0
src/err_putmsg.c +13 -0
src/err_putmsgdie.c +12 -0
src/extras_putmsg.c +13 -0
src/obuffers_adddbg.c +18 -0
src/obuffers_addextra.c +18 -0
src/obuffers_addlog.c +18 -0
src/obuffers_remdbg.c +15 -0
src/obuffers_remextra.c +17 -0
src/obuffers_remlog.c +15 -0
src/out_putmsg.c +13 -0
src/out_putmsgdie.c +12 -0

diff --git a/doc/obuffers.h.0.md b/doc/obuffers.h.0.md
new file mode 100644
index 0000000..5ee45b9
--- /dev/null
+++ b/doc/obuffers.h.0.md
@@ -0,0 +1,67 @@
+% limb manual
+% obuffers.h(0)
+
+# NAME
+
+obuffers.h - output buffer interface for stdout/stderr
+
+# SYNOPSIS
+
+    #include <limb/obuffers.h>
+
+# DESCRIPTION
+
+This header defines required functions to write on output buffers for stdout
+and/or stderr.
+
+Two output buffers are set up, `obuffer_1` and `obuffer_2`, to interface
+respectively *stdout* (via `buffer_1`) and *stderr* (via `buffer_2`).
+
+Additionally up to 3 extra output buffers can be set up. Any messages sent to
+*stdout* via [out_putmsg](3), [out_putmsgdie](3) or [dbg_putmsg](3) will also
+be sent to these extra output buffers.
+
+Similarly, any messages sent to *stderr* via [err_putmsg](3) or
+[err_putmsgdie](3) will also be sent to these extra output buffers.
+
+## Functions
+
+The following functions are defined :
+
+: [obuffers_addextra](3)
+:: Set up a new extra output buffer.
+
+: [obuffers_remextra](3)
+:: Remove an extra output buffer.
+
+: [obuffers_addlog](3)
+:: Set up a new extra buffer from the given file descriptor (e.g. to have a log
+: of all stdout/stderr messages)
+
+: [obufers_adddbg](3)
+:: Similar to [obuffers_addlog](3) but this buffer will default to *OLVL_DEBUG*
+
+: [obuffers_remlog](3)
+:: Remove the log buffer from extra output buffers
+
+: [obuffers_remdbg](3)
+:: Remove the debug buffer from extra output buffers
+
+: [extras_putmsg](3)
+:: Send a message to all extra output buffers
+
+: [out_putmsg](3)
+:: Send a message to `obuffer_1` and all extra output buffers
+
+: [err_putmsg](3)
+:: Send a message to `obuffer_2` and all extra output buffers
+
+: [dbg_putmsg](3)
+:: Same as [out_putmsg](3) but prefix the message with the given function name,
+:: file name and line number. Mostly used via [dbg](3)
+
+: [out_putmsgdie](3)
+:: Same as [out_putmsg](3) but terminate process execution afterwards
+
+: [err_putmsgdie](3)
+:: Same as [err_putmsg](3) but terminate process execution afterwards
diff --git a/doc/obuffers_addextra.3.md b/doc/obuffers_addextra.3.md
new file mode 100644
index 0000000..9514b3b
--- /dev/null
+++ b/doc/obuffers_addextra.3.md
@@ -0,0 +1,42 @@
+% limb manual
+% obuffers_addextra(3)
+
+# NAME
+
+obuffers\_addextra, obuffers\_remextra - add/remove an extra output buffer
+
+# SYNOPSIS
+
+    #include <limb/obuffers.h>
+
+```pre hl
+int obuffers_addextra(buffer *<em>buf</em>, u8 <em>level</em>)
+int obuffers_remextra(buffer *<em>buf</em>)
+```
+
+# DESCRIPTION
+
+The `obuffers_addextra`() function will set up a new extra output buffer, using
+the given buffer `buf` (which must be set up for writing), using `level` as the
+buffer's level -- meaning only sent messages with the same level or lower will
+be written into `buf`.
+
+The `obuffers_remextra`() function will remove the extra buffer set up using the
+buffer `buf`.
+
+# RETURN VALUE
+
+These functions returns 1 on success. Otherwise they returns 0 and sets `errno`
+to indicate the error.
+
+# ERRORS
+
+The `obuffers_addextra`() function may fail if :
+
+: *ENOBUFS*
+:: All extra buffers are already set up.
+
+The `obuffers_remextra`() function may fail if :
+
+: *ENOENT*
+:: No extra buffer found using the specified buffer
diff --git a/doc/obuffers_addlog.3.md b/doc/obuffers_addlog.3.md
new file mode 100644
index 0000000..94475d9
--- /dev/null
+++ b/doc/obuffers_addlog.3.md
@@ -0,0 +1,51 @@
+% limb manual
+% obuffers_addlog(3)
+
+# NAME
+
+obuffers\_addlog, obuffers\_adddbg, obuffers\_remlog, obuffers\_remdbg -
+set up/remove an extra buffer from a file descriptor
+
+# SYNOPSIS
+
+    #include <limb/obuffers.h>
+
+```pre hl
+int obuffers_addlog(int <em>fd</em>)
+int obuffers_adddbg(int <em>fd</em>)
+
+int obuffers_remlog(void)
+int obuffers_remdbg(void)
+```
+
+# DESCRIPTION
+
+The `obuffers_addlog`() function will set up an extra buffer, using the given
+file descriptor `fd` which must be opened for writing.
+
+The `obuffers_adddbg`() is similar except that the output buffer will default to
+*OLVL_DEBUG* (instead of *OLVL_NORMAL*), thusly receiving any debug messages
+sent.
+
+The `obuffers_remlog`() function will remove the extra buffer previously set up
+using `obuffers_addlog`().
+
+The `obuffers_remdbg`() function will remove the extra buffer previously set up
+using `obuffers_adddbg`().
+
+# RETURN VALUE
+
+These functions returns 1 on success. Otherwise they returns 0 and sets `errno`
+to indicate the error.
+
+# ERRORS
+
+The `obuffers_addlog`() and `obuffers_adddbg`() functions may fail if :
+
+: *EADDRINUSE*
+:: A buffer was already set up using the same function
+
+They may also fail for any of the errors specified for [obuffers_addextra](3).
+
+The `obuffers_remlog`() and `obuffers_remdbg`() functions may fail for any of
+the errors specified for [obuffers_remextra](3).
diff --git a/doc/out_putmsg.3.md b/doc/out_putmsg.3.md
new file mode 100644
index 0000000..e77a405
--- /dev/null
+++ b/doc/out_putmsg.3.md
@@ -0,0 +1,54 @@
+% limb manual
+% out_putmsg(3)
+
+# NAME
+
+out\_putmsg, err\_putmsg, dbg\_putmsg, extras\_putmsg - write message, given as
+an array of strings, to output buffers for stdout and/or stderr
+
+# SYNOPSIS
+
+    #include <limb/obuffers.h>
+
+```pre hl
+void out_putmsg(u8 <em>level</em>, const char * const *<em>as</em>, unsigned int <em>n</em>)
+void err_putmsg(u8 <em>level</em>, const char * const *<em>as</em>, unsigned int <em>n</em>)
+
+void dbg_putmsg(u8 <em>level</em>, const char *<em>func</em>, const char *<em>file</em>, int <em>line</em>,
+                const char * const *<em>as</em>, unsigned int <em>n</em>)
+
+void extras_putmsg(u8 <em>level</em>, const char * const *<em>as</em>, unsigned int <em>n</em>)
+
+void out_putmsgdie(int <em>exit</em>, u8 <em>level</em>, const char * const *<em>as</em>, unsigned int <em>n</em>)
+void err_putmsgdie(int <em>exit</em>, u8 <em>level</em>, const char * const *<em>as</em>, unsigned int <em>n</em>)
+```
+
+# DESCRIPTION
+
+The `out_putmsg`() function will write the message, given as an array of
+strings `as` of `n` elements, into the output buffer for *stdout* - `obuffer_1`
+- as well as the extra output buffers.
+
+The `err_putmsg`() function is similar, only with the output buffer for *stderr*
+- `obuffer_2` - instead of `obuffer_1`.
+
+The `dbg_putmsg`() function is similar to `out_putmsg`(), but prefixes the
+message with the given function name, file name and line number, resulting in a
+message written in the form:
+
+    [func@file:line] message
+
+It is mostly used via [dbg](3)
+
+
+The `extras_putmsg`() function is similar to `out_putmsg`(), but only for the
+extra output buffers.
+
+
+The `out_putmsgdie`() function is similar to `out_putmsg`(), but it will
+terminate the process execution (via [\_exit](3)) using `exit` as exit status
+code.
+
+The `err_putmsgdie`() function is similar to `err_putmsg`(), but it will
+terminate the process execution (via [\_exit](3)) using `exit` as exit status
+code.
diff --git a/include/limb/obuffers.h b/include/limb/obuffers.h
new file mode 100644
index 0000000..39786e4
--- /dev/null
+++ b/include/limb/obuffers.h
@@ -0,0 +1,33 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LIMB_OBUFFERS_H
+#define LIMB_OBUFFERS_H
+
+#include "limb/obuffer.h"
+
+extern int obuffers_addextra(buffer *b, u8 level);
+extern int obuffers_remextra(buffer *b);
+
+extern int obuffers_addlog(int fd);
+extern int obuffers_adddbg(int fd);
+extern int obuffers_remlog(void);
+extern int obuffers_remdbg(void);
+
+extern void extras_putmsg(u8 level, const char * const *as, unsigned int n);
+extern void out_putmsg(u8 level, const char * const *as, unsigned int n);
+extern void err_putmsg(u8 level, const char * const *as, unsigned int n);
+extern void dbg_putmsg(u8 level, const char *func, const char *file, int line,
+                       const char * const *as, unsigned int n);
+extern void out_putmsgdie(int exit, u8 level, const char * const *as, unsigned int n);
+extern void err_putmsgdie(int exit, u8 level, const char * const *as, unsigned int n);
+
+extern obuffer obuffer_1_;
+#define obuffer_1 (&obuffer_1_)
+
+extern obuffer obuffer_2_;
+#define obuffer_2 (&obuffer_2_)
+
+extern obuffer obuffer_extras[3];
+
+#endif /* LIMB_OBUFFERS_H */
diff --git a/meta/libs/limb b/meta/libs/limb
index da8a1e2..33e34cc 100644
--- a/meta/libs/limb
+++ b/meta/libs/limb
@@ -29,6 +29,19 @@ obj/buffer_putmsg.o
 obj/obuffer_put.o
 obj/obuffer_putmsg.o
 obj/obuffers_putmsg.o
+# obuffers.h
+obj/obuffers_addextra.o
+obj/obuffers_remextra.o
+obj/obuffers_addlog.o
+obj/obuffers_adddbg.o
+obj/obuffers_remlog.o
+obj/obuffers_remdbg.o
+obj/extras_putmsg.o
+obj/out_putmsg.o
+obj/err_putmsg.o
+obj/dbg_putmsg.o
+obj/out_putmsgdie.o
+obj/err_putmsgdie.o
 # find msb
 obj/msb64.o
 # {,un}pack u64
diff --git a/src/dbg_putmsg.c b/src/dbg_putmsg.c
new file mode 100644
index 0000000..6dab03d
--- /dev/null
+++ b/src/dbg_putmsg.c
@@ -0,0 +1,18 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/output.h"
+#include "limb/u32.h"
+
+void
+dbg_putmsg(u8 level, const char *func, const char *file, int line,
+           const char * const *as, unsigned int n)
+{
+    char buf[U32_FMT];
+    buf[u32_fmt(buf, line)] = 0;
+
+    const char *strings[7 + n];
+    memcpy(strings, (const char * const [])  { "[", func, "@", file, ":", buf, "] " }, 7 * sizeof(char *));
+    memcpy(strings + 7, as, n * sizeof(*as));
+    out_putmsg(level, strings, 7 + n);
+}
diff --git a/src/err_putmsg.c b/src/err_putmsg.c
new file mode 100644
index 0000000..680e82e
--- /dev/null
+++ b/src/err_putmsg.c
@@ -0,0 +1,13 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/obuffers.h"
+
+obuffer obuffer_2_ = { buffer_2, OLVL_NORMAL };
+
+void
+err_putmsg(u8 level, const char * const *as, unsigned int n)
+{
+    obuffer_putmsg(obuffer_2, level, as, n);
+    extras_putmsg(level, as, n);
+}
diff --git a/src/err_putmsgdie.c b/src/err_putmsgdie.c
new file mode 100644
index 0000000..108de86
--- /dev/null
+++ b/src/err_putmsgdie.c
@@ -0,0 +1,12 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <unistd.h>
+#include "limb/obuffers.h"
+
+void
+err_putmsgdie(int exit, u8 level, const char * const *as, unsigned int n)
+{
+    err_putmsg(level, as, n);
+    _exit(exit);
+}
diff --git a/src/extras_putmsg.c b/src/extras_putmsg.c
new file mode 100644
index 0000000..2a64d40
--- /dev/null
+++ b/src/extras_putmsg.c
@@ -0,0 +1,13 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/obuffers.h"
+
+obuffer obuffer_extras[3] = { 0 };
+
+void
+extras_putmsg(u8 level, const char * const *as, unsigned int n)
+{
+    obuffers_putmsg(obuffer_extras, sizeof(obuffer_extras) / sizeof(obuffer_extras[0]),
+                    level, as, n);
+}
diff --git a/src/obuffers_adddbg.c b/src/obuffers_adddbg.c
new file mode 100644
index 0000000..6a16f38
--- /dev/null
+++ b/src/obuffers_adddbg.c
@@ -0,0 +1,18 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <errno.h>
+#include "limb/obuffers.h"
+
+static char buf[BUFFER_OUTSIZE];
+buffer buffer_dbg_ = { .fd = -1 };
+
+int
+obuffers_adddbg(int fd)
+{
+    if (buffer_dbg_.fd >= 0)
+        return (errno = EADDRINUSE, 0);
+    if (!buffer_init(&buffer_dbg_, &fd_writev, fd, buf, sizeof(buf)))
+        return 0;
+    return obuffers_addextra(&buffer_dbg_, OLVL_DEBUG);
+}
diff --git a/src/obuffers_addextra.c b/src/obuffers_addextra.c
new file mode 100644
index 0000000..32357ba
--- /dev/null
+++ b/src/obuffers_addextra.c
@@ -0,0 +1,18 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <errno.h>
+#include "limb/obuffers.h"
+
+int
+obuffers_addextra(buffer *b, u8 level)
+{
+    int n = sizeof(obuffer_extras) / sizeof(obuffer_extras[0]);
+    for (int i = 0; i < n; ++i)
+        if (!obuffer_extras[i].b) {
+            obuffer_extras[i].b = b;
+            obuffer_extras[i].lvl = level;
+            return 1;
+        }
+    return (errno = ENOBUFS, 0);
+}
diff --git a/src/obuffers_addlog.c b/src/obuffers_addlog.c
new file mode 100644
index 0000000..28491e2
--- /dev/null
+++ b/src/obuffers_addlog.c
@@ -0,0 +1,18 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <errno.h>
+#include "limb/obuffers.h"
+
+static char buf[BUFFER_OUTSIZE];
+buffer buffer_log_ = { .fd = -1 };
+
+int
+obuffers_addlog(int fd)
+{
+    if (buffer_log_.fd >= 0)
+        return (errno = EADDRINUSE, 0);
+    if (!buffer_init(&buffer_log_, &fd_writev, fd, buf, sizeof(buf)))
+        return 0;
+    return obuffers_addextra(&buffer_log_, OLVL_NORMAL);
+}
diff --git a/src/obuffers_remdbg.c b/src/obuffers_remdbg.c
new file mode 100644
index 0000000..9764da0
--- /dev/null
+++ b/src/obuffers_remdbg.c
@@ -0,0 +1,15 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/obuffers.h"
+
+extern buffer buffer_dbg_;
+
+int
+obuffers_remdbg(void)
+{
+    if (!obuffers_remextra(&buffer_dbg_))
+        return 0;
+    buffer_dbg_.fd = -1;
+    return 0;
+}
diff --git a/src/obuffers_remextra.c b/src/obuffers_remextra.c
new file mode 100644
index 0000000..b1e60b6
--- /dev/null
+++ b/src/obuffers_remextra.c
@@ -0,0 +1,17 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <errno.h>
+#include "limb/obuffers.h"
+
+int
+obuffers_remextra(buffer *b)
+{
+    int n = sizeof(obuffer_extras) / sizeof(obuffer_extras[0]);
+    for (int i = 0; i < n; ++i)
+        if (obuffer_extras[i].b == b) {
+            obuffer_extras[i].b = NULL;
+            return 1;
+        }
+    return (errno = ENOENT, 0);
+}
diff --git a/src/obuffers_remlog.c b/src/obuffers_remlog.c
new file mode 100644
index 0000000..2f327fc
--- /dev/null
+++ b/src/obuffers_remlog.c
@@ -0,0 +1,15 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/obuffers.h"
+
+extern buffer buffer_log_;
+
+int
+obuffers_remlog(void)
+{
+    if (!obuffers_remextra(&buffer_log_))
+        return 0;
+    buffer_log_.fd = -1;
+    return 0;
+}
diff --git a/src/out_putmsg.c b/src/out_putmsg.c
new file mode 100644
index 0000000..54db980
--- /dev/null
+++ b/src/out_putmsg.c
@@ -0,0 +1,13 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "limb/obuffers.h"
+
+obuffer obuffer_1_ = { buffer_1, OLVL_NORMAL };
+
+void
+out_putmsg(u8 level, const char * const *as, unsigned int n)
+{
+    obuffer_putmsg(obuffer_1, level, as, n);
+    extras_putmsg(level, as, n);
+}
diff --git a/src/out_putmsgdie.c b/src/out_putmsgdie.c
new file mode 100644
index 0000000..0927526
--- /dev/null
+++ b/src/out_putmsgdie.c
@@ -0,0 +1,12 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <unistd.h>
+#include "limb/obuffers.h"
+
+void
+out_putmsgdie(int exit, u8 level, const char * const *as, unsigned int n)
+{
+    out_putmsg(level, as, n);
+    _exit(exit);
+}