=head1	NAME

dkapp - application support

=head1	SYNOPSIS

  #include <dkapp.h>


  dk_app_t *dkapp_open (int argc, char *argv[]);
  
  dk_app_t *dkapp_open_ext1 (
    int argc, char *argv[], char *gr, char *etcdir,
    int sil, int nostdio
  );
  
  void dkapp_close (dk_app_t *a);
 
  void
  dkapp_set_source_filename (dk_app_t *a, char *n);
  
  void
  dkapp_set_source_lineno (dk_app_t *a, unsigned long lineno);

  int dkapp_log_msg (dk_app_t *a, int p, char **msg, int az);

  void dkapp_log_1(dk_app_t *a, int p, char **msgarray, size_t i);

  void dkapp_log_3(dk_app_t *a, int p, char **msgarray, size_t i1, size_t i2, char *t);

  void dkapp_log_5(dk_app_t *a, int p, char **msgarray, size_t i1, size_t i2, size_t i3, char *t1, char *t2);
  
  int
  dkapp_log_level_in_use (dk_app_t *app, int loglevel);

  int
  dkapp_get_pref (
    dk_app_t *a, char *key, char *buf, size_t lgt, int ex
  );
  
  int dkapp_set_pref (dk_app_t *a, char *key, char *value);
  
  void
  dkapp_unconfigure (dk_app_t *app);

  int
  dkapp_transform_string (
    dk_app_t *app,char *dest,size_t sz,char *src
  );
  
  int
  dkapp_transform_string_ext1 (
    dk_app_t *app,char *dest,size_t sz,char *src,int fn
  );
  
  int
  dkapp_find_cfg (dk_app_t *a, char *name, char *buffer, size_t sz);
  
  int
  dkapp_find_file (dk_app_t *a, char *name, char *buffer, size_t sz);
  
  char *
  dkapp_find_string (dk_app_t *a, char *t, char *k, char *d);
  
  void
  dkapp_find_multi (dk_app_t *app, dk_string_finder_t *f, char *table);

  int
  dkapp_get_argc (dk_app_t *a);
  
  char **
  dkapp_get_argv (dk_app_t *a);
  
  void
  dkapp_help (dk_app_t *a, char *filename, char **def_strings);
  
  dk_stream_t *
  dkapp_read_file (dk_app_t *app, char *filename);
  
  dk_stream_t *
  dkapp_read_cfg (dk_app_t *app, char *filename);
  
  dk_stream_t *
  dkapp_write_file (dk_app_t *app, char *filename);
  
  int
  dkapp_tmpnam (dk_app_t *app, char *buffer, size_t sz);
  
  void
  dkapp_err_traverse_dir (dk_app_t *app, char *name);
  
  void
  dkapp_err_stat_failed (dk_app_t *app, char *name);
  
  void
  dkapp_err_cwd (dk_app_t *app);
  
  void
  dkapp_err_memory (dk_app_t *app, size_t elsize, size_t nelem);
  
  void
  dkapp_err_matchfile (dk_app_t *app, char *name);
  
  void
  dkapp_err_matchdir (dk_app_t *app, char *name);
  
  void
  dkapp_err_fopenr (dk_app_t *app, char *name);
  
  void
  dkapp_err_fopenw (dk_app_t *app, char *name);
  
  void
  dkapp_err_fwrite (dk_app_t *app, char *name);
  
  void
  dkapp_err_fread (dk_app_t *app, char *name);
  
  int
  dkapp_get_relaxed_fopen_check (dk_app_t *app);
  
  void
  dkapp_err_nowrite (dk_app_t *app, char *fn, int reason);
  
  dk_stream_t *
  dkapp_stream_openfile (dk_app_t *a, char *n, char *m);
  
  dk_stream_t *
  dkapp_stream_opengz (dk_app_t *a, char *n, char *m);
  
  dk_stream_t *
  dkapp_stream_openbz2 (dk_app_t *a, char *n, char *m);
  
  FILE *
  dkapp_fopen (dk_app_t *a, char *n, char *m);
  
  char *
  dkapp_get_appname (dk_app_t *a);
  
  void
  dkapp_set_silent (dk_app_t *a, int v);
  
  void
  dkapp_set_nostdio (dk_app_t *a, int v);
  
  int
  dkapp_set_groupname (dk_app_t *a, char *n);
  
  void
  dkapp_err_tcpip (dk_app_t *app);
  
  int
  dkapp_silence_check (int argc, char **argv);
  
  int
  dkapp_get_min_loglevel (dk_app_t *a);
  
  int
  dkapp_ide_type (char *str);
  
  unsigned char *
  dkapp_get_stdout_codepage (dk_app_t *a);
  
  char *
  dkapp_fne_one (dk_app_t *a, dk_fne_t *f, char *p);
  
  void
  dkapp_err_no_such_file (dk_app_t *app, char *pat);
  
  void
  dkapp_err_multiple_files (dk_app_t *app, char *pat);

=head1	DESCRIPTION

The dkapp module provides mechanisms for preference management, localization
and logging in command line applications. Data related to the application
is stored in a I<dk_app_t> structure.

The dkapp_open_ext1() function creates a new application structure. It returns
a pointer to the new structure on success, NULL on error.
The I<argc> and I<argv> parameters are those delivered by the environment
to the main() function. The I<g> parameter specifies a programm group name.
This group name is used to construct directory names, so I recommend to
use characters, digits and underscores only, the length should not
exceed 8. The I<etc> parameter must be the path to the system configuration
directory, typically this is "/etc" or "/usr/local/etc".
The I<sil> parameter switches the application to silent behaviour, no log
messages are written to stdout or stderr. The I<nostdout> parameter
specifies that the program is running as a filter, no log messages should
go to stdout.

Before exiting the application the I<dk_app_t> structure must be destroyed
using the dkapp_close() function.

The dkapp_open() function creates a new application structure using less
arguments than dkapp_open_ext1(). This function is in the library for
backward compatibility, you should not use when writing new programs.
Use dkapp_open_ext1() instead.

The dkapp_log_msg() function creates a log message. The I<p> parameter
specifies the priority of the message, it can be one of: I<DK_LOG_LEVEL_PANIC>,
I<DK_LOG_LEVEL_FATAL>, I<DK_LOG_LEVEL_ERROR>, I<DK_LOG_LEVEL_WARNING>,
I<DK_LOG_LEVEL_INFO>, I<DK_LOG_LEVEL_PROGRESS>, I<DK_LOG_LEVEL_DEBUG>.
The I<msg> parameter points to an array of strings, I<az> is the number
of elements in the array.
Depending on the preferences the log messages is written to log file,
stdout, stderr and syslog service (on *x systems).

The dkapp_log_1(), dkapp_log_3() and dkapp_log_5() functions are convenience
variants of the dkapp_log_msg() function. An applicaation should load an
array of localized messages into a ``char const * const * msg;'' array.
A fixed message or combinations of fixed messages can be logged. The
print order is msg[i1], t, msg[i2] for dkapp_log_3() and
msg[i1], t1, msg[i2], t2, msg[i3] for dkapp_log_5().

The dkapp_set_source_filename() and dkapp_set_source_lineno() functions
can be used before dkapp_log_msg() to set a file name and a line number
of an input file.

The dkapp_log_level_in_use() function checks, whether a given
I<loglevel> is in use. This can be used to load string tables for
debugging or progress messages only if they are needed.

The dkapp_get_pref() function retrieves a preference string for the
specified name I<key>. The string is written to the buffer I<buf>
which is I<lgt> bytes long. The I<ex> parameter specifies, which information
sources to exclude, may be I<DK_APP_PREF_EXCL_CMD> (command line options),
I<DK_APP_PREF_EXCL_PROG> (settings made by the program itself),
I<DK_APP_PREF_EXCL_USER> (settings made by the user) or
I<DK_APP_PREF_EXCL_SYSTEM> (settings in system-wide configuration files).
Use an or-combination to exclude multiple information sources.

The dkapp_set_pref() function sets a preference specified by I<key> to
I<value>. When the application is finished by dkapp_close() the new preferences
are written to the preferences file. On Windows systems the preferences
are written to the registry immediately.

The dkapp_unconfigure() function sets a flag to destroy the user
specified preferences (by writing an empty preferences file)
for the application when closing the application. On Windows systems
all registry entries in the applications registry key in HKCU are
removed.

The dkapp_transform_string() function transforms a string I<src> to the
buffer I<dest> of I<sz> bytes. The following macros are expanded:

  $(app.name)       the application name
  $(app.dir)        the application directory
  $(shared.dir)     the shared directory
  $(temp.dir)       the temporary directory
  $(user.name)      the user's login name
  $(user.home)      the user's home directory
  $(user.uid)       the user id
  $(user.gid)       the group id
  $(user.euid)      the effective user id
  $(user.egid)      the effective group id
  $(host.name)      the host name
  $(host.domain)    the DNS domain name
  $(process.pid)    the process id
  $(process.ppid)   the parent process id
  $(process.pgid)   the process group id

The dkapp_find_cfg() function searches for a configuration file
with the specified I<name> and stores the full path in the I<buffer>.
The function searches for compressed and localized versions too.
Search is done by checkgin the /etc and /etc/program-group-name
directory for a subdirectory structure matching language/region/encoding.
On W* systems the %windir% and %windir%\program-group-name directory
is used instead.

The dkapp_find_file() function searches for files in the current
directory, the application directory, the application group directory,
the shared directory, the %windir% and subdirectories and the
system configuration directory and subdirectories.

The dkapp_find_string() function searches in a string table
for an entry matching the key name I<k> and returns a pointer to the
string (if found) or a pointer to the default string I<d>. The I<t>
parameter specifies the name of the string table (file name without
extension).

The dkapp_find_multi() function searches for several strings in
a string table at once. This is more performant than finding each
string individually.

The dkapp_get_argc() function returns the corrected I<argc>, the number
of command line parameters. The dkapp_get_argv() function returns a
pointer to a corrected array of strings containing the command line
parameters. Corrected means that preferences specified on the command
line are removed (Preferences on the command line are recognized by
checking for "--/" at the beginning of a command line argument).

The dkapp_help() function prints a help text either from a file or
from a built-in array of strings. The file name must be specified
as name and extension but without leading path. The I<def_strings>
arguments points to an array of strings which is finished by a NULL
pointer.

The dkapp_read_cfg() function searches for a configuration file
as dkapp_find_cfg() does. The file is opened for reading, a 
I<dk_stream_t> to read the file is returned. This stream must be closed
by dkstream_close() after usage.

The dkapp_read_file() function searches for a file as dkapp_find_file()
does. The file is opened for reading, a
I<dk_stream_t> to read the file is returned. This stream must be closed
by dkstream_close() after usage.

The dkapp_write_file() function tries to open the specified file for
writing. It returns a valid stream pointer on success, NULL on error.
The stream must be closed by the dkstream_close() function after usage.

The dkapp_tmpnam() function creates a file name for a temporary
file and stores the name into the I<buffer>.

The I<dkapp_err_...()> function issue error messages:

=over	4

=item	* dkapp_err_traverse_dir()

Failed to traverse the specified directory.

=item	* dkapp_err_stat_failed()

The stat() function  failed for the specified file name (typically this
means the file does not exist or we have no permissions on the file).

=item	* dkapp_err_cwd()

Unable to change the current working directory.

=item	* dkapp_err_memory()

Not enough memory available to dynamically allocate space for I<nelem>
elements of size I<elsize>.

=item	* dkap_err_matchfile()

There is no file matching the pattern.

=item	* dkapp_err_matchdir()

There is no such directory.

=item	* dkapp_err_fopenr()

Failed to open the file for reading.

=item	* dkapp_err_fopenw()

Failed to open the file for writing.

=item	* dkapp_err_fwrite()

Failure while writing to the file.

=item	* dkapp_err_fread()

Failure while reading from the file.

=item	* dkapp_err_nowrite()

Opening a file was denied for the specified reason.

=item	* dkapp_err_tcpip()

An error occured while accessing the network.

=item	* dkapp_err_no_such_file()

There is no file matching the pattern.

=item	* dkapp_err_multiple_files()

The pattern does not select exactly one file. Multiple
file names match the pattern.


=back

The dkapp_stream_openfile(), dkapp_stream_opengz() and
dkapp_stream_openbz2() functions open a file and return a pointer to
a stream structure. The file name is passed as parameter I<n>,
I<m> is the opening mode (same as used by fopen()). The functions
return a valid pointer on success, NULL on error.
The stream must be closed using the dkstream_close() function after usage.

The dkapp_fopen() function opens a file and returns a pointer to the
file or NULL on errors.

The dkapp_get_appname() function returns a pointer to a string containing
the name of the application.

The dkapp_set_silent() function turns silent behaviour on or off.
Note: Instead of using dkapp_open() and dkapp_set_silent() you should
use dkapp_open_ext1().

The dkapp_set_nostdio() function turns filter behaviour on or off. Note:...

The dakpp_set_groupname() function sets the name of the program group.
Note:...

The dkapp_silence_check() function scans the command line arguments
to find out whether the application should run in silent mode.

The dkapp_ide_type() function converts a string into an int key
describing which compiler/assembler is simulated in error messages
and warnings.

The dkapp_get_stdout_codepage() function returns a pointer to the
codepage used by the application when writing log messages to stdout.

The dkapp_fne_one() function checks, whether or not the pattern in a
file name expander selects exactly one file. A pointer to a string
containing the full file name is returned, NULL otherwise.
The string must be release using the dk_delete() macro after usage.

=head1	AUTHOR

Dirk Krause

=head1	COPYRIGHT AND LICENSE

Copyright (c) 2001-2005, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above
   copyright notice, this list of conditions and the
   following disclaimer.

 * Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials
   provided with the distribution.

 * Neither the name of the Dirk Krause nor the names of
   contributors may be used to endorse or promote products
   derived from this software without specific prior written
   permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
