= LogC Utilities programmers guide

This describes usage of `logc_util.h`. This is header only extension for `logc.h`
and implements various handy macros that are too specific to be included in
primary header.


== Inclusion

To include LogC Utilities you just have to include `logc_util.h` preferably after
`DEFLOG` definition.

== Not implemented

During development and sometimes even during production it is common to have
prepared but not yet implemented functions, cases, branches and so on. In most
cases such function or branch would be left empty with just plain comment such as
`// TODO`. Problem is that there is no code in such case. It is required to have
such function compiled but having no code there can cause weird behavior of
program once such function is actually used in code. The better approach would be
to for example call `abort` in such function to terminate execution and thus
preventing the unexpected behavior. And ideal option is to also report exact
location of issue and what is actually missing. The ideal solution in LogC is
implemented simply using `not_implemented` macro.

Usage of `not_implemented` would be:
[,C]
----
void foo(int fee) {
	not_implemented;
}
----
On `foo` invocation you would get critical message `foo not implemented yet` and
`abort` would be called.

There is also `log_not_implemented(LOG)` macro. It serves the same purpose but allows
log specification. It can be used when `DEFLOG` is not defined or anytime you do
not want to use default log.


== Standard library `-1` error return

Functions in standard C library as well as in POSIX are commonly reporting errors
by returning `-1` and setting `errno`. Handling of these errors in all programs
can be simply put to two groups: handled and unhandled. Handled errors are not of
interest in here as they are handled somehow and in most cases all corner cases
are covered and error or at least some log message are reported. On the other hand
it is common that there is nothing like that for unhandled returns, clearly
because they are unhandled. They are unhandled most likely because of two reasons:
* There is not effect on program execution even if function fails
* The fail is not in anyway expected

[WARNING]
  These functions should be only used really on functions returning `-1` and
  setting `stderr` on error. Be aware that they are not intended to be used on any
  other error handling.

=== Functions allowed to fail

The example of such function is `unlink` on our temporally file. Pretty reasonable
expectation in that case is that `unlink` fails only if target path is not
present. So the result or removal file and failure of removal file in such case is
the same.

Second example would be signal for some other process on program termination. This
can be just to reload configuration for example (thus `kill(pid, SIGUSR1)`). This
operation is just nice to do or best effort. `kill` can fail because process might
not be running anymore but original program really does not care about that so it
can safely ignore error.

In both example cases it is pretty reasonable to ignore returned value and thus
error. In terms of code complexity adding `if` statement is probably out of
question. At the same time it can be that error should not be really ignored in
some cases or that error can be used to deduce state of program. Just ignoring it
always is not as good idea considering possible faults in judgement. Because of
that LogC provides utility macro `std_ignore`. This simply prints message with
trace severity saying for example `Ignored fail of 'unlink(path)'` in case of
failure in:
[,C]
----
std_ignore(unlink(path));
----

There is also `log_std_ignore` macro. It serves the same purpose but it allows log
specification. It can be used when `DEFLOG` is not defined or anytime you do not
want to use default log.

=== Function expected not to fail

The example of such case can be change of owner of just created hardlink. It is
reasonable expectation that we have rights for it as we just created it as well as
that it exists.

It is clear that in most cases error is not handled simply for code simplicity.
Unfortunately at the same time that allows possibly hard to debug issues in some
circumstances. To prevent this LogC provides utility macro `std_fatal`. This
simply prints `Unexpected fail of 'chown(new_path, uid, gid)'` when our example
`chown` function reports failure.
[,C]
----
if (link(path, new_path) == 0) {
  std_fatal(chown(new_path, uid, gid));
}
----

There is also `log_std_fatal` macro. It serves the same purpose but it allows log
specification. It can be used when `DEFLOG` is not defined or anytime you do not
want to use default log.


== Standard library `NULL` error return

There is one more type of error reporting used in standard C library as well as in
POSIX and that is return of pointer or `NULL` in case of an error. These are
functions such as `malloc` or `strdup`.

There is no LogC utility to handle these. The reason is because in pretty much all
cases you need return value to work with it later.

You can use plain `assert` for unexpected failures.

For these functions there just can't be anything as allowed failure as they in
general return pointer to memory. The ignored failure can later trigger
segmentation fail.
