/** @file dk3app.h Application functions prototypes. The dk3_app_t data type can be used for logging, file search, internationalization and configuration. The dk3_app_t type can be used with different application types: command line applications, GUI applications, daemons, and silent applications. The main difference between these types is the log output destination. For command line applications diagnostics go to standard error output and to the log file. There is one log file per process. By default the log file is deleted at the end of the program unless there was an error message, a user can use preferences to change this. For GUI applications diagnostics are written to the log file only. For daemons we append to the same log file again and again. For silent applications no log file is written. @section dk3appopen Opening and closing an application @code #include #include static dkChar const gn[] = { "tests" }; DK3_MAIN { dk3_app_t *app = NULL; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { ... do something ... dk3app_close(app); } } @endcode In the example we open a command line application using dk3app_open_command(). Use dk3app_open_daemon() to create an application object for a daemon after the fork()+setsid()/setpgrp() sequence. Use dk3app_open_silent() to create an application object doing no diagnostics. The dk3app_open_gui() function is used by the DkWxAppHelper constructor. @section dk3appargs Accessing command line arguments The dk3app_get_argc() and dk3app_get_argv() functions can be used to access command line arguments. The dk3_app_t structure has it's own copy of the command line arguments, any preferences specified on the command line (i.e. --/log/stderr/level=debug) are removed. @code #include #include static dkChar const gn[] = { "tests" }; DK3_MAIN { dk3_app_t *app = NULL; int xargc = 0; dkChar const * const *xargv = NULL; dkChar buffer[32]; int i = 0; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { xargc = dk3app_get_argc(app); xargv = dk3app_get_argv(app); dk3sf_initialize_stdout(); for(i = 0; i < xargc; i++) { dk3sf_sprintf3(buffer, dkT("%05d: "), i); dk3sf_fputs(buffer, stdout); dk3sf_fputs(xargv[i], stdout); dk3sf_fputc(dkT('\n'), stdout); } dk3app_close(app); } } @endcode See the dk3opt.h documentation for the dk3_opt_set_t to process command line arguments. @section dk3appretrieveinformation Retrieving information - dk3app_get_logname()\n retrieves the name of the current user. - dk3app_get_homedir()\n retrieves the home directory of the current user. - dk3app_get_language()\n retrieves the users language. - dk3app_get_region()\n retrieves the users region (country). - dk3app_get_appname()\n retrieves the application name. - dk3app_get_appgroup()\n retrieves the application group name. - dk3app_get_execfilename()\n retrieves the name of the executable file. - dk3app_get_bindir()\n retrieves the name of the binary directory (i.e. /usr/bin). - dk3app_get_etcdir()\n retrieves the name of the system configuration directory (i.e. /etc). - dk3app_get_sharedir()\n retrieves the name of the data root directory (i.e. /usr/share). - dk3app_get_vardir()\n retrieves the name of the local state directory (i.e. /var). - dk3app_get_encoding()\n retrieves the internal encoding used for text strings stored in memory, one from: DK3_ENCODING_PLAIN, DK3_ENCODING_UTF8, DK3_ENCODING_UTF16, DK3_ENCODING_UNICODE. - dk3app_get_input_stdin_encoding()\n retrieves the default encoding expected for input on stdin: DK3_FILE_ENCODING_ASCII, DK3_FILE_ENCODING_UTF8, DK3_FILE_ENCODING_UTF16_MSB_FIRST, DK3_FILE_ENCODING_UTF16_LSB_FIRST, DK3_FILE_ENCODING_UNICODE_MSB_FIRST, DK3_FILE_ENCODING_UNICODE_LSB_FIRST. - dk3app_get_input_file_encoding()\n retrieves the default encoding expected when processing input from files. - dk3app_get_output_encoding()\n retrieves the default encoding to write output files. @section dk3appresourcesearch Resource file search The dk3app_find_data_file() searches for a file specified by short file name without leading directory. It searches for a matching file in a couple of directories, depending on the users language and region. The full path name of the most relevant file found is copied into the result buffer on success. @section dk3applocalized Using localized texts Use the dk3app_messages() function. This function attempts to load a message text array from the named file. If this fails the original text array containing the default texts is returned. The memory for the strings from file is allocated dynamically and released automatically during dk3app_close(). Note the NULL as the finalizing pointer at the end of the default texts array. @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { dkT("Hello world"), dkT("Goodbye world"), NULL }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); dk3sf_initialize_stdout(); dk3sf_fputs(msg[0], stdout); dk3sf_fputc(dkT('\n'), stdout); dk3sf_fputs(msg[1], stdout); dk3sf_fputc(dkT('\n'), stdout); dk3app_close(app); } } @endcode When using the dk3app module in conjunction with dkct you should use a *.ctr file: @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { $!string-table macro=dkT,file=myprog.str # # 0: Greeting "Hello world" at start of program. # Hello world # # 1: Greeting "Goodbye world" at end of program. # Goodbye world $!end NULL }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); dk3sf_initialize_stdout(); dk3sf_fputs(msg[0], stdout); dk3sf_fputc(dkT('\n'), stdout); dk3sf_fputs(msg[1], stdout); dk3sf_fputc(dkT('\n'), stdout); dk3app_close(app); } } @endcode When dkct is run on the file the $!string-table...$!end construct is converted to an array of dkChar strings and a myprog.str file is written containing an english version of the string table. Translators can use this file as a starting point to create string tables in other languages. Note the comments before each text: We comment the index, we need the index later to select the correct element from the array. Additionally we describe the context of the text (is it a diagnostic message or a button label...). @section dk3apphelp Localized help texts The dk3app_help() function can be used to show a help text. Specify a short file name, the function searches for a file in the users language. If no such file is found the default help texts are shown. @section dk3applog Logging @subsection dk3applogfull Fully controlled message from multiple parts The dk3app_log_msg() function issues a log message consisting of multiple parts. The arguments are: - An appliction object. - The log level (DK3_LL_PANIC, DK3_LL_FATAL, DK3_LL_ERROR, DK3_LL_WARNING, DK3_LL_INFO, DK3_LL_PROGRESS, or DK3_LL_DEBUG). - A pointer to an array of string pointers. The array contains the individual messages parts, all parts are concatenated. - The number of elements in the array. @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { dkT("Hello world"), dkT("Goodbye world"), dkT("This is a"), dkT(" simple message consisting"), dkT(" of multiple parts"), NULL }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); { dkChar const * logmsg[3]; logmsg[0] = msg[2]; logmsg[1] = msg[3]; logmsg[2] = msg[4]; dk3app_log_msg(app, DK3_LL_ERROR, (dkChar const * const *)logmsg, 3); } dk3app_close(app); } } @endcode @subsection dk3applogsimple Simplified logging Mostly diagnostic messages consist of fixed parts (i.e. "Failed to open file:") and variable parts (i.e. the file name to report). The fixed parts are typically obtained from a localized message text array. The dk3app_log_1(), dk3app_log_3() and dk3app_log_5() functions can be used for log messages consisting of 1 constant part, 2 constant parts enclosing one variable part or 3 constant parts enclosing 2 variable parts. @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { dkT("Hello world"), dkT("Goodbye world"), dkT("Failed to open file \""), dkT("\"!"), NULL }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; dkChar const *filename; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); ... set filename ... dk3app_log_3(app, DK3_LL_ERROR, msg, 2, 3, filename); dk3app_close(app); } } @endcode @subsection dk3appsttfile Provide english string table file In the previous example the string defaults were written as an array. When using dkct there is a special notation available in *.ctr, *.cpt, *.wxc, and *.mtr files: @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { $!string-table file=myprog.str,macro=dkT # # 0: The greeting text to say hello. # Hello world # # 1: The greeting text to say goodbye. # Goodbye world # # 2/3: Error message: Failed to open file "..."! # Failed to open file " "! $!end }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; dkChar const *filename; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); ... set filename ... dk3app_log_3(app, DK3_LL_ERROR, msg, 2, 3, filename); dk3app_close(app); } } @endcode In a $!string-table ... $!end environment you can write a string table in string table syntax. This string table is converted into an array of texts when dkct is run. If the $!string-table command has a file=... argument the original string table is written to the specified file. Users localizing the software to their language can use this english string table file as a template. @subsection dk3apploginternal Internal message texts The dk3app_log_i1(), dk3app_log_i3() and dk3app_log_i5() functions use constant texts maintained by the dk3app module itself. I.e. if a file name is too long to be stored into a buffer you can use the following code to complain about that. @code #include #include static dkChar const gn[] = { "tests" }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; dkChar const *filename; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { ... set filename ... dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, filename); dk3app_close(app); } } @endcode See section @ref dk3appref below for details about the messages texts used by the dk3app module. @subsection dk3appmaxloglevel Getting the maximum log level The dk3app_max_log_level() returns the numeric maximum of the log levels required to write a diagnostic message to any output direction. If diagnostic messages require a special preparation - i.e. conversion of an IP address to text - one can use code like this: @code if(dk3app_max_log_level(app) >= DK3_LL_DEBUG) { ... convert IP address to text ... dk3app_log_3(app, DK3_LL_DEBUG, msg, i1, i2, text); } @endcode @subsection dk3apperrorposition Showing the error position Programs processing text files should show the error position in the file in diagnostic messages. Use dk3app_set_source_file() and dk3app_set_source_line() to set the error position. Use dk3app_get_source_file() and dk3app_get_source_line() to retrieve the current position (i.e. to save it now and restore it later). @section dk3appcfgsearch Configuration file search The dk3app_find_config_file() function can be used to search for a configuration file specified by short filename (without leading directory information). On success the program returns a pointer to a new dk3_search_t structure containing the file names found. When traversing the search results the file names are returned in order from low priority (most general configuration file) to high priority (application and user specific). If you want to process the most relevant file only, use dk3app_find_config_file_revers() and process the first result only. This function returns the search results in reversed sort order, most relevant file first. @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { dkT("File \""), dkT("\" found."), NULL }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; dkChar const *fn = NULL; dk3_search_t *result = NULL; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); result = dk3app_find_config_file(app, dkT("test.conf")); if(result) { dk3search_reset(result); dk3sf_initialize_stdout(); while((fn = dk3search_next(result)) != NULL) { dk3sf_fputs(msg[0], stdout); dk3sf_fputs(fn, stdout); dk3sf_fputs(msg[1], stdout); } dk3search_close(result); } dk3app_log_3(app, DK3_LL_ERROR, msg, 2, 3, filename); dk3app_close(app); } } @endcode @section dk3appkeywords Get keywords (localized or non-localized) The dk3app module reads a string table containing 350+ texts when a new dk3_app_t is opened. Applications or other modules can access these texts by number using dk3app_localized(). Other non-localized texts are built-in into dk3app, use dk3app_not_localized() to retrieve one of these texts. @section dk3appprefs Preferences Preferences are key=value pairs. Preferences can be set in the dk3pref.conf file, from within the program itself or on the command line. The dk3app_get_pref() function retrieves preferences, the dk3app_set_pref() function sets preferences. Preferences set by dk3app_set_pref() are written back to file $HOME/.dk3app/application/dk3pref.conf during dk3app_close(). The dk3app_unconfigure() function instructs dk3app_close() to remove the $HOME/.dk3app/application/dk3pref.conf file instead of writing an updated file. The dk3app_get_sys_pref() function retrieves preferences only from system configuration files (users configuration files and command line preference overrides are ignored). So only values configured by the administrator or the program itself are returned. @section dk3apptempfiles Temporary files The dk3app_get_tmp_file_name() function creates a name for a temporary file and saves it to a buffer provided as argument. @section dk3appstdin Processing standard input The dk3app_process_stdin_chars() and dk3app_process_stdin_lines() functions can be used to process standard input character by character or line by line. Both functions save standard input to a temporary file first. The file is inspected for a BOM (byte order marker) at the beginning of the file to process the file in correct encoding. @section dk3apprandom Random data generation The functions related to random data generation are declared in dk3app.h, the implementation is in the dk3appr module in the dk3csrnd library. Depending on available system functions and libraries a set of different random data generators can be used: - simple (srand()/rand()) - rand48 (lrand48()) - random (initstate()/setstate()/random()) - openssl (PRNG from the OpenSSL library) The dk3app_rand_init() function must be used to initialize random number generation. In the il argument you can specify the allowed PRNG types, i.e. "random,openssl". If one of the PRNG types is available and can be seeded the function succeeds. The dk3app_rand_bytes() function can be used to obtain random data. The dk3app_rand_bytes_non_crypto() can be used to obtain random data for non-cryptographic purposes. The dk3app_rand_end() function inidicates that we are done with random number generation. So wen can attempt to save random seed to a file. This function is invoked automatically from dk3app_close() when dk3app_rand_init() was called for the dk3_app_t object. @section dk3appchangeuser Change user for daemon For a daemon dk3_app_t object we can use dk3app_change_user() to change ownership for all writable files and directories assigned to the dk3_app_t object to a new user and group. @section dk3appref Reference @subsection dk3applogref Diagnostic messages reference Use the table contents as follows: If you want to show an error "Not enough memory" you find one index number (9) in the table. So the code to show the message is: @code dk3app_log_i1(app, DK3_LL_ERROR, 9); @endcode If a user specified an unknown digest type for checksumming and you have the name available in the mdname variable you will find "127, 128, m" in the table. The message consists of three parts, so the code is @code dk3app_log_i3(app, DK3_LL_ERROR, 127, 128, mdname); @endcode
 
Resources
Not enough memory!9
Not enough memory, failed to allocate ... bytes!12, 13, text
Numeric overflow in size calculation!15
Numeric overflow in size calculation, x elements per y bytes!16, 17, 18, e, n
Failed to create directory for log file!46
Too many requests for temporary file names!54
Process table overflow!276
Too many open files!277
Resource shortage!294
Timeout occured!299
 
Memory, string operations, data buffers, data structures
String too long!108
Command name too long!109
Destination buffer too small!38
Directory name ... too long!59, 60, d
Directory name too long!87
HOME directory name too long!194
File name ... too long!65, 66, f
Command ... is too long!103, 104, c
Command is too long!105
File name for log file gets too long!45
The name of the temporary directory is too long!49
Preference name too long!51
Current locale too long!254
Illegal characters in source string, conversion failed!67
Illegal characters in source string!112
Illegal characters in source bufer!113
String contains non-ISO-LATIN-1 characters!219
Illegal destination encoding!114
Conversion to UTF-8 failed!115
Conversion to UTF-16 failed!116
UTF-8 decoding failed!118
UTF-16 decoding failed!119
Result characters not available for destination encoding!117
Mismatch between encoding and character size!125
Unknown message digest type: ...!127, 128, m
Not support for message digest ...!156, 157, m
Illegal message digest or encoding!158
Unknown encoding: ...!129, 130, e
Encoding not supported by C runtime library!204
Index out of range!200
Misconfigured start/end for range!220
New range conflicts with existing one!221
Matrix expansion requires a square matrix!201
Incomplete input sequence!218
Syntax error!223
Record too large!245
Failed to convert timestamp to local time!268
 
File I/O, reading and writing data
Failed to read directory ...!63, 64, d
Failed to obtain information about file ...!61, 62, f
Failed to information about ... (file/directory)!96, 97, f
Failed to change into directory: ...!242, 243, d
Not a regular file: ...!255, 256, f
No information about a file!98
Failed to create directory ...!84, 85, d
Failed to create directory!86
Failed to remove directory!68
Failed to remove directory ...!69, 70, d
Failed to remove file ...!88, 89, f
Failed to remove file!90
Failed to save preference entry k=v!56, 57, 58, k, v
File ... is a directory!74, 75, f
File ... exists, but is not a directory!81, 82, f
Not a directory: ...!202, 203, f
File exists, but is not a directory!83
Can not open file, name refers to a directory76
Symlink owner of ... is not owner of file!100, 101, f
Symlink owner is not file owner!102
Failed to open file ...!143, 144, f
Failed to open file!145
Failed to open file ... for write access!77, 78, f
Failed to open file for write access!79
Failed to write data!120
Write operation failed, ... of ... bytes written!170,171,172,b,s
Write operation failed, ... of ... elements written! 174,175,176,e,s
Write operation failed!173
Failed to write data to file: ...!343, 344, f
Failed to read data from file!345
Failed to read data from file: ...!346, 347, f
Failed to flush output!121
Failed to close data stream object!122
Error while closing file!340
Error while closing file ...!341, 342, f
Stream not opened for write operations!123
Failed to read data!124
I/O error occured!329
Too many symbolic links in path!330
Illegal pathname (missing a parent directory)!331
File system is mounted read-only!332
Stale NFS file handle!333
Server for remote file not available!334
No space left on device!335
Too many .. entries in file name ...!110, 111, f
Too many .. entries in file name!126
Checksumming is available for regular files only!159
Resource file ... not found!150, 151, f
Configuration file ... not found!154, 155, f
Too many file names match pattern ..., just one allowed168, 169, p
No file name matches pattern ...!215, 216, p
Failed to retrieve console settings!265
Failed to restore console settings!266
Failed to modify console settings!267
Failed to change ownership for file ...!270, 271, f
Failed to change file permissions for ...!272, 273, f
Insufficient permissions!274
 
Compression and encoding
Flate compression not supported!262
Illegal compression cell type used!263
Error during previous compression operations!264
 
Finding information
Failed to find current working directory53
Failed to obtain the users login name!43
Failed to find the uses home directory!44
Failed to find current host name!131
Failed to retrieve current locale!253
Failed to find local state (var) directory!50
Failed to obtain current time!80
No user record for ...!92, 93, u
No matching user record found!94
No user name entry in the record!91
No home directory entry in user record!95
The HOMEDRIVE environment variable is not set!71
The HOMEPATH environment variable is not set72
The PATH environment variable is not defined!106
Attempt to read preferences file ... (information).230, 231, f
Failed to enumerate printers!244
 
Options and command line arguments
Errors occured while processing command line options!252
Malformed preference entry on command line52
Unknown option ...!139, 140, o
Option ... requires an argument!133, 134, o
Option ... too long for processing!135, 136, o
Not a numeric value: ...!141, 142, o
Not a boolean value: ...!146, 147, o
Not a hex number!222
Ignoring irrelevant argument in ...!137, 138, a
Option name missing in long option: ...!160, 161, o
Failed to convert a numeric value to text!162
Too many command line arguments! Ignoring...164, 165, a
 
Images, printing
Image file type unknown or not supported!257
Bits per component restricted to 16!258
Failed to set bitmap image frame!261
Incorrect page setup, no usable space between borders!259
Mathematical error in size calculations!260
 
Databases
File damaged or not a database file!246
No support for database type ... available!247, 248, t
Key not found in database!249
DB entry probably damaged - not a multibyte char string!250
Database opened for read access only!251
No file name available for database!269
 
Network
Failed to open network socket!279
Failed to close socket!280
Failed to connect!282
Failed to connect to: ...!351, 352, h
Previous connection attempt not yet completed!295
Connection refused, port not open on peer!296
Socket already connected!297
Failed to bind local address!302
Socket already bound to local address!304
Failed to write data to socket!305
Operation would block!306
Connection reset by peer!307
Peer address required for connectionless socket!308
Peer address specification not allowed for connected socket!309
Message too large to be sent automatically!310
Sending queue full for socket!311
Writing to a pipe without a reader!312
Less bytes were written than required!313
Failed to read data from socket!314
Failed to shut down socket!315
Socket not connected!316
Failed to accept incoming connection request!317
Connection aborted!318
Network protocol error!319
Network subsystem not available!320
Windows sockets not initialized!321
A blocking WinSock 1.1 operation is in progress!322
Socket type doesn't correspond to address family!323
Socket not configured for broadcasts!324
Requested address is not available!325
Host unreachable!326
Windows sockets version not available!327
Too many processes use Windows sockets at this time!328
Network unreachable!298
Failed to listen for incoming requests!283
Failed to create any listener socket for socket set!364
Failed to wait for sockets to become ready, timed out!336
Failed to find IP address for: ...!284, 285, h
No valid socket found in set!359
Connection from ... accepted (information).360, 361, c
Connection from ... rejected!362, 363, c
Host not found!286
Host exists, but no IP address assigned!287
Failed to find address for host!338
Failed to set socket options!339
Failed to convert text address to address!337
Local address already in use!293
Access denied by firewall or due to insufficient permissions!292
Can not connect to remote port 0!291
Problem on DNS server!288
Temporary problem on DNS server, try again later!289
Not an IP address: ...!348, 349, a
Not an IP address!350
Netmask is not a dotted IP addres!354
Netmask is not a bit number!355
Netmask is not an IPv6 address!356
No name resolution available, please specify IP address!357
Interrupted by signal!281
Unknown or illegal address family!275
Failed to retrieve socket state!301
Protocol not supported!278
No gethostbyname() function available!290
No select() function available!358
No select() function available, timeout settings ignored!300
No function available to check blocking/non-blocking state!353
 
Random data generation
Failed to create random data!177
No usable PRNG found!178
Failed to seed simple PRNG!179
Failed to seed lrand48() PRNG!180
Failed to seed random() PRNG!181
Failed to seed OpenSSL PRNG!182
Seed file ... not used (permissions)!183, 184, f
Seed file ... not used (symlink owner)!185, 186, f
Unknown PRNG type: ...!187, 188, p
The srand()/rand() PRNG ist not available!189
The srand48()/lrand48() PRNG is not availanble!190
The random() PRNG is not available!191
The OpenSSL PRNG is not available!192
Failed to save random seed data!193
Attempt to obtain seed data from CryptoAPI (information).227
Attempt to obtain seed data from screen (information).228
OpenSSL PRNG seeded successfully (information).229
 
Text to LaTeX conversion
No directory containing LaTeX encoding tables found!205
LaTeX table directory: ... (information).232, 233, d
Reading LaTeX table directory: ... (information).236, 237, d
Attempting LaTeX table directory: ... (information).234, 235, d
Registering LaTeX conversion range ... (information).238, 239, r
Loading LaTeX conversion data file ... (information).240, 241, f
Redefinition, overwriting ... by ...206,207,208,o,n
Syntax error, index ... is out of range 0...255.209, 201, i
Syntax error near ...!211, 212, t
Syntax error, missing LaTeX encoding213
Syntax error, missing index!214
Character redefinition!224
Range not declared in character directory!225
Package name conflicts with previous definition!226
*/ /** @page stringtable String table files. @section dk3sttstructure File structure The string table file consists of string lines and comment lines. A comment is started by a raute sign "#" immediately on the beginning of the line (no leading spaces allowed). All other lines are string lines, each line is used to build one string in the string array. The lines are used in order of appearance. If you need a raute sign at the beginning of a string, use the backslash + raute sequence "\#". If you need a string including newlines write "\n" for the newlines. String table files - as help text files too - must be UTF-8 encoded. @section dk3sttstringfilename File names The string table file name is specified as short file name (without leading directory) to dk3app_messages(). The function searches for the file in the following directories and uses the first file found: - \$(datarootdir)/programname/language/region - \$(datarootdir)/programgroup/language/region - \$(datarootdir)/dk3app/language/region - \$(datarootdir)/language/region - \$(datarootdir)/programname/language - \$(datarootdir)/programgroup/language - \$(datarootdir)/dk3app/language - \$(datarootdir)/language - \$(datarootdir)/programname/en - \$(datarootdir)/programgroup/en - \$(datarootdir)/dk3app/en - \$(datarootdir)/en - \$(datarootdir)/programname - \$(datarootdir)/programgroup - \$(datarootdir)/dk3app - \$(datarootdir) @section dk3sttstringexample Example To write an appropriate string table file for @code #include #include static dkChar const gn[] = { "tests" }; static dkChar const * const mytexts[] = { dkT("Hello world."), dkT("Goodbye world."), NULL }; DK3_MAIN { dk3_app_t *app = NULL; dkChar const * const *msg = NULL; app = dk3app_open_command(argc, (dkChar const * const *)argv, gn); if(app) { msg = dk3app_messages(app, dkT("myprog.str"), (dkChar const **)mytexts); dk3sf_initialize_stdout(); dk3sf_fputs(msg[0], stdout); dk3sf_fputc(dkT('\n'), stdout); dk3sf_fputs(msg[1], stdout); dk3sf_fputc(dkT('\n'), stdout); dk3app_close(app); } } @endcode we could write /usr/local/share/tests/de/de/myprog.str as @code # # 0: Message text: Hello world. # Guten Tag. # # 1: Message text: Goodbye world. # Auf Wiedersehen. @endcode Here are some recommendations for comments: - You should have a comment with the entry (string) number before each string. - Additionally the comment should show the purpose and the original message in english language. */