/** @page tutorial01 Tutorial 01: The dkapp module
@section sec001 About this tutorial
This tutorial gives an introduction to some of the library modules.
It is restricted to typical usage cases.
For better readability there is only mimimum error checking shown in the
examples.
@section subsec0001 The example program
In the examples we will expand the simple program hello01.c:
@include hello01.c
Running
@code
./hello01
@endcode
will show
@code
Hello world!
Goodbye world!
@endcode
@section subsec0002 Adding dkapp support
The program with dkapp support looks like this:
@include hello02.c
- First we include the dk.h file.
- The dk.h file includes the dkconfig.h file in turn, this file defines
DK_HAVE_XXX_H preprocessor directives for available include files.
- The dkapp.h file declares the functions of the dkapp module.
- The dkapp_open_ext1() function creates a new dk_app_t object and returns
the pointer to it.
- The dkapp_close() function destroys the object and releases the memory
used by the object.
Running
@code
./hello02
@endcode
will show the same messages as for hello01.
Run
@code
./hello02 --/log/stderr/level=debug
@endcode
to see some debug messages.
@section subsec003 Localization.
@include hello03.c
- The tablename string contains the name of the string table to use.
- The kv array contains key/value pairs, each pair consists of a message
name and a default message text assigned to that name.
- The szkv variable contains the number of entries in kv.
- The dkapp_find_key_value() function returns a pointer to an array of string
pointers. The array contains string values for the message names in the
same order as listed in the kv array.
The strings reside in memory managed by the dkapp module. This memory
is released automatically by dkapp_close().
The array of string pointers returned by dkapp_find_key_value() is allocated
using dk_new(), we must use dk_delete() to release the array.
There is no string table yet, if we run
@code
./hello03
@endcode
we will see a warning message that the string table was not found. The
default message texts are printed.
Now we create a string table hello.str:
@include hello.str
and run
@code
stc hello.str .
@endcode
This creates a string table directory structure in the current directory
and fills it with string tables.
We run
@code
./hello03
@endcode
once again, the program prints the messages listed in hello.str now.
We can change the language to de_DE.UTF-8 (set the LANG environment
variable) and run the program
again, so we will see the german text versions.
@code
LANG="de_DE.UTF-8"
./hello03
@endcode
@section subsec004 Logging
We change our program to hello04.c:
@include hello04.c
and the string table hello.str
@include hello.str
and run
@code
stc hello.str .
@endcode
After building hello04 we run
@code
./hello04
@endcode
and see the warning and the error message.
@section subsec005 Preferences
The dkapp based applications use preferences (stored key/value entries
for permanent settings). You can override the value of a
preference on the command line.
We run
@code
dkpref -a hello04 /log/stdout/level none
dkpref -a hello04 /log/stderr/level debug
@endcode
to set the minimum required log level for stdout to none and
the minimum required log level for logging to stderr to debug.
When running
@code
./hello04
@endcode
we can see the debug message from dkapp_log_msg(app, DK_LOG_LEVEL_DEBUG,...)
too.
The preferences are stored in $HOME/.defaults/hello04, for other programs
hello04 is replaced by the file name.
To override the preferences settings on the command line we attempt
@code
./hello04 --/log/stderr/level=none --/log/stdout/level=progress
@endcode
to set the required level for messages logged to stdout to progress and
the required level for messages logged to stderr to none for this one
program invokation.
A user can modify preferences either using the dkpref command or by
writing a $HOME/.defaults/progname file or in the
$HOME/.defaults/all file.
@section subsec006 Command line arguments
The dkapp_get_argc() and dkapp_get_argv() functions return an argc
replacement and an argv replacement to traverse a copy of the command
line arguments without the preferences overrides.
@include hello05.c
After building hello05 run
@code
./hello05 This is --/log/stderr/level=none --/log/stdout/level=info a test.
@endcode
to see the command line arguments ``This'', ``is'', ``a'', ``test.''.
*/
/** @page tutorial02 Tutorial 02: Memory allocation using dkmem module
@section sec003 Memory allocation
When allocating memory it is convenient to have the memory initialized
to 0x00 bytes.
Most - but not all - systems provide a calloc() function to obtain
initialized memory. Some of the systems - but not all - provide and
require the use of the special function cfree() instead of free() to
release memory allocated by calloc().
To ease up things the dkmem.h module defines the macros dk_new() and
dk_delete(). The macros use calloc() or malloc() and cfree() or
free() - whatever possible. If calloc() is not available the dk_new() macro
uses a fallback function from the dkmem module which calls malloc()
and resets the memory.
Instead of
@code
char *buffer = NULL;
...
buffer = calloc(512, sizeof(char));
if(buffer) {
...
free(buffer);
}
@endcode
you can use
@code
#include
...
char *buffer = NULL;
...
buffer = dk_new(char,512);
if(buffer) {
...
dk_delete(buffer);
}
@endcode
*/
/** @page tutorial03 Tutorial 03: Sorting and searching using the dksto module
@section sec004 Sorting and searching
The dksto module can be used for sorted data storage and searching.
The dk_storage_t data type represents a container storing elements,
the dk_storage_iterator_t data type is an iterator used to traverse
the container.
In the stotut.c example program we focus on sorting and searching,
so we do not provide localization....
We will write a program to store persons data. The program accepts
the following commands as input (one command per line):
- add _surname_ _familyname_ _age_
- del f _famiilyname_
- del s _surname_
- del a _age_
- read _filename_
- print
- tree
- find f _familyname_
- find s _surname_
- find a _age_
- quit
Unfortunately we will loose all data when exiting the program.
This is intended for simplicity and readability.
Data about a person is stored in a structure Person:
@code
typedef struct {
char *famname; /**< Family name */
char *surname; /**< Surname */
unsigned long age; /**< Age in years */
} Person;
@endcode
We use 4 storages (containers) to save data sorted by family name,
surname, age and unsorted.
When creating the container sorted by family name and when searching
for a record about a person with a given family name we need a comparison
function which compares a record either against another record
by family name or against a specified family name. The same comparisons
are needed for the surname.
We write a function
@code
int compare_fct(void *p1, void *p2, int cr)
{
int back = 0;
switch(cr) {
case 0: {
back = strcmp(((Person *)p1)->famname, ((Person *)p2)->famname);
} break;
case 1: {
back = strcmp(((Person *)p1)->famname, (char *)p2);
} break;
case 2: {
back = strcmp(((Person *)p1)->surname, ((Person *)p2)->surname);
} break;
case 3: {
back = strcmp(((Person *)p1)->surname, (char *)p2);
} break;
}
return back;
}
@endcode
If we want to compare two Person structs we pass pointers to the
structs as p1 and p2 and set cr to 0.
If we are searching for a recored about a specified family name
the function has a pointer to a Person struct in p1, the name is passed
as p2, the cr parameter is 1.
To compare two struct Person instances by surname or to compare one struct
Person instance against a name we use cr values 2 and 3.
In the main() function we create the containers. For container s1 and s2
(sorted by family name and surname) we set the comparison function to
compare-fct and provide 0 (comparison by family name) and 2
(comparison by surname) as cr value.
When handling the input commands we use dksto_it_find_like() to
search for a specified family name, surname or age. The search
requires comparisons, comparison arguments are objects stored in the
container (on the left side) and the specified name/surname/age on
the right side. So we can not use cr values 0 and 2 -- this would require
objects on the left and the right side -- we use 1 and 3 instead.
If the dksto_it_find_like() function finds a matching object it returns the
pointer to the first object found. Otherwise it returns NULL and
sets the iterators internal pointer so the next call to
dksto_it_find_next() will return a pointer to the next larger object.
@include stotut.c
*/
/** @page tutorial04 Tutorial 04: Generic I/O using the dkstream module
The dkstream module can read from and write to plain files, gzip or
bzip2 compressed files. The compression type is specified by choosing the
appropriate dkstream_openxxx() function.
The details of read/write and close operations are hidden from the application
programmer, the application code only needs to deal with the
dk_stream_t API.
We can use the dk_stream_t API for both text and binary data.
@include strtut.c
The example program write a file, either test.dat or a file name you
specify. You can choose to either write a plain file or a gzip or bzip2
compressed one.
The first argument - if specified - must be either ``gzip'' or ``bzip2''
to choose the compression type.
The second argument - if specified - is the file name to use.
After building strtut we can run
@code
./strtut plain test.dat
cat test.dat
@endcode
@code
./strtut gzip test.dat.gz
gzip -dc test.dat.gz
@endcode
@code
./strtut bzip2 test.dat.bz2
bzip2 -dc test.dat.bz2
@endcode
See the documentation of dkstream module for more information about the
functions to read and write data.
If your program uses the dkapp module you should use the
dkapp_read_file(), dkapp_read_cfg(), dkapp_write_file() and dkapp_write_cfg()
functions to open the streams. These functions have builtin security checks
and error reporting.
*/
/** @page security Security considerations when using the libraries
@section securityoverview Overview
Some of the functions in the dktools libraries return built-in default values
or values obtained/derived from environment variables if they fail to obtain
the requested information from system functions.
This is intended for application development, if an application is not fully
configured it should do best possible recovery and attempt to run.
For SUID/SGID programs, daemons and services this might be dangerous,
these programs should not attempt to guess configuration settings. They should
print an error message to remind the user or administrator to complete
the configuration and exit.
@section security001 Functions to avoid in SUID/SGID programs, network daemons and services
- all functions from the dkapp module
- dksf_get_uname(),
- dksf_get_euname(),
- dksf_get_home(),
- dksf_get_ehome(),
- dksf_get_hostname(),
- dksf_get_tempdir(),
- dksf_get_domainname() and
- dksf_get_executable().
@section security002 Functions to use with care in SUID/SGID programs, network daemons and services
For
- dksf_getpid(),
- dksf_getppid(),
- dksf_getuid(),
- dksf_getgid(),
- dksf_geteuid(),
- dksf_getegid(),
- dksf_getpgrp() and
- dksf_getpgid()
you should use the dksf_have_getpid() ... functions to check whether the
function returns a usable result on the current system.
*/