aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/embedlog.h.in3
-rw-r--r--man/el_cleanup.312
-rw-r--r--man/el_destroy.31
-rw-r--r--man/el_flush.32
-rw-r--r--man/el_init.354
-rw-r--r--man/el_new.31
-rw-r--r--man/el_option.32
-rw-r--r--man/el_overview.777
-rw-r--r--man/el_print.32
-rw-r--r--src/el-options.c52
-rw-r--r--tst/test-el-file.c27
-rw-r--r--tst/test-el-options.c5
12 files changed, 234 insertions, 4 deletions
diff --git a/include/embedlog.h.in b/include/embedlog.h.in
index 53525bb..a3deeb1 100644
--- a/include/embedlog.h.in
+++ b/include/embedlog.h.in
@@ -219,6 +219,9 @@ int el_pbinary(enum el_level level, const void *memory, size_t mlen);
const struct el *el_get_el(void);
int el_flush(void);
+struct el * el_new(void);
+int el_destroy(struct el *el);
+
int el_oinit(struct el *el);
int el_ocleanup(struct el *el);
int el_ooption(struct el *el, int option, ...);
diff --git a/man/el_cleanup.3 b/man/el_cleanup.3
index 20ff67e..19c9742 100644
--- a/man/el_cleanup.3
+++ b/man/el_cleanup.3
@@ -14,6 +14,8 @@ calls.
.BI "int el_cleanup(void)"
.br
.BI "int el_ocleanup(struct el *" el ")"
+.br
+.BI "int el_destroy(struct el *" el ")"
.SH DESCRIPTION
.PP
.BR el_cleanup (3)
@@ -25,6 +27,13 @@ After clean up, library calls cannot be used without initialization.
works just the same, but accepts custom
.I el
object as argument.
+.PP
+.BR el_destroy (3)
+works just the same, but must be used when
+.I el
+object has been created with
+.BR el_new (3)
+function.
.SH RETURN VALUE
.PP
Functions return 0 upon successful cleanup or -1 on errors.
@@ -35,6 +44,8 @@ used.
.BR el_cleanup (3)
function cannot fail.
.BR el_ocleanup (3)
+and
+.BR el_destroy (3)
may return:
.TP
.B EINVAL
@@ -53,6 +64,7 @@ Passed el object is not valid
.BR el_pmemory (3),
.BR el_pmemory_table (3),
.BR el_opmemory_table (3),
+.BR el_new (3),
.BR el_ooption (3),
.BR el_oputs (3),
.BR el_oprint (3),
diff --git a/man/el_destroy.3 b/man/el_destroy.3
new file mode 100644
index 0000000..f5c1d77
--- /dev/null
+++ b/man/el_destroy.3
@@ -0,0 +1 @@
+.so man3/el_cleanup.3
diff --git a/man/el_flush.3 b/man/el_flush.3
index 3ae99b2..e3788d1 100644
--- a/man/el_flush.3
+++ b/man/el_flush.3
@@ -72,6 +72,8 @@ Passed el object is not valid
.BR el_pmemory (3),
.BR el_pmemory_table (3),
.BR el_opmemory_table (3),
+.BR el_new (3),
+.BR el_destroy (3),
.BR el_ooption (3),
.BR el_oputs (3),
.BR el_oprint (3),
diff --git a/man/el_init.3 b/man/el_init.3
index 34dfb83..2056bf5 100644
--- a/man/el_init.3
+++ b/man/el_init.3
@@ -10,6 +10,8 @@
.BI "int el_init(void)"
.br
.BI "int el_oinit(struct el *" el ")"
+.br
+.BI "struct el * el_new(void)"
.SH DESCRIPTION
.PP
There are two types of functions in
@@ -63,14 +65,53 @@ object may be used.
If you want to have multiple embedlog instances (ie. one for program logs,
and one for queries) that stores logs differently - this is the function you
want to use.
+Object initialized with this function must be deinitialized with
+.BR el_ocleanup (3)
+function.
+.PP
+.BR el_new (3)
+Works in the same way as
+.BR el_oinit (3)
+but function returns newly heap-allocated pointer to
+.I el
+struct.
+Object created with this function must be destroyed with
+.BR el_destroy (3)
+function.
+.SH NOTES
+Keeps in mind that using
+.BR el_oinit (3)
+function is suscible to ABI breakage.
+If stable ABI is important to you, use
+.BR el_new (3)
+function.
+Please check
+.BR el_overview (3)
+for more information about this.
.SH RETURN VALUE
.PP
-Both functions will return 0 upon success and -1 on errors.
+.BR el_init (3)
+cannot fail and always returns 0.
+.BR el_oinit (3)
+function will return 0 upon success and -1 on errors.
+.BR el_new (3)
+returns valid pointer on success and
+.B NULL
+when error occurs.
.SH ERRORS
+.PP
+.BR el_oinit (3)
+can return:
.TP
.B EINVAL
.I el
object is invalid (null).
+.PP
+.BR el_new (3)
+can return:
+.TP
+.B ENOMEM
+Not enough memory in the system to perform necessary memory allocations.
.SH EXAMPLE
.PP
Note: error handling has been ommited for clarity sake
@@ -80,11 +121,12 @@ Note: error handling has been ommited for clarity sake
int main(void)
{
- struct el el;
+ struct el el, *elp;
- /* initialize both default and custom el objects */
+ /* initialize default and two custom el objects */
el_init();
el_oinit(&el);
+ elp = el_new();
/* make el to print to file and stderr */
el_ooption(&el, EL_OUT, EL_OUT_FILE | EL_OUT_STDERR);
@@ -93,8 +135,10 @@ Note: error handling has been ommited for clarity sake
/* print messages */
el_print(ELI, "will print to stderr");
el_oprint(ELI, &el, "will print to file /tmp/test.log and stderr");
+ el_oprint(ELN, elp, "print to stderr");
/* cleanup after any initialization code (like fopen) */
+ el_destroy(elp);
el_ocleanup(&el);
el_cleanup();
@@ -109,13 +153,15 @@ Note: error handling has been ommited for clarity sake
.BR el_option (3),
.BR el_puts (3),
.BR el_flush (3),
-.BR el_oflish (3),
+.BR el_oflush (3),
.BR el_print (3),
.BR el_vprint (3),
.BR el_perror (3),
.BR el_pmemory (3),
.BR el_pmemory_table (3),
.BR el_opmemory_table (3),
+.BR el_new (3),
+.BR el_oinit (3),
.BR el_ocleanup (3),
.BR el_ooption (3),
.BR el_oputs (3),
diff --git a/man/el_new.3 b/man/el_new.3
new file mode 100644
index 0000000..3dbf2b6
--- /dev/null
+++ b/man/el_new.3
@@ -0,0 +1 @@
+.so man3/el_init.3
diff --git a/man/el_option.3 b/man/el_option.3
index 511a1a5..a7ddae7 100644
--- a/man/el_option.3
+++ b/man/el_option.3
@@ -653,6 +653,8 @@ informations
.BR el_pmemory (3),
.BR el_pmemory_table (3),
.BR el_opmemory_table (3),
+.BR el_new (3),
+.BR el_destroy (3),
.BR el_ocleanup (3),
.BR el_oputs (3),
.BR el_oprint (3),
diff --git a/man/el_overview.7 b/man/el_overview.7
index cb9813e..4dde0c9 100644
--- a/man/el_overview.7
+++ b/man/el_overview.7
@@ -111,6 +111,10 @@ for more information.
.br
.BI "int el_ocleanup(struct el *" el ")"
.br
+.B struct el * el_new(void)
+.br
+.BI "int el_destroy(struct el *" el ")"
+.br
.BI "int el_ooption(struct el *" el ", enum el_option " option ", \
\&...)"
.br
@@ -232,6 +236,77 @@ You can simply call it like
.EX
el_oprint(OELN, "Notice message");
.EE
+.SH "STABLE ABI CONSIDERATION"
+.PP
+Since
+.B embedlog
+is versatile and can work on both hardcore embedded systems (nuttx, freertos,
+bare metals) and on big CPUs that can run Linux, library must provide a way
+for user to use stack-allocated objects and stable ABI.
+Unfortunately there is no way to provide both at the same time, so
+.B embedlog
+provides two solutions so everybody is happy.
+.PP
+Note that library versioning follows
+.B STABLE ABI
+way of using library.
+So if feature is added that adds new field to
+.BR "struct el",
+then this will not be treated as ABI breakage, because if you are using
+.BR el_new (3)
+or
+.BR el_init (3)
+functions, ABI will not be broken.
+Only when using
+.BR el_oinit (3)
+ABI will be broken.
+.SS "STABLE ABI"
+.PP
+When stable ABI is required, user must initialize
+.B embedlog
+either with
+.BR el_init (3)
+or
+.BR el_new (3)
+function.
+User also must not access internal fields directly and all operations on
+.I el
+object must be done through the API functions.
+.BR el_new (3)
+will malloc necessary memory for the user which must be freed with
+.BR el_destroy (3)
+function.
+Under no circumstances use
+.B sizeof
+on the object nor struct.
+Operation will succeed, but may return invalid results when library is updated.
+To put it in as few word as possible - you don't know anything about internals
+of
+.BR "struct el" .
+.SS "STACK ALLOCATED OBJECT"
+.PP
+When you use library in hardcore embedded environment, where there is not
+dynamic linking involved, you are save to ignore any ABI changes, since
+you always build your programs alongside the library.
+But thanks to that you can avoid
+.BR malloc ()
+call and allocate everything on the stack.
+To allocate object on stack you must use
+.BR el_oinit (3)
+function, and deinitialize object with
+.BR el_ocleanup (3).
+.PP
+If you are using
+.BR el_oinit (3)
+on systems with dynamic library support you are suscible to ABI breakage and
+undefined behaviour when only new features are added, or even when bugfix
+introduces new field to
+.BR "struct el" .
+Heck, even recompilation with different flags can break ABI here.
+Do not use this approach if your system have dynamic library support unless
+you can rebuild all programs against new version of library.
+.PP
+.B You've been warned!
.SH EXAMPLE
.PP
Initial setup is very trivial.
@@ -274,6 +349,8 @@ for more details.
.BR el_opmemory_table (3),
.BR el_oinit (3),
.BR el_ocleanup (3),
+.BR el_new (3),
+.BR el_destroy (3),
.BR el_ooption (3),
.BR el_oputs (3),
.BR el_oprint (3),
diff --git a/man/el_print.3 b/man/el_print.3
index 26ed93e..8bddf80 100644
--- a/man/el_print.3
+++ b/man/el_print.3
@@ -513,6 +513,8 @@ and if file rotation is enabled also from
.BR el_oflish (3),
.BR el_pmemory (3),
.BR el_pmemory_table (3),
+.BR el_new (3),
+.BR el_destroy (3),
.BR el_opmemory_table (3),
.BR el_ocleanup (3),
.BR el_ooption (3),
diff --git a/src/el-options.c b/src/el-options.c
index 9b30f5c..67d9548 100644
--- a/src/el-options.c
+++ b/src/el-options.c
@@ -38,6 +38,7 @@
#include "el-private.h"
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
@@ -435,6 +436,36 @@ int el_oinit
/* ==========================================================================
+ Same as el_init but struct el is initialized on heap, so user does not
+ have to know anything about internal structure of 'el'.
+
+ errno
+ ENOMEM not enough memory in the system to allocate data
+ ========================================================================== */
+
+
+struct el *el_new
+(
+ void
+)
+{
+ struct el *el;
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+ el = malloc(sizeof(*el));
+ if (el == NULL)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ el_oinit(el);
+ return el;
+}
+
+
+/* ==========================================================================
cleans up whatever has been initialized/reserved by el_init
========================================================================== */
@@ -481,6 +512,27 @@ int el_ocleanup
/* ==========================================================================
+ Same as el_ocleanup but can be used only with object created on heap
+ with el_new().
+ ========================================================================== */
+
+
+int el_destroy
+(
+ struct el *el /* el object */
+)
+{
+ if (el_ocleanup(el) != 0)
+ {
+ return -1;
+ }
+
+ free(el);
+ return 0;
+}
+
+
+/* ==========================================================================
checks wheter log print is allowed if not. Print is not allowed when log
level is no high enough or no output has been configured.
========================================================================== */
diff --git a/tst/test-el-file.c b/tst/test-el-file.c
index 852311b..da114fb 100644
--- a/tst/test-el-file.c
+++ b/tst/test-el-file.c
@@ -1263,6 +1263,32 @@ static void file_rotate_and_directory_reappear(void)
========================================================================== */
+static void file_multi_message_on_el_new(void)
+{
+ struct el *el;
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+ mt_assert((el = el_new()) != NULL);
+ el_ooption(el, EL_OUT, EL_OUT_FILE);
+ el_ooption(el, EL_FSYNC_EVERY, 0);
+ el_ooption(el, EL_FROTATE_NUMBER, 0);
+ mt_fok(el_ooption(el, EL_FPATH, WORKDIR"/log"));
+
+ el_oputs(el, s9);
+ el_oputs(el, s8);
+ el_oputs(el, s5);
+ mt_fok(file_check(WORKDIR"/log", s9 s8 s5));
+
+ unlink(WORKDIR"/log");
+ mt_fok(el_destroy(el));
+}
+
+
+/* ==========================================================================
+ ========================================================================== */
+
+
static void file_no_dir_for_logs(void)
{
mt_ferr(el_option(EL_FPATH, WORKDIR"/i-dont/exist"), ENOENT);
@@ -1652,6 +1678,7 @@ void el_file_test_group(void)
mt_run(file_rotate_write_after_failed_open_to_existing_file_with_holes2);
mt_run(file_rotate_write_after_failed_open_to_existing_file_with_holes3);
mt_run(file_rotate_and_directory_reappear);
+ mt_run(file_multi_message_on_el_new);
mt_prepare_test = &test_prepare;
mt_cleanup_test = &test_cleanup;
diff --git a/tst/test-el-options.c b/tst/test-el-options.c
index 9c98f3e..09ad7a1 100644
--- a/tst/test-el-options.c
+++ b/tst/test-el-options.c
@@ -88,6 +88,7 @@ static void options_init(void)
{
struct el default_el; /* expected default el */
struct el el; /* custom el to init */
+ struct el *elp; /* heap allocated el */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -122,6 +123,10 @@ static void options_init(void)
mt_fail(el_init() == 0);
mt_fail(memcmp(&g_el, &default_el, sizeof(default_el)) == 0);
mt_fail(el_cleanup() == 0);
+
+ mt_fail((elp = el_new()) != NULL);
+ mt_fail(memcmp(elp, &default_el, sizeof(*elp)) == 0);
+ mt_fok(el_destroy(elp));
}