diff options
-rw-r--r-- | include/embedlog.h.in | 3 | ||||
-rw-r--r-- | man/el_cleanup.3 | 12 | ||||
-rw-r--r-- | man/el_destroy.3 | 1 | ||||
-rw-r--r-- | man/el_flush.3 | 2 | ||||
-rw-r--r-- | man/el_init.3 | 54 | ||||
-rw-r--r-- | man/el_new.3 | 1 | ||||
-rw-r--r-- | man/el_option.3 | 2 | ||||
-rw-r--r-- | man/el_overview.7 | 77 | ||||
-rw-r--r-- | man/el_print.3 | 2 | ||||
-rw-r--r-- | src/el-options.c | 52 | ||||
-rw-r--r-- | tst/test-el-file.c | 27 | ||||
-rw-r--r-- | tst/test-el-options.c | 5 |
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)); } |