%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% header #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif /** Open application structure for command line application. * Diagnostic messages are written to stderr and to the log file. * The log file $HOME/log/application-pid.log * is removed automatically by dk3app_close() unless there was an * error message. * @param argc Number of command line arguments. * @param argv Command line arguments array. * @param gn Application group name. * @return Pointer to new application on success, NULL on error. */ dk3_app_t * dk3app_open_command(int argc, dkChar const * const * argv, dkChar const *gn); /** Open application structure for GUI application. * Diagnostic messages are written to the log file only. * The log file is removed automatically by dk3app_open() unless * there were error messages. * Typically this function is invoked from a DkWxAppHelper constructor. * @param argc Number of command line arguments. * @param argv Command line arguments array. * @param gn Application group name. * @return Pointer to new application on success, NULL on error. */ dk3_app_t * dk3app_open_gui(int argc, dkChar const * const * argv, dkChar const *gn); /** First silence check to correct the type if necessary. Do not report errors directly, set app->de instead. @param app Application structure. @param argc Number of command line arguments. @param argv Command line arguments array. */ int dk3app_first_silence_check(dk3_app_t *app,int argc,dkChar const * const *argv); /** Open application structure for a daemon. * Log messages are appended to * ${localstatedir}/log/applicationname/applicationname.log. * @param wd Working directory when starting the program. * @param argc Number of command line arguments. * @param argv Command line arguments array. * @param gn Application group name. * @return Pointer to new application on success, NULL on error. */ dk3_app_t * dk3app_open_daemon(dkChar const *wd, int argc, dkChar const * const * argv, dkChar const *gn); /** Open application structure for a silent application (no diagnostics). * @param argc Number of command line arguments. * @param argv Command line arguments array. * @param gn Application group name. * @return Pointer to new application on success, NULL on error. */ dk3_app_t * dk3app_open_silent(int argc, dkChar const * const * argv, dkChar const *gn); /** Close application structure, release dynamic memory and resources * assigned to the object. * @param app Application to close. */ void dk3app_close(dk3_app_t *app); /** Log a message consisting of multiple parts. * @param app Application structure. * @param ll Log level. * @param msg Message parts array. Pointer to an array * of string pointers, all array elements are concatenated to * create the message text. * @param nmsg Number of elements in the array. */ void dk3app_log_msg(dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg); /** Log message consisting of one part. * @param app Application structure. * @param ll Log level. * @param msg Message texts array, typically localized, obtained * from dk3app_messages(). * @param i1 Index of message text in \a msg. */ void dk3app_log_1(dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1); /** Log message consisting of two parts. * @param app Application structure. * @param ll Log level. * @param msg Message texts array, typically localized, obtained * from dk3app_messages(). * @param i Index of message text in \a msg. * @param st String to write as second part. */ void dk3app_log_2( dk3_app_t *app, int ll, dkChar const * const * msg, size_t i, dkChar const *st ); /** Log message consisting of three parts. * @param app Application structure. * @param ll Log level. * @param msg Message string array. * @param i1 Index of first message text in \a msg. * @param i2 Index of third message text in \a msg. * @param st Second message text. */ void dk3app_log_3( dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1, size_t i2, dkChar const *st ); /** Log message consisting of five parts. * @param app Application structure. * @param ll Log level. * @param msg Message string array. * @param i1 Index of first message text in \a msg. * @param i2 Index of third message text in \a msg. * @param i3 Index of fifth message text in \a msg. * @param st1 Second message text. * @param st2 Fourth message text. */ void dk3app_log_5( dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1, size_t i2, size_t i3, dkChar const *st1, dkChar const *st2 ); /** Log message consisting of one part. * @param app Application structure. * @param ll Log level. * @param i1 Index of message text in messages array. */ void dk3app_log_i1(dk3_app_t *app, int ll, size_t i1); /** Log message consisting of two parts. * @param app Application structure. * @param ll Log level. * @param i Index of first message text in messages array. * @param st Second message text. */ void dk3app_log_i2(dk3_app_t *app, int ll, size_t i, dkChar const * st); /** Log message consisting of three parts. * @param app Application structure. * @param ll Log level. * @param i1 Index of first message text in messages array. * @param i2 Index of third message text in messages array. * @param st Second message text. */ void dk3app_log_i3( dk3_app_t *app, int ll, size_t i1, size_t i2, dkChar const *st ); /** Log message consisting of five parts. * @param app Application structure. * @param ll Log level. * @param i1 Index of first message text in messages array. * @param i2 Index of third message text in messages array. * @param i3 Index of fifth message text in messages array. * @param st1 Second message text. * @param st2 Fourth message text. */ void dk3app_log_i5( dk3_app_t *app, int ll, size_t i1, size_t i2, size_t i3, dkChar const *st1, dkChar const *st2 ); /** Set file name for current source file position. The source file position is used when writing diagnostic messages. @param app Application structure. @param fn Source file name. Use NULL to disable printing the file name. */ void dk3app_set_source_file(dk3_app_t *app, dkChar const *fn); /** Set source line number for current source file position. The source file position is used when writing diagnostic messages. @param app Application structure. @param li Line number. Use 0UL to disable printing the line number. */ void dk3app_set_source_line(dk3_app_t *app, unsigned long li); /** Get current source file name. @param app Application structure. @return Current source file name, may be NULL. */ dkChar const * dk3app_get_source_file(dk3_app_t const *app); /** Get current source line number. @param app Application structure. @return Current source file line number, may be 0UL. */ unsigned long dk3app_get_source_line(dk3_app_t const *app); /** Get number of command line arguments. @param app Application structure. @return Number of command line arguments. */ int dk3app_get_argc(dk3_app_t const *app); /** Get command line arguments array. @param app Application structure. @return Command line arguments array. */ dkChar const * const * dk3app_get_argv(dk3_app_t const *app); /** Retrieve application name. @param app Application structure. @return Application name on success, NULL on error. */ dkChar const * dk3app_get_appname(dk3_app_t const *app); /** Retrieve name of executable file. * @param app Application structure. * @return Executable file name on success, NULL on error. */ dkChar const * dk3app_get_execfilename(dk3_app_t const *app); /** Retrieve binary directory name. @param app Application structure. @return Name of bin directory on success, NULL on error. */ dkChar const * dk3app_get_bindir(dk3_app_t const *app); /** Get system configuration directory (/etc or /usr/local/etc). @param app Application structure. @return Directory name on success, NULL on error. */ dkChar const * dk3app_get_etcdir(dk3_app_t const *app); /** Get data root directory (/usr/share or /usr/local/share). @param app Application structure. @return Directory name on success, NULL on error. */ dkChar const * dk3app_get_sharedir(dk3_app_t const *app); /** Get local state directory (/var or /usr/local/var). @param app Application structure. @return Directory name on success, NULL on error. */ dkChar const * dk3app_get_vardir(dk3_app_t const *app); /** Get user login name. @param app Application structure. @return Login name on success, NULL on error. */ dkChar const * dk3app_get_logname(dk3_app_t const *app); /** Get host name. @param app Application structure. @return Host name on success, NULL on error. */ dkChar const * dk3app_get_hostname(dk3_app_t const *app); /** Get users home directory. @param app Application structure. @return Home directory on success, NULL on error. */ dkChar const * dk3app_get_homedir(dk3_app_t const *app); /** Get application group name. @param app Application structure. @return Group name on success, NULL on error. */ dkChar const * dk3app_get_appgroup(dk3_app_t const *app); /** Retrieve users language. @param app Application structure. @return Pointer to users language or NULL if no language is defined. */ dkChar const * dk3app_get_language(dk3_app_t const *app); /** Retrieve users region. @param app Application structure. @return Pointer to users region or NULL if no region is defined. */ dkChar const * dk3app_get_region(dk3_app_t const *app); /** Retrieve internal encoding. @param app Application structure. @return Internal (in-memory) encoding. */ int dk3app_get_encoding(dk3_app_t const *app); /** Retrieve output file encoding. @param app Application structure. @return Output file encoding. */ int dk3app_get_output_encoding(dk3_app_t const *app); /** Retrieve default encoding expected on stdin. @param app Application structure. @return Expected input encoding (DK3_FILE_ENCODING_xxx). */ int dk3app_get_input_stdin_encoding(dk3_app_t const *app); /** Retrieve default encoding expected on files. @param app Application structure. @return Expected input encoding (DK3_FILE_ENCODING_xxx). */ int dk3app_get_input_file_encoding(dk3_app_t const *app); /** Get file name for temporary file. The file name is stored into the buffer @a db. @param app Application structure. @param db Destination buffer. @param sz Size of \a db (number of characters). @return 1 on success, 0 on error. */ int dk3app_get_temp_file_name(dk3_app_t *app, dkChar *db, size_t sz); /** Set a preference value. Preferences set by this function are written to the $HOME/.dk3app/application/dk3pref.conf file during dk3app_close(). @param app Application structure. @param k Key (preference name). @param v Value. @return 1 on success, 0 on error. */ int dk3app_set_pref(dk3_app_t *app, dkChar const *k, dkChar const *v); /** Get a preference value. On success the preference value is written to @a d. @param app Application structure. @param k Key (preference name). @param d Destination buffer. @param s Size of \a d (number of characters). @return 1 on success, 0 on error. */ int dk3app_get_pref(dk3_app_t *app, dkChar const *k, dkChar *d, size_t s); /** Get boolean preference value. @param app Application structure. @param name Preference name. @param dv Default value if preference not found. @return Preference value or default value. */ int dk3app_get_pref_bool(dk3_app_t *app, dkChar const *name, int dv); /** Get int preference value. @param app Application structure. @param name Preference name. @param dv Default value. @return Preference value or default value. */ int dk3app_get_pref_int(dk3_app_t *app, dkChar const * name, int dv); /** Get a system preference value. Command line and user-set preferences are ignored. @param app Application structure. @param k Key (preference name). @param d Destination buffer. @param s Size of \a d (number of characters). @return 1 on success, 0 on error. */ int dk3app_get_sys_pref(dk3_app_t *app, dkChar const *k, dkChar *d, size_t s); /** Unconfigure application. @param app Application structure. */ void dk3app_unconfigure(dk3_app_t *app); /** Find configuration file. On success the function returns a file name collection. Configuration files with low priority are at the start of the collection, files with higher priority are at the end. This allows higher priorized configuration files to overwrite settings made by the previously processed files. After you are done with the search results set, use dk3search_close() to close the set and release resources assigned to it. @param app Application structure. @param fn File name to search for (short filename without leading path). @param exclu Flag: Exclude users configuration file. @return Collection of file names (full path names including the leading directory), use dk3search_close() after use to destroy it. */ dk3_search_t * dk3app_find_config_file(dk3_app_t *app, dkChar const *fn, int exclu); /** Find configuration file in reverse search order (most significant file first). This function is typically used to process the first file from the set only which is the most significant file. After you are done with the search results set, use dk3search_close() to close the set and release resources assigned to it. @param app Application structure. @param fn File name to search for (short file name without leading directory). @param exclu Flag: Exclude users configuration files. @return Collection of file names (full path names with leading directory), use dk3search_close() after use to destroy it. */ dk3_search_t * dk3app_find_config_file_revers(dk3_app_t *app, dkChar const *fn, int exclu); /** Find data file. The full path name of the file found is written to @a db on success. @param app Application structure. @param fn File name to search for (short file name without leading directory). @param db Destination buffer. @param sz Size of \a db (number of characters). @return 1 on success, 0 on error. */ int dk3app_find_data_file(dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz); /** Get string table. @param app Application structure. @param fn Short file name of string table. @param dv Default value, used if file not found. @return New string table if found or \a dv on problems. */ dkChar const * const * dk3app_messages(dk3_app_t *app, dkChar const *fn, dkChar const * const *dv); /** Find and print help text. The function searches for a help text file in the users language. If no file is found the default text is printed. @param app Application structure. @param fn Help text file name (short name wih). @param dt Default text to use if file not found. */ void dk3app_help(dk3_app_t *app, dkChar const *fn, dkChar const * const *dt); /** Get log level used for stderr. @param app Application structure. @return Log level required for logging to stderr. */ int dk3app_get_stderr_log_level(dk3_app_t const *app); /** Set log level used for stderr. @param app Application structure. @param ll New log level. */ void dk3app_set_stderr_log_level(dk3_app_t *app, int ll); /** Report write error. @param app Application structure. @param ll Log level. @param wished Number of bytes wished to write. @param written Number of bytes written. */ void dk3app_log_write_error(dk3_app_t *app, int ll, size_t wished, size_t written); /** Report fwrite error. @param app Application structure. @param ll Log level. @param wished Number of elements wished to write. @param written Number of elements written. */ void dk3app_log_fwrite_error(dk3_app_t *app, int ll, size_t wished, size_t written); /** Get a localized text. @param app Application structure. @param num Index of string in array. @return Pointer to localized string on success, NULL on error. */ dkChar const * dk3app_localized(dk3_app_t const *app, size_t num); /** Get a non-localized text. @param num Index of string in array. @return Pointer to localized string on success, NULL on error. */ dkChar const * dk3app_not_localized(size_t num); /** Initialize random number generator. Set up allowed PRNG types and seed best PRNG found. If at least one of the PRNG types specified in @a il is available we attempt to seed this PRNG. The following preferences are used by this function: - /rand/types is used if il is NULL. - /rand/file/allowed configured whether or not usage o seed file in the users home directory is allowed - /rand/egd/name can be used to specify of the EDG socket if an EGD (entropy gathering daemon) is running on the system. By default /dev/urandom and/or /dev/random are used to seed a PRNG if available. @param app Application structure. @param il Text line to process, may be NULL. If this argument is NULL, the /rand/types preference is used to find the allowed PRNG types. @return 1 on success, 0 on error. */ int dk3app_rand_init(dk3_app_t *app, dkChar const *il); /** Retrieve list of allowed PRNG types from a text line. If the text line \a il pointer is NULL the /rand/types preference value is used. @param app Application structure. @param il Text line to process. @return Combination of DK3_PRNG_xxx. */ int dk3app_get_allowed_prng_types(dk3_app_t *app, dkChar const *il); /** Retrieve pseudo-random bytes. @param app Application structure. @param db Destination buffer. @param sz Size of \a db (number of bytes). @return Number of bytes found. */ size_t dk3app_rand_bytes(dk3_app_t *app, void *db, size_t sz); /** Retrieve pseudo-random bytes. The bytes will not be used for cryptographic or authentication purposes, so we can use a less unpredictive (less complicated und thus faster) generation mechanism. @param app Application structure. @param db Destination buffer. @param sz Size of \a db (number of bytes). @return Number of bytes found. */ size_t dk3app_rand_bytes_non_crypto(dk3_app_t *app, void *db, size_t sz); /** Attempt to save random seed to file when closing an application. @param app Application structure. */ void dk3app_rand_end(dk3_app_t *app); /** Get default input encoding for stdin ignoring preferences. @param app Application structure. @return Encoding (DK3_FILE_ENCODING_xxx). */ int dk3app_get_default_stdin_encoding(dk3_app_t const *app); /** Get default input encoding for files ignoring preferences. @param app Application structure. @return Encoding (DK3_FILE_ENCODING_xxx). */ int dk3app_get_default_file_encoding(dk3_app_t const *app); /** Process standard input character by character. Attempt to save stdin data to file so we can do a BOM check. @param app Application structure. @param obj Object to modify while processing data. @param hf Handler function. @param de Default encoding. */ int dk3app_process_stdin_chars( dk3_app_t *app, void *obj, dk3_char_handler_t *hf, int de ); /** Process standard input line by line. Attempt to save stdin data to file so we can do a BOM check. @param app Application structure. @param obj Object to modify while reading data. @param hf Handler function. @param buffer Line buffer. @param szbuffer Size of buffer. @param de Default encoding. */ int dk3app_process_stdin_lines( dk3_app_t *app, void *obj, dk3_line_handler_t *hf, dkChar *buffer, size_t szbuffer, int de ); /** Get maximum log level used by the application. @param app Application structure. @return Maximum log level used by the application. */ int dk3app_max_log_level(dk3_app_t const *app); /** Remove trailing newline and handle backslash escape sequences. This function is run on lines read from string table file. @param lb Line buffer. */ void dk3app_squeeze_line(char *lb); #if !DK3_ON_WINDOWS #if DK3_HAVE_SETUID && DK3_HAVE_SETGID && DK3_HAVE_CHOWN #if DK3_CHAR_SIZE == 1 /** Change ownership to writable files. This function is used by daemons before switching to a non-privileged user account. @param app Application structure. @param uid New user ID for process. @param gid New group ID for process. @return 1 on success, 0 on error. */ int dk3app_change_user(dk3_app_t *app, uid_t uid, gid_t gid); #endif #endif #endif /** Retrieve directory setting from preference. @param app Application structure. @param pn Preference name. @param buf Result buffer. @param bs Size of bs (number of dkChar). @param ch Flag: Check existance of directory. @return 1 on success, 0 on error. */ int dk3app_get_dir_from_pref( dk3_app_t *app, dkChar const *pn, dkChar *buf, size_t bs, int ch ); #ifdef __cplusplus } #endif %% module #include "dk3all.h" #if DK3_HAVE_OPENSSL_RAND_H #include #endif $(trace-include) /** Names of preference scope attributes. */ static dkChar const * const dk3app_scope_attributes[] = { /* 0 */ dkT("user"), /* 1 */ dkT("application"), /* 2 */ dkT("application-group"), /* 3 */ dkT("host"), /* 4 */ dkT("language"), /* 5 */ dkT("region"), NULL }; /** Text strings, not localized. */ static dkChar const * const dk3app_no_loc[] = { /* 0 */ dkT("bin"), /* Used to build bindir. */ /* 1 */ dkT("etc"), /* Used to build etcdir. */ /* 2 */ dkT("share"), /* Used to build sharedir. */ /* 3 */ dkT("var"), /* Used to build vardir. */ #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH /* 4 */ dkT("\\log"), /* Used to build log directory. */ #else /* 4 */ dkT("/log"), /* Used to build log directory. */ #endif /* 5 */ dkT("-"), /* Used to build log file name. */ /* 6 */ dkT(".log"), /* Used to build log file name. */ /* 7 */ dkT("/"), /* Used to build log directory. */ /* 8 */ dkT("a"), /* Open mode for log file. */ #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH /* 9 */ dkT("\\tmp"), /* Subdirectory for temporary files. */ #else /* 9 */ dkT("/tmp"), /* Subdirectory for temporary files. */ #endif #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH /* 10 */ dkT("\\run"), /* Subdirectory for temporary files. */ #else /* 10 */ dkT("/run"), /* Subdirectory for temporary files. */ #endif /* 11 */ dkT("LANG"), /* Environment variable for language. */ /* 12 */ dkT("Control Panel\\International"), /* Reg key for language. */ /* 13 */ dkT("LocaleName"), /* Reg entry name for language. */ /* 14 */ dkT("sLanguage"), /* Alternative reg entry name for language. */ /* 15 */ dkT("utf8"), /* Encoding UTF-8 (modern variant). */ /* 16 */ dkT("UTF-8"), /* Encoding UTF-8 (older variant). */ /* 17 */ dkT("dk3app"), /* Subdirectory in system configuration. */ /* 18 */ dkT(".dk3app"), /* Subdirectory in home directory. */ /* 19 */ dkT("."), /* Current directory. */ #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH /* 20 */ dkT("\\"), /* File name separator. */ #else /* 20 */ dkT("/"), /* File name separator. */ #endif /* 21 */ dkT("dk3pref.conf"), /* Configuration file name. */ /* 22 */ dkT("r"), /* File open mode for reading. */ /* 23 */ dkT("dk3app.str"), /* String table name. */ /* 24 */ dkT("w"), /* File open mode. */ /* 25 */ dkT("="), /* Used when writing preferences. */ /* 26 */ dkT("\n"), /* Used when writing preferences. */ /* 27 */ dkT("/ui/lang"), /* User interface, language. */ /* 28 */ dkT("/log/file/level"), /* Required log level for file. */ /* 29 */ dkT("/log/file/keep"), /* Required level to keep file. */ /* 30 */ dkT("/log/stderr/level"), /* Required log level for stderr. */ /* 31 */ dkT("/temp/dir/keep"), /* Required to keep temp dir. */ /* 32 */ dkT("-site"), /* Check for site-specific config files. */ /* 33 */ dkT("*"), /* Wildcard for all users ... */ /* 34 */ dkT("dk3conf.conf"), /* Configuration file name. */ /* 35 */ dkT("%lu"), /* scanf/printf format. */ /* 36 */ dkT("rb"), /* File open mode: Read binary. */ /* 37 */ dkT("/rand/types"), /* Preference name for allowed PRNG types. */ /* 38 */ dkT(".rnd-simple"), /* Preference name for simple seed file. */ /* 39 */ dkT(".rnd-lrand48"), /* Preference name for lrand48() seed file. */ /* 40 */ dkT(".rnd-random"), /* Preference name for random() seed file. */ /* 41 */ dkT(".rnd-openssl"), /* Preference name for OpenSSL seed file. */ /* 42 */ dkT("/rand/egd/name"), /* Preference name for EGD socket. */ /* 43 */ dkT("EGDSOCKET"), /* Environment variable name for EGD socket. */ /* 44 */ dkT("/dev/urandom"), /* Device name for seed data. */ /* 45 */ dkT("/dev/random"), /* Device name for seed data. */ /* 46 */ dkT("/rand/file/allowed"), /* Preference name. */ /* 47 */ dkT("en"), /* Default language name. */ #if 0 /* 48 */ dkT("/dir/uc2lat-t"), /* Preference name for LaTeX encoding. */ #else /* 48 */ dkT("/dir/charmap"), /* Preference name for LaTeX encoding. */ #endif /* 49 */ #if 0 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH dkT("\\uc2lat-t"), #else dkT("/uc2lat-t"), #endif #else #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH dkT("\\dkt-3\\charmap"), /* Character map subdirectory of share. */ #else dkT("/dkt-3/charmap"), /* Character map subdirectory of share. */ #endif #endif /* 50 */ dkT("/silent"), /* Preference name for silent work. */ /* 51 */ dkT("/input/encoding/file"), /* Preference name. */ /* 52 */ dkT("/input/encoding/stdin"), /* Preference name. */ /* 53 */ dkT("wb"), /* File open mode: Read binary. */ /* 54 */ dkT(".dir"), /* Suffix for uc2lat *.dir files. */ /* 55 */ dkT(".lat"), /* Suffix for uc2lat *.lat files. */ /* 56 */ dkT("sbin"), /* sbin dirctory. */ }; /** Directories where binary executable can reside. */ static dkChar const * const dk3app_bindir_candidates[] = { $!string-table macro=dkT bin sbin lib libexec $!end }; /** Keywords for users configuration files. These keywords can be used in the $HOME/.dk3app/dk3conf.conf file. */ dkChar const * const dk3app_conf_file[] = { /* 0 */ dkT("use-system-config-files"), /* 1 */ dkT("ignore-system-config-files"), NULL }; /** Log level names. */ static dkChar const * const dk3app_log_levels[] = { dkT("n$one"), dkT("pa$nic"), dkT("f$atal"), dkT("e$rror"), dkT("w$arning"), dkT("in$fo"), dkT("pr$ogress"), dkT("d$ebug"), dkT("ig$nore"), NULL }; #if 0 static dkChar const * const dk3app_prng_type_names[] = { /* 0 */ dkT("openssl"), /* OpenSSL PRNG. */ /* 1 */ dkT("random"), /* initstate()/setstate()/random() */ /* 2 */ dkT("rand48"), /* lrand48(). */ /* 3 */ dkT("simple"), /* srand()/rand(). */ NULL }; #endif /** Text strings, localization needed. The texts strings are used as parts of diagnostic messages. */ static dkChar const * const dk3app_kw[] = { $!string-table macro=dkT,file=dk3app.str # # 000: \n # \n # # 001: PANIC # PANIC # # 002: FATAL # FATAL # # 003: ERROR # ERROR # # 004: Warning # Warning # # 005: Information # Information # # 006: Progress # Progress # # 007: Debug # Debug # # 008: # # # 009: Not enough memory (RAM/swap space)! # Not enough memory (RAM/swap space)! # # 010: # # \# # # 011: : # : # # 012: Memory allocation ( # Memory allocation ( # # 013: bytes) failed! # bytes) failed! # # 014: Memory allocation failed! # Memory allocation failed! # # 015: Numeric overflow in size calculation! # Numeric overflow in size calculation! # # 016: Numeric overflow in size calculation ( # Numeric overflow in size calculation ( # # 017: x # x # # 018: bytes)! # bytes)! # # 019: Application " # Application " # # 020: " started. # " started. # # 021: Application " # Application " # # 022: " finished. # " finished. # # 023: Application name: # Application name: # # 024: Application group: # Application group: # # 025: Executable file: # Executable file: # # 026: Directory "bin": # Directory "bin": # # 027: Directory "etc": # Directory "etc": # # 028: Directory "share": # Directory "share": # # 029: Directory "var": # Directory "var": # # 030: Directory "home": # Directory "home": # # 031: Directory "temp": # Directory "temp": # # 032: User: # User: # # 033: Log file: # Log file: # # 034: Language: # Language: # # 035: Region: # Region: # # 036: # # # 037: The name of the temporary directory is too long! # The name of the temporary directory is too long! # # 038: Destination buffer too small! # Destination buffer too small! # # 039: The LANG environment variable is too long! # The LANG environment variable is too long! # # 040: Failed to find name of executable file! # Failed to find name of executable file! # # 041: Too few directories in hierarchy!\nExecutable files should not reside in the root directory! # Too few directories in hierarchy!\nExecutable files should not reside in the root directory! # # 042: File name of executable file too long! # File name of executable file too long! # # 043: Failed to obtain the users login name! # Failed to obtain the users login name! # # 044: Failed to find the users home directory! # Failed to find the users home directory! # # 045: File name for log file gets too long! # File name for log file gets too long! # # 046: Failed to create directory for log file! # Failed to create directory for log file! # # 047: Failed to convert process ID to text! # Failed to convert process ID to text! # # 048: Failed to find application name! # Failed to find application name! # # 049: The name of the temporary directory is too long! # The name of the temporary directory is too long! # # 050: Failed to find local state (var) directory! # Failed to find local state (var) directory! # # 051: Preference name too long! # Preference name too long! # # 052: Malformed preference entry on command line! # Malformed preference entry on command line! # # 053: Failed to find current working directory! # Failed to find current working directory! # # 054: Too many requests for temporary file names! # Too many requests for temporary file names! # # 055: Internal error (bug): Missing a file or directory name! # Internal error (bug): Missing a file or directory name! # # 056: Failed to save preference entry " # Failed to save preference entry " # # 057: "=" # "=" # # 058: "! # "! # # 059: Directory name " # Directory name " # # 060: " too long! # " too long! # # 061: Failed to obtain information about " # Failed to obtain information about " # # 062: "!\nThe stat() function failed! # "!\nThe stat() function failed! # # 063: Failed to read directory " # Failed to read directory " # # 064: "! # "! # # 065: File name " # File name " # # 066: " too long! # " too long! # # 067: Illegal characters in source string, conversion failed! # Illegal characters in source string, conversion failed! # # 068: Failed to remove directory! # Failed to remove directory! # # 069: Failed to remove directory " # Failed to remove directory " # # 070: "! # "! # # 071: The HOMEDRIVE environment variable is not set! # The HOMEDRIVE environment variable is not set! # # 072: The HOMEPATH environment variable is not set! # The HOMEPATH environment variable is not set! # # 073: Failed to obtain information about a file! # Failed to obtain information about a file! # # 074: " # " # # 075: " is a directory! # " is a directory! # # 076: Can not open file, name refers to a directory! # Can not open file, name refers to a directory! # # 077: Failed to open file " # Failed to open file " # # 078: " for write access! # " for write access! # # 079: Failed to open file for write access! # Failed to open file for write access! # # 080: Failed to obtain current time! # Failed to obtain current time! # # 081: File " # File " # # 082: " exists but is not a directory! # " exists but is not a directory! # # 083: File exists but is not a directory! # File exists but is not a directory! # # 084: Failed to create directory " # Failed to create directory " # # 085: "! # "! # # 086: Failed to create directory! # Failed to create directory! # # 087: Directory name too long! # Directory name too long! # # 088: Failed to remove file " # Failed to remove file " # # 089: "! # "! # # 090: Failed to remove file! # Failed to remove file! # # 091: No user name entry in user record! # No user name entry in user record! # # 092: No user record for " # No user record for " # # 093: "! # "! # # 094: No matching user record found! # No matching user record found! # # 095: No home directory entry in user record! # No home directory entry in user record! # # 096: Failed to obtain information about " # Failed to obtain information about " # # 097: "!\nThe lstat() function failed! # "!\nThe lstat() function failed! # # 098: No information about a file, lstat() failed! # No information about a file, lstat() failed! # # 099: No information about a file, lstat() failed! # No information about a file, lstat() failed! # # 100: Owner of symlink " # Owner of symlink " # # 101: " is not owner of file! # " is not owner of file! # # 102: Symlink owner is not file owner! # Symlink owner is not file owner! # # 103: Command " # Command " # # 104: " is too long! # " is too long! # # 105: Command is too long! # Command is too long! # # 106: The PATH environment variable is not defined! # The PATH environment variable is not defined! # # 107: No mkdir() function available! # No mkdir() function available! # # 108: String too long! # String too long! # # 109: Command name too long! # Command name too long! # # 110: Too many ".." entries in file name " # Too many ".." entries in file name " # # 111: "! # "! # # 112: Illegal character(s) in source string! # Illegal character(s) in source string! # # 113: Illegal character(s) in source buffer! # Illegal character(s) in source buffer! # # 114: Illegal destination encoding! # Illegal destination encoding! # # 115: Conversion to UTF-8 failed! # Conversion to UTF-8 failed! # # 116: Conversion to UTF-16 failed! # Conversion to UTF-16 failed! # # 117: Result character(s) not available for destination encoding! # Result character(s) not available for destination encoding! # # 118: UTF-8 decoding failed! # UTF-8 decoding failed! # # 119: UTF-16 decoding failed! # UTF-16 decoding failed! # # 120: Failed to write data! # Failed to write data! # # 121: Failed to flush output! # Failed to flush output! # # 122: Failed to close data stream object! # Failed to close data stream object! # # 123: Stream not opened for write operations! # Stream not opened for write operations! # # 124: Failed to read data! # Failed to read data! # # 125: Mismatch between encoding and character size! # Mismatch between encoding and character size! # # 126: Too many ".." entries in file name! # Too many ".." entries in file name! # # 127: Unknown message digest type: " # Unknown message digest type: " # # 128: "! # "! # # 129: Unknown encoding: " # Unknown encoding: " # # 130: "! # "! # # 131: Failed to find current host name! # Failed to find current host name! # # 132: Host: # Host: # # 133: Option " # Option " # # 134: " requires an argument! # " requires an argument! # # 135: Option " # Option " # # 136: " too long for processing # " too long for processing # # 137: Ignoring irrelevant argument in " # Ignoring irrelevant argument in " # # 138: "! # "! # # 139: Unknown option " # Unknown option " # # 140: "! # "! # # 141: Not a numeric value: " # Not a numeric value: " # # 142: "! # "! # # 143: Failed to open file " # Failed to open file " # # 144: "! # "! # # 145: Failed to open file! # Failed to open file! # # 146: Not a boolean value: " # Not a boolean value: " # # 147: "! # "! # # 148: Resource file " # Resource file " # # 149: " found. # " found. # # 150: Resource file " # Resource file " # # 151: " not found. # " not found. # # 152: Configuration file " # Configuration file " # # 153: " found. # " found. # # 154: Configuration file " # Configuration file " # # 155: " not found. # " not found. # # 156: No support for message digest " # No support for message digest " # # 157: "! # "! # # 158: Illegal message digest or encoding number! # Illegal message digest or encoding number! # # 159: Checksumming is available for regular files only! # Checksumming is available for regular files only! # # 160: Option name missing in long option: " # Option name missing in long option: " # # 161: "! # "! # # 162: Failed to convert a numeric value to text! # Failed to convert a numeric value to text! # # 163: "! # "! # # 164: Too many command line arguments! Ignoring " # Too many command line arguments! Ignoring " # # 165: "...! # "...! # # 166: Internal error (bug) # Internal error (bug) # # 167: . # . # # 168: Too many file names match pattern " # Too many file names match pattern " # # 169: ", just one allowed! # ", just one allowed! # # 170: Write operation failed, # Write operation failed, # # 171: of # of # # 172: bytes written! # bytes written! # # 173: Write operation failed! # Write operation failed! # # 174: Write operation failed, # Write operation failed, # # 175: of # of # # 176: elements written! # elements written! # # 177: Failed to create random data! # Failed to create random data! # # 178: No usable PRNG found! # No usable PRNG found! # # 179: Failed to seed simple PRNG! # Failed to seed simple PRNG! # # 180: Failed to seed lrand48() PRNG! # Failed to seed lrand48() PRNG! # # 181: Failed to seed random() PRNG! # Failed to seed random() PRNG! # # 182: Failed to seed OpenSSL PRNG! # Failed to seed OpenSSL PRNG! # # 183: Seed file " # Seed file " # # 184: " not used (permissions)! # " not used (permissions)! # # 185: Seed file " # Seed file " # # 186: " not used (symlink owner)! # " not used (symlink owner)! # # 187: Unknown PRNG type: " # Unknown PRNG type: " # # 188: "! # "! # # 189: The srand()/rand() PRNG is not available! # The srand()/rand() PRNG is not available! # # 190: The srand48()/lrand48() PRNG is not available! # The srand48()/lrand48() PRNG is not available! # # 191: The random() PRNG is not available! # The random() PRNG is not available! # # 192: The OpenSSL PRNG is not available! # The OpenSSL PRNG is not available! # # 193: Failed to save random seed data! # Failed to save random seed data! # # 194: HOME directory name too long! # HOME directory name too long! # # 195: System configuration files skipped by user. # System configuration files skipped by user. # # 196: Attempt to obtain seed data from " # Attempt to obtain seed data from " # # 197: ". # ". # # 198: Seed data: # Seed data: # # 199: bytes found. # bytes found. # # 200: Index out of range! # Index out of range! # # 201: Matrix expansion requires a square matrix! # Matrix expansion requires a square matrix! # # 202: Not a directory: " # Not a directory: " # # 203: "! # "! # # 204: Encoding not supported by C runtime library! # Encoding not supported by C runtime library! # # 205: No directory containing LaTeX encoding tables found! # No directory containing LaTeX encoding tables found! # # 206: Redefinition,\noverwriting " # Redefinition,\noverwriting " # # 207: " by " # " by " # # 208: ". # ". # # 209: Syntax error,\nindex # Syntax error,\nindex # # 210: is out of range 0...255. # is out of range 0...255. # # 211: Syntax error\nnear " # Syntax error\nnear " # # 212: "! # "! # # 213: Syntax error,\nmissing LaTeX encoding! # Syntax error,\nmissing LaTeX encoding! # # 214: Syntax error,\nmissing index! # Syntax error,\nmissing index! # # 215: No file name matches pattern " # No file name matches pattern " # # 216: "! # "! # # 217: Missing name of long option! # Missing name of long option! # # 218: Incomplete input sequence. # Incomplete input sequence. # # 219: String contains non-ISO-LATIN-1 characters! # String contains non-ISO-LATIN-1 characters! # # 220: Misconfigured start/end for range! # Misconfigured start/end for range! # # 221: New range conflicts with existing one! # New range conflicts with existing one! # # 222: Not a hex number! # Not a hex number! # # 223: Syntax error! # Syntax error! # # 224: Character redefinition! # Character redefinition! # # 225: Range not declared in character directory! # Range not declared in character directory! # # 226: Package name conflicts with previous definition! # Package name conflicts with previous definition! # # 227: Attempt to obtain seed data from CryptoAPI. # Attempt to obtain seed data from CryptoAPI. # # 228: Attempt to obtain seed data from screen. # Attempt to obtain seed data from screen. # # 229: OpenSSL PRNG seeded successfully. # OpenSSL PRNG seeded successfully. # # 230: Attempt to read preferences file " # Attempt to read preferences file " # # 231: ". # ". # # 232: LaTeX table directory: " # LaTeX table directory: " # # 233: ". # ". # # 234: Attempting LaTeX table directory: " # Attempting LaTeX table directory: " # # 235: ". # ". # # 236: Reading LaTeX table dir: " # Reading LaTeX table dir: " # # 237: ". # ". # # 238: Registering LaTeX conversion range # Registering LaTeX conversion range # # 239: . # . # # 240: Loading LaTeX conversion data file " # Loading LaTeX conversion data file " # # 241: ". # ". # # 242: Failed to change into directory: " # Failed to change into directory: " # # 243: "! # "! # # 244: Failed to enumerate printers! # Failed to enumerate printers! # # 245: Record too large! # Record too large! # # 246: File damaged or not a database file! # File damaged or not a database file! # # 247: No support for database type " # No support for database type " # # 248: " available! # " available! # # 249: Key not found in database! # Key not found in database! # # 250: DB entry probably damaged - not a multibyte char string! # DB entry probably damaged - not a multibyte char string! # # 251: Database opened for read access only! # Database opened for read access only! # # 252: Error(s) occured while processing command line options! # Error(s) occured while processing command line options! # # 253: Failed to retrieve current locale! # Failed to retrieve current locale! # # 254: Current locale too long! # Current locale too long! # # 255: Not a regular file: " # Not a regular file: " # # 256: "! # "! # # 257: Image file type unknown or not supported! # Image file type unknown or not supported! # # 258: Bits per component restricted to 16! # Bits per component restricted to 16! # # 259: Incorrect page setup, no usable space between borders! # Incorrect page setup, no usable space between borders! # # 260: Mathematical error in size calculations! # Mathematical error in graphics calculations! # # 261: Failed to set bitmap image frame! # Failed to set bitmap image frame! # # 262: Flate compression not supported! # Flate compression not supported! # # 263: Illegal compression cell type used! # Illegal compression cell type used! # # 264: Error during previous compression operations! # Error during previous compression operations! # # 265: Failed to retrieve console settings! # Failed to retrieve console settings! # # 266: Failed to restore console settings! # Failed to restore console settings! # # 267: Failed to modify console settings! # Failed to modify console settings! # # 268: Failed to convert timestamp to local time! # Failed to convert timestamp to local time! # # 269: ERROR: No file name available for database! # No file name available for database! # # 270/271: ERROR: Failed to change file ownership! # Failed to change ownership for file:\n" "! # # 272/273: ERROR: Failed to change file permissions! # Failed to change permissions for file:\n" "! # # 274: ERROR: Failed to open network socket, insufficient permissions! # Insufficient permissions to open network connection! # # 275: ERROR: Failed to open network socket, unknown address family! # Unknown or illegal address family! # # 276: ERROR: Failed to open network socket, process table overflow! # Process table overflow! # # 277: ERROR: Too many open files! # Too many open files! # # 278: ERROR: Protocol not supported! # Protocol not supported! # # 279: ERROR: Failed to open network socket! # Failed to open network socket! # # 280: ERROR: Failed to close socket! # Failed to close socket! # # 281: ERROR: Operation interrupted by signal! # Interrupted by signal or explicitly cancelled! # # 282: ERROR: Failed to connect! # Failed to connect! # # 283: ERROR: Failed to listen for incoming requests! # Failed to listen for incoming requests! # # 284/285: ERROR: Failed to find IP address for "..."! # Failed to find IP address for:\n" "! # # 286 # Host not found! # # 287 # Host exists, but no IP address assigned! # # 288 # Problem on DNS server! # # 289 # Temporary problem on DNS server, try again later! # # 290 # No gethostbyname() function available! # # 291 # Can not connect to remote port 0! # # 292 # Access denied by firewall or due to insufficient permissions! # # 293 # Local address already in use! # # 294 # Resources shortage, network operation failed! # # 295 # Previous connection attempt not yet completed! # # 296 # Connection refused, port not open on peer! # # 297 # Socket already connected! # # 298 # Network unreachable! # # 299 # Timeout occured. # # 300 # No select() function available, timeout settings ignored! # # 301 # Failed to retrieve socket state! # # 302 # Failed to bind local address! # 303 UNUSED # # 304 # Socket already bound to local address! # # 305 # Failed to write data to socket! # # 306 # Operation would block! # # 307 # Connection reset by peer! # # 308 # Peer address is required to send data via connectionless socket! # # 309 # Peer address specification is not allowed for connected sockets! # # 310 # Message too large to be sent atomically! # # 311 # Sending queue full for socket! # # 312 # Writing to a pipe without a reader! # # 313 # Less bytes were written than required! # # 314 # Failed to read data from socket! # # 315 # Failed to shut down socket! # # 316 # Socket not connected! # # 317 # Failed to accept incoming connection request! # # 318 # Connection aborted! # # 319 # Network protocol error! # # 320 # Network subsystem not available! # # 321 # Windows sockets not initialized! # # 322 # A blocking Winsock 1.1 operation is in progress! # # 323 # Socket type doesn't correspond to address family! # # 324 # Socket not configured for broadcasts! # # 325 # Requested address is not available! # # 326 # Host unreachable! # # 327 # Windows sockets version not available! # # 328 # Too many processes use Windows sockets at this time! # # 329 # I/O error occured! # # 330 # Too many symbolic links in path! # # 331 # Illegal pathname (missing a parent directory)! # # 332 # File system is mounted read-only! # # 333 # Stale NFS file handle! # # 334 # Server for remote file not available! # # 335 # No space left on device! # # 336 # Failed to wait for sockets to become ready! # # 337 # Failed to convert text address to address! # # 338 # Failed to find address for host! # # 339 # Failed to set socket options! # # 340 # Error while closing file! # # 341/342 # Error while closing file\n" "! # # 343/344 # Failed to write data to file:\n" "! # # 345 # Failed to read data from file! # # 346/347 # Failed to read data from file:\n" "! # # 348/349 # Not an IP address: " "! # # 350 # Not an IP address! # # 351/352 # Failed to connect to: " "! # # 353 # No function available to check blocking/non-blocking state! # # 354 # Netmask is not a dotted IP address! # # 355 # Netmask is not a bit number! # # 356 # Netmask is not an IPv6 address! # # 357 # No name resolution available, please specify IP address! # # 358 # No select() function available! # # 359 # No valid socket found in set! # # 360 361 # Socket connected to client: # # 362 363 # Connection from " " rejected! # # 364 # Failed to create any listener socket for socket set! # # 365 # Preference value of /threads/max higher than number of cores! # # 366 + 367 # Failed to find unique file identifier for file\n" "! # # 368 # Failed to find unique file identifier for a file! # # 369 + 370 Preference ... does not point to a directory! # Preference " " does not point to a directory! # # 371 # # # 372 373 374 # Socket listening: # # 375 376 377 # Socket connected: # # 378 379 380 # Multiple different font encodings required! Font encoding both required and denied: ` '! # # 381 382 # Font encoding required: ` '! # # 383 384 # The following font encoding can not be used: ` '. # # 385 # All font encodings denied! # # 386 387 388 # Too many entries on position in text line:\n" " # # 389 390 # Unexpected end of text after backslash in text:\n" " # # 391 392 # UTF-8 decoding failed for string:\n" UTF-16 decoding failed for string:\n" # # 393 394 # Non-ANSI characters in string:\n" Non-URL characters in string:\n" $!end }; /** Preferences entry. */ typedef struct _dk3app_pref_t { dkChar const *k; /**< Key (name). */ dkChar const *v; /**< Value. */ } dk3app_pref_t; /** Message catalog. */ typedef struct _dk3app_mc_t_ { dkChar const *n; /**< Name (always dynamically allocated). */ dkChar const **msg; /**< Message texts. */ int f; /**< Flag: Messages dynamically allocated. */ size_t nmsg; /**< Number of messages. */ } dk3app_mc_t; /** Delete preferences entry, release memory. @param p Preference entry to delete. */ static void dk3app_pref_delete(dk3app_pref_t *p) { if(p) { $? "= dk3app_pref_delete \"%s\"=\"%s\"", TR_STR(p->k), TR_STR(p->v) dk3_release(p->k); dk3_release(p->v); dk3_delete(p); } } /** Create new preferences entry, allocate memory. @param k Key (preference name). @param v Value. @return Pointer to new entry on success, NULL on error. */ static dk3app_pref_t * dk3app_pref_new(dkChar const *k, dkChar const *v) { dk3app_pref_t *back = NULL; $? "+ dk3app_pref_new \"%s\"=\"%s\"", TR_STR(k), TR_STR(v) if((k) && (v)) { back = dk3_new(dk3app_pref_t,1); if(back) { back->k = dk3str_dup_app(k, NULL); back->v = dk3str_dup_app(v, NULL); if(!((back->k) && (back->v))) { dk3app_pref_delete(back); back = NULL; } } } $? "- dk3app_pref_new %s", TR_PTR(back) return back; } /** Compare two preference entries by name. @param l Left entry. @param r Right entry. @param crit Comparison criteria (ignored). @return Comparison result l <=> r. */ static int dk3app_compare_pref(void const *l, void const *r, int crit) { int back = 0; dk3app_pref_t const *pl = NULL; /* Left object. */ dk3app_pref_t const *pr = NULL; /* Right object. */ if(l) { if(r) { pl = (dk3app_pref_t const *)l; pr = (dk3app_pref_t const *)r; if(pl->k) { if(pr->k) { back = dk3str_cmp(pl->k, pr->k); } else { back = 1; } } else { if(pr->k) { back = -1; } } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Delete string table. @param ta Table to delete. @param n Number of entries in the table. */ static void dk3app_mc_table_delete(dkChar const **ta, size_t n) { dkChar const **ptr = NULL; /* Start of string table. */ size_t i = 0; /* Index of current element to process. */ $? "+ dk3app_mc_table_delete %s %u", TR_PTR(ta), (unsigned)n ptr = ta; for(i = 0; i < n; i++) { $? ". entry no %u", (unsigned)i if(*ptr) { $? ". delete \"%s\"", TR_STR(*ptr) dk3_delete(*ptr); } *(ptr++) = NULL; } dk3_delete(ta); $? "- dk3app_mc_table_delete" } /** Delete message catalog entry. @param mc Message catalog entry to delete. */ static void dk3app_mc_delete(dk3app_mc_t *mc) { $? "+ dk3app_mc_delete %s", TR_PTR(mc) if(mc) { $? ". name=\"%s\"", TR_STR(mc->n) dk3_release(mc->n); if(mc->f) { if(mc->msg) { dk3app_mc_table_delete(mc->msg, mc->nmsg); } } mc->f = 0; mc->msg = NULL; dk3_delete(mc); } $? "- dk3app_mc_delete" } /** Create message catalog entry. @param n Short file name of string table file. @param msg String table. @param nmsg Number of entries in \a msg. @param f Flag: The memory for \a msg was dynamically allocated. @param app Application structure for diagnostics, may be NULL. @return Pointer to message catalog entry on success, NULL on error. */ static dk3app_mc_t * dk3app_mc_new( dkChar const *n, dkChar const **msg, size_t nmsg, int f, dk3_app_t *app ) { dk3app_mc_t *back = NULL; $? "+ dk3app_mc_new \"%s\" f=%d nmsg=%u", TR_STR(n), f, (unsigned)nmsg back = dk3_new_app(dk3app_mc_t,1,app); if(back) { back->n = NULL; back->msg = NULL; back->f = f; back->nmsg = nmsg; back->n = dk3str_dup_app(n, app); if(back->n) { back->msg = msg; } else { dk3app_mc_delete(back); back = NULL; } } $? "- dk3app_mc_new %s", TR_PTR(back) return back; } /** Compare two message catalog entries. @param l Left entry. @param r Right entry. @param cr Comparison criteria (ignored). @return Comparison result. */ static int dk3app_mc_compare(void const *l, void const *r, int cr) { int back = 0; dk3app_mc_t const *pl = NULL; /* Left message catalog. */ dk3app_mc_t const *pr = NULL; /* Right message catalog. */ if(l) { if(r) { pl = (dk3app_mc_t const *)l; pr = (dk3app_mc_t const *)r; if(pl->n) { if(pr->n) { back = dk3str_cmp(pl->n, pr->n); } else { back = 1; } } else { if(pr->n) { back = -1; } } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Write log message to a file. If the time has changed since the last message written to that file we write a new timestamp before writing the message. @param app Application structure. @param ll Log level, DK3_LL_xxx. @param msg Array of message parts. @param nmsg Number of elements in \a msg. @param fipo File to write to. @param last_time Timestamp of last message written to that file. */ static void dk3app_log_to_file( dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg, FILE *fipo, dk3_time_t *last_time ) { dk3_time_t time_now; /* Current time. */ dkChar tb[64]; /* Buffer to store current time as text. */ char ulb[64]; /* Buffer for current time as char text. */ char *sp = NULL; /* Source pointer used in conversion. */ size_t i = 0; /* Index of current string to process. */ $? "+ dk3app_log_to_file" if(dk3sf_time(&time_now)) { if(time_now != *last_time) { if(dk3sf_time_convert_app(tb, DK3_SIZEOF(tb,dkChar), &time_now, NULL)) { *last_time = time_now; dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[10], fipo); dk3sf_fputs(tb, fipo); dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[0], fipo); } } } if(app->n_sourcefile) { dk3sf_fputs(app->n_sourcefile, fipo); dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[11], fipo); if(app->sourceline) { sprintf(ulb, "%lu", app->sourceline); sp = ulb; while(*sp) { dk3sf_fputc( (dkChar)(*(sp++)), fipo); } dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[11], fipo); } dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[8], fipo); } if((ll >= DK3_LL_PANIC) && (ll <= DK3_LL_WARNING)) { dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[ll], fipo); dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[11], fipo); dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[8], fipo); } for(i = 0; i < nmsg; i++) { if(msg[i]) { dk3sf_fputs(msg[i], fipo); } } dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[0], fipo); $? "- dk3app_log_to_file" } /** Write log message to log file. If the time has changed since the last message written to that file we write a new timestamp before writing the message. @param app Application structure. @param ll Log level, DK3_LL_xxx. @param msg Array of message parts. @param nmsg Number of elements in \a msg. */ static void dk3app_log_file(dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg) { FILE *fipo; /* Output file. */ dk3_stat_t stb; /* File stat buffer. */ $? "+ dk3app_log_file" if(app->n_logfilename) { $? ". file \"%s\"", app->n_logfilename if(app->f_first_file_log) { if(app->app_type == DK3_APP_TYPE_DAEMON) { app->f_first_file_log = 0; if(!dk3sf_stat_app(&stb, app->n_logfilename, NULL)) { app->f_first_file_log = 1; } } } fipo = dk3sf_fopen_app(app->n_logfilename, dk3app_no_loc[8], NULL); /* WRITE */ if(fipo) { $? ". file opened" #if DK3_ON_WINDOWS && (DK3_CHAR_SIZE > 1) /* Switch to 16 bit characters. */ (void)_setmode(_fileno(fipo), _O_U16TEXT); /* Write byte order marker. */ if(app->f_first_file_log) { fputwc(0xFEFF, fipo); } #endif app->f_first_file_log = 0; dk3app_log_to_file( app, ll, msg, nmsg, fipo, &(app->t_last_log_file) ); fclose(fipo); } else { $? "! fopen" } } $? "- dk3app_log_file" } int dk3app_max_log_level(dk3_app_t const *app) { int back = 0; if(app) { if(app->app_type != DK3_APP_TYPE_SILENT) { back = app->ll_file; if(app->app_type == DK3_APP_TYPE_COMMAND) { if(app->ll_stderr > back) { back = app->ll_stderr; } } } } return back; } void dk3app_log_msg(dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg) { $? "+ dk3app_log_msg %s level=%d parts=%u", TR_PTR(app), ll, (unsigned)nmsg if((app) && (msg) && (nmsg)) { $? ". arguments ok" if(app->f_readytolog) { $? ". ready to log" if(ll < app->ll_highest) { $? ". keep new highest log level" app->ll_highest = ll; } switch(app->app_type) { case DK3_APP_TYPE_COMMAND: { $? ". command line logging" if(app->ll_file >= ll) { $? ". log level sufficient (file)" dk3app_log_file(app, ll, msg, nmsg); } else { $? "! log level insufficient (file %d)", app->ll_file } if(app->ll_stderr >= ll) { $? ". log level sufficient (stderr)" dk3sf_initialize_stderr(); dk3app_log_to_file( app, ll, msg, nmsg, stderr, &(app->t_last_log_stderr) ); } else { $? "! log level insufficient (stderr %d)", app->ll_stderr } } break; case DK3_APP_TYPE_GUI: case DK3_APP_TYPE_DAEMON: $? ". daemon/GUI logging" { $? ". ll_file=%d ll=%d", app->ll_file, ll if(app->ll_file >= ll) { $? ". log level sufficient" dk3app_log_file(app, ll, msg, nmsg); } } break; } } else { $? "! not yet ready to log" } } else { $? "! arguments problem" } $? "- dk3app_log_msg" } void dk3app_log_1(dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1) { dkChar const *m[2]; /* Message parts. */ $? "+ dk3app_log_1" if((app) && (msg)) { m[0] = msg[i1]; m[1] = NULL; dk3app_log_msg(app, ll, (dkChar const * const *)m, 1); } $? "- dk3app_log_1" } void dk3app_log_2( dk3_app_t *app, int ll, dkChar const * const * msg, size_t i, dkChar const *st ) { dkChar const *m[3]; if((app) && (msg)) { m[0] = msg[i]; m[1] = st; m[2] = NULL; dk3app_log_msg(app, ll, (dkChar const * const *)m, 2); } } void dk3app_log_3( dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1, size_t i2, dkChar const *st ) { dkChar const *m[4]; /* Message parts. */ $? "+ dk3app_log_3" if((app) && (msg)) { m[0] = msg[i1]; m[1] = st; m[2] = msg[i2]; m[3] = NULL; dk3app_log_msg(app, ll, (dkChar const * const *)m, 3); } $? "- dk3app_log_3" } void dk3app_log_5( dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1, size_t i2, size_t i3, dkChar const *st1, dkChar const *st2 ) { dkChar const *m[6]; /* Message parts. */ $? "+ dk3app_log_5" if((app) && (msg)) { m[0] = msg[i1]; m[1] = st1; m[2] = msg[i2]; m[3] = st2; m[4] = msg[i3]; m[5] = NULL; dk3app_log_msg(app, ll, (dkChar const * const *)m, 5); } $? "- dk3app_log_5" } void dk3app_log_i1(dk3_app_t *app, int ll, size_t i1) { $? "+ dk3app_log_i1" if(app) { dk3app_log_1(app, ll, ((app->msg) ? app->msg : dk3app_kw), i1); } $? "- dk3app_log_i1" } void dk3app_log_i2(dk3_app_t *app, int ll, size_t i, dkChar const * st) { dkChar const *msg[3]; /* Message parts. */ if((app) && (i) && (st)) { if(i < DK3_SIZEOF(dk3app_kw,DK3_PCDKCHAR)) { msg[0] = ((app->msg) ? app->msg : dk3app_kw)[i]; msg[1] = st; msg[2] = NULL; dk3app_log_msg(app, ll, (dkChar const * const *)msg, 2); } } } void dk3app_log_i3( dk3_app_t *app, int ll, size_t i1, size_t i2, dkChar const *st ) { $? "+ dk3app_log_i3" if(app) { dk3app_log_3(app, ll, ((app->msg) ? app->msg : dk3app_kw), i1, i2, st); } $? "- dk3app_log_i3" } void dk3app_log_i5( dk3_app_t *app, int ll, size_t i1, size_t i2, size_t i3, dkChar const *st1, dkChar const *st2 ) { $? "+ dk3app_log_i5" if(app) { dk3app_log_5( app, ll, ((app->msg) ? app->msg : dk3app_kw), i1, i2, i3, st1, st2 ); } $? "- dk3app_log_i5" } void dk3app_set_source_file(dk3_app_t *app, dkChar const *fn) { if(app) { $? "= dk3app_set_source_file \"%s\"", TR_STR(fn) app->n_sourcefile = fn; } } void dk3app_set_source_line(dk3_app_t *app, unsigned long li) { if(app) { $? "= dk3app_set_source_line %lu", li app->sourceline = li; } } dkChar const * dk3app_get_source_file(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_sourcefile; } $? "= dk3app_get_source_file \"%s\"", TR_STR(back) return back; } unsigned long dk3app_get_source_line(dk3_app_t const *app) { unsigned long back = 0UL; if(app) { back = app->sourceline; } $? "= dk3app_get_source_line %lu", back return back; } /** Find data (resource) file. String tables are resources too, so we check language and region subdirectories too. @param app Application structure. @param fn File name. @param db Destination buffer. @param sz Size of \a db (number of characters). @param verb Flag: Diagnostic messages enabled. @return 1 on success, 0 on error. */ static int dk3app_my_find_data_file( dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz, int verb ) { int back = 0; dkChar const *p1 = NULL; /* dk3app, group or application name. */ dkChar const *p2 = NULL; /* Language. */ dkChar const *p3 = NULL; /* Region. */ int cc = 1; /* Flag: Can go. */ size_t mysz = 0; /* Size for calculation. */ size_t sz1 = 0; /* Length of /xxx/share directory name. */ size_t sz2 = 0; /* Length of short file name. */ dk3_stat_t stb; /* Stat buffer to test existance of files. */ int i = 0; /* Pass: 0=lang+region, 1=language, 0=share. */ int j = 0; /* Pass: 0=app, 1=appgroup, 2=dk3app, 3=base. */ $? "+ dk3app_my_find_data_file \"%s\"", TR_STR(fn) if((app) && (fn) && (db) && (sz)) { if(app->n_sharedir) { sz1 = dk3str_len(app->n_sharedir); sz2 = dk3str_len(fn); for(i = 0; ((back == 0) && (i < 4)); i++) { for(j = 0; ((back == 0) && (j < 4)); j++) { $? ". i=%d j=%d", i, j p1 = NULL; p2 = NULL; p3 = NULL; cc = 0; switch(i) { case 1: { if(app->n_language) { p2 = app->n_language; cc = 1; } } break; case 2: { p2 = dk3app_no_loc[47]; cc = 1; } break; case 3: { cc = 1; } break; default: { if(app->n_language) { p2 = app->n_language; if(app->n_region) { p3 = app->n_region; cc = 1; } } } break; } switch(j) { case 1: { if(app->n_appgroup) { p1 = app->n_appgroup; } else { cc = 0; } } break; case 2: { p1 = dk3app_no_loc[17]; } break; case 3: { p1 = NULL; } break; default: { if(app->n_app) { p1 = app->n_app; } else { cc = 0; } } break; } if(cc) { mysz = sz1 + sz2 + 1; if(p1) { mysz += dk3str_len(p1); mysz++; } if(p2) { mysz += dk3str_len(p2); mysz++; } if(p3) { mysz += dk3str_len(p3); mysz++; } if(mysz < sz) { dk3str_cpy_not_overlapped(db, app->n_sharedir); if(p1) { dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, p1); } if(p2) { dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, p2); } if(p3) { dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, p3); } dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, fn); $? ". i=%d j=%d db=\"%s\"", i, j, db if(dk3sf_stat_app(&stb, db, NULL)) { switch((stb.ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_REGULAR: { back = 1; $? ". found \"%s\"", db } break; } } if(back) { /* DEBUG: Resource file ... found. */ dk3app_log_i3(app, DK3_LL_DEBUG, 148, 149, db); } else { /* DEBUG: Resource file ... not found. */ dk3app_log_i3(app, DK3_LL_DEBUG, 150, 151, db); } } } } } } else { if(verb) { /* Internal error, no /xxx/share directory! */ dk3app_log_i1(app, DK3_LL_ERROR, 55); } } } $? "- dk3app_my_find_data_file %d", back return back; } /** Remove a file. The difference to dk3sf_remove_file_app() is that this function does not complain if the file does not exist. @param n File name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3app_remove_file_app(dkChar *n, dk3_app_t *app) { int back = 0; dk3_stat_t stb; /* Stat buffer to test existance of file. */ $? "+ dk3app_remove_file_app %s", TR_STR(n) if(dk3sf_stat_app(&stb,n,app)) { $? ". file exists" back = dk3sf_remove_file_app(n, app); } else { $? ". no such file" back = 1; /* File does not exist. */ } $? "- dk3app_remove_file_app %d", back return back; } /** Delete one temporaray file. @param app Application structure. @param n Number to build the file name. @param s Number to build the file suffix. @param f Pointer to error code variable. */ static void dk3app_delete_one_temp_file(dk3_app_t *app, unsigned long n, unsigned s, int *f) { dkChar buffer[DK3_MAX_PATH]; /* Buffer to construct complete file name. */ dkChar fnb2[16]; /* Buffer for short file name. */ char fnb[16]; /* Buffer for numeric conversion. */ dk3_app_t *ra = NULL; /* Application to use for diagnostics. */ size_t sz = 0; /* Length needed for complete file name. */ $? "+ dk3app_delete_one_temp_file %lu %u", n, s sprintf(fnb, "/%08lx.%03x", n, s); ra = app; if((*f) & 1) { ra = NULL; } if(dk3str_cnv_c8_to_str_app(fnb2, 15, fnb, ra)) { sz = dk3str_len(app->n_tmpdir) + dk3str_len(fnb2); if(sz < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, app->n_tmpdir); dk3str_cat(buffer, fnb2); dk3str_correct_filename(buffer); ra = app; if((*f) & 4) { ra = NULL; } if(!dk3app_remove_file_app(buffer, NULL)) { *f = ((*f) | 4); } } else { if(!((*f) & 2)) { dk3app_log_i1(app, DK3_LL_ERROR, 37); *f = ((*f) | 2); } } } else { *f = ((*f) | 1); } $? "- dk3app_delete_one_temp_file" } /** Delete all temporary files of an application for a core name. @param app Application structure. @param n Number to build core file name. @param f Pointer to error code variable. */ static void dk3app_delete_all_temp_files_for(dk3_app_t *app, unsigned long n, int *f) { unsigned u; /* Used for file name suffix. */ $? "+ dk3app_delete_all_temp_files_for %lu", n for(u = 0; u < 0x1000U; u++) { dk3app_delete_one_temp_file(app, n, u, f); } $? "- dk3app_delete_all_temp_files_for" } /** Delete all temporary files of an application. @param app Application structure. */ static void dk3app_remove_temporary_files(dk3_app_t *app) { unsigned long ul = 0UL; /* Used for base file name. */ unsigned u = 0; /* Used for suffixes of final base. */ int f = 0; /* Error checking variable. */ $? "+ dk3app_remove_temporary_files" if(app->n_tmpdir) { f = 0; if(app->i_tmpcarry) { for(ul = 0UL; ul < 0xFFFFFFFFUL; ul++) { dk3app_delete_all_temp_files_for(app, ul, &f); } dk3app_delete_all_temp_files_for(app, 0xFFFFFFFFUL, &f); } else { for(ul = 0UL; ul < app->ul_tmpname; ul++) { dk3app_delete_all_temp_files_for(app, ul, &f); } for(u = 0; u < app->u_tmpsuffix; u++) { dk3app_delete_one_temp_file(app, app->ul_tmpname, u, &f); } dk3app_delete_one_temp_file(app, app->ul_tmpname, app->u_tmpsuffix, &f); } dk3sf_remove_dir_app(app->n_tmpdir, NULL); } $? "- dk3app_remove_temporary_files" } /** Construct configuration file name candidate. When searching for files (configuration or resource files) we specify the sort file name without leading directory. During the search process we do several tests prepending directory names before the short file name. This function is used to construct a file name. @param app Application structure. @param fn File name. @param db Result buffer. @param sz Size of \a db (number of characters). @param passno Pass number (0-15). @param verb Flag: Diagnostic messages enabled. @return 1 on success, 0 on error. */ static int dk3app_config_name( dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz, int passno, int verb ) { int back = 0; dkChar const *ptr1 = NULL; /* Base directory (etc or share). */ dkChar const *ptr2 = NULL; /* Subdirectory (app, group, dk3app or none). */ dkChar const *ptr3 = NULL; /* Application or group name. */ size_t mysz = 0; /* Buffer size needed for all components. */ $? "+ dk3app_config_name \"%s\" pass=%d", TR_STR(fn), passno ptr1 = NULL; ptr2 = NULL; ptr3 = NULL; switch(passno) { #if VERSION_BEFORE_20110219 case 0: { ptr1 = app->n_sharedir; ptr2 = dk3app_no_loc[17]; } break; case 2: { ptr1 = app->n_sharedir; ptr2 = app->n_appgroup; } break; case 3: { ptr1 = app->n_etcdir; ptr2 = app->n_appgroup; } break; case 4: { ptr1 = app->n_sharedir; ptr2 = app->n_app; } break; case 5: { ptr1 = app->n_etcdir; ptr2 = app->n_app; } break; case 6: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; } break; case 7: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_appgroup; } break; case 8: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_app; } break; case 9: { ptr1 = dk3app_no_loc[19]; } break; default: { /* 1 */ ptr1 = app->n_etcdir; ptr2 = dk3app_no_loc[17]; } break; #else case 0: { ptr1 = app->n_sharedir; ptr2 = dk3app_no_loc[17]; } break; case 1: { ptr1 = app->n_etcdir; ptr2 = dk3app_no_loc[17]; } break; case 2: { ptr1 = app->n_sharedir; ptr2 = dk3app_no_loc[17]; } break; case 3: { ptr1 = app->n_etcdir; ptr2 = dk3app_no_loc[17]; } break; case 4: { ptr1 = app->n_sharedir; ptr2 = app->n_appgroup; } break; case 5: { ptr1 = app->n_etcdir; ptr2 = app->n_appgroup; } break; case 6: { ptr1 = app->n_sharedir; ptr2 = app->n_appgroup; } break; case 7: { ptr1 = app->n_etcdir; ptr2 = app->n_appgroup; } break; case 8: { ptr1 = app->n_sharedir; ptr2 = app->n_app; } break; case 9: { ptr1 = app->n_etcdir; ptr2 = app->n_app; } break; case 10: { ptr1 = app->n_sharedir; ptr2 = app->n_app; } break; case 11: { ptr1 = app->n_etcdir; ptr2 = app->n_app; } break; case 12: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; } break; case 13: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_appgroup; } break; case 14: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_app; } break; case 15: { ptr1 = dk3app_no_loc[19]; } break; #endif } mysz = dk3str_len(fn); if(ptr1) { mysz += dk3str_len(ptr1); mysz++; } if(ptr2) { mysz += dk3str_len(ptr2); mysz++; } if(ptr3) { mysz += dk3str_len(ptr3); mysz++; } switch(passno) { case 2: case 3: case 6: case 7: case 10: case 11: { mysz += dk3str_len(dk3app_no_loc[32]); } break; } if(mysz < sz) { if(ptr1) { dk3str_cpy_not_overlapped(db, ptr1); if(ptr2) { dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, ptr2); } if(ptr3) { dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, ptr3); } switch(passno) { case 2: case 3: case 6: case 7: case 10: case 11: { dk3str_cat(db, dk3app_no_loc[32]); } break; } dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, fn); back = 1; $? ". file name = \"%s\"", db } else { if(verb) { /* Internal error, some directory not set! */ } } } else { if(verb) { dk3app_log_i1(app, DK3_LL_ERROR, 38); } } $? "- dk3app_config_name %d", back return back; } /** Unconfigure application (delete registry key or config file). @param app Application to unconfigure. */ static void dk3app_do_unconfigure(dk3_app_t *app) { dkChar fnb[DK3_MAX_PATH]; /* File name buffer for config file. */ if(dk3app_config_name(app, dk3app_no_loc[21], fnb, DK3_MAX_PATH, 14, 0)) { (void)dk3sf_remove_file_app(fnb, app); } } /** Save self-set preferences to registry or file. @param app Application structure. */ static void dk3app_do_save_config(dk3_app_t *app) { dkChar fnb[DK3_MAX_PATH]; /* File name buffer for conf file. */ dkChar *ptr = NULL; /* Slash/backslash correction. */ FILE *fipo = NULL; /* Used to write file. */ dk3app_pref_t *p1 = NULL; /* Preference entry to process. */ dk3app_pref_t *p2 = NULL; /* Check in higher priorized storage. */ $? "+ dk3app_do_save_config" if(dk3app_config_name(app, dk3app_no_loc[21], fnb, DK3_MAX_PATH, 14, 0)) { $? ". file name found \"%s\"", fnb ptr = dk3str_rchr(fnb, DK3_CHAR_SEP); if(ptr) { *ptr = dkT('\0'); dk3sf_mkdir_app(fnb, 0700, NULL); *ptr = DK3_CHAR_SEP; } fipo = dk3sf_fopen_app(fnb, dk3app_no_loc[24], app); /* WRITE */ if(fipo) { $? ". file opened" #if DK3_ON_WINDOWS && (DK3_CHAR_SIZE > 1) /* Switch to 16 bit characters. */ (void)_setmode(_fileno(fipo), _O_U16TEXT); /* Write byte order marker. */ fputwc(0xFEFF, fipo); #endif if((app->s_varprefs) && (app->i_varprefs)) { dk3sto_it_reset(app->i_varprefs); while((p1 = (dk3app_pref_t *)dk3sto_it_next(app->i_varprefs)) != NULL) { p2 = NULL; if((app->s_selfprefs) && (app->i_selfprefs)) { p2 = (dk3app_pref_t *)dk3sto_it_find_like(app->i_selfprefs, p1, 0); } if(!(p2)) { dk3sf_fputs(p1->k, fipo); dk3sf_fputs(dk3app_no_loc[25], fipo); dk3sf_fputs(p1->v, fipo); dk3sf_fputs(dk3app_no_loc[26], fipo); } } } if((app->s_selfprefs) && (app->i_selfprefs)) { dk3sto_it_reset(app->i_selfprefs); while((p1 = (dk3app_pref_t *)dk3sto_it_next(app->i_selfprefs)) != NULL) { dk3sf_fputs(p1->k, fipo); dk3sf_fputs(dk3app_no_loc[25], fipo); dk3sf_fputs(p1->v, fipo); dk3sf_fputs(dk3app_no_loc[26], fipo); } } fclose(fipo); } else { $? "! failed to open file" } } else { $? "! file name not found" } $? "- dk3app_do_save_config" } void dk3app_close(dk3_app_t *app) { int i = 0; /* Used to release argv memory. */ dk3app_pref_t *pref = NULL; /* Used to delete preference entries. */ dk3app_mc_t *mcptr = NULL; /* Used to delete message catalogs. */ $? "+ dk3app_close" if(app) { if(app->f_unconfigure) { $? ". must unconfigure application" dk3app_do_unconfigure(app); } else { if(app->f_prefschanged) { $? ". must save self-set preferences" dk3app_do_save_config(app); } } /* Clean up preferences system. */ $? ". clean up preferences" if(app->s_selfprefs) { if(app->i_selfprefs) { dk3sto_it_reset(app->i_selfprefs); while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_selfprefs)) != NULL) { dk3app_pref_delete(pref); } dk3sto_it_close(app->i_selfprefs); } dk3sto_close(app->s_selfprefs); } app->s_selfprefs = NULL; app->i_selfprefs = NULL; if(app->s_cmdprefs) { if(app->i_cmdprefs) { dk3sto_it_reset(app->i_cmdprefs); while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_cmdprefs)) != NULL) { dk3app_pref_delete(pref); } dk3sto_it_close(app->i_cmdprefs); } dk3sto_close(app->s_cmdprefs); } app->s_cmdprefs = NULL; app->i_cmdprefs = NULL; if(app->s_sysprefs) { if(app->i_sysprefs) { dk3sto_it_reset(app->i_sysprefs); while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_sysprefs)) != NULL) { dk3app_pref_delete(pref); } dk3sto_it_close(app->i_sysprefs); } dk3sto_close(app->s_sysprefs); } app->s_sysprefs = NULL; app->i_sysprefs = NULL; if(app->s_constprefs) { if(app->i_constprefs) { dk3sto_it_reset(app->i_constprefs); while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_constprefs)) != NULL) { dk3app_pref_delete(pref); } dk3sto_it_close(app->i_constprefs); } dk3sto_close(app->s_constprefs); } app->s_constprefs = NULL; app->i_constprefs = NULL; if(app->s_varprefs) { if(app->i_varprefs) { dk3sto_it_reset(app->i_varprefs); while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_varprefs)) != NULL) { dk3app_pref_delete(pref); } dk3sto_it_close(app->i_varprefs); } dk3sto_close(app->s_varprefs); } app->s_varprefs = NULL; app->i_varprefs = NULL; /* Clean up temporary directory. */ $? ". clean up tmp dir" if(app->ll_highest > app->ll_tmp_keep) { dk3app_remove_temporary_files(app); } /* Remove log file if no longer needed. */ $? ". remove log file" if(DK3_APP_TYPE_DAEMON != app->app_type) { dk3app_log_i3(app, DK3_LL_DEBUG, 21, 22, app->n_app); if(app->ll_highest > app->ll_file_keep) { dk3sf_remove_file_app(app->n_logfilename, NULL); } } /* Unset resources, release resources. */ app->ll_file = app->ll_stderr = app->ll_file_keep = app->ll_highest = 0; app->app_type = 0; app->msg = NULL; app->n_sourcefile = NULL; app->sourceline = 0UL; $? ". release message catalogs" if(app->s_mc) { if(app->i_mc) { dk3sto_it_reset(app->i_mc); while((mcptr = (dk3app_mc_t *)dk3sto_it_next(app->i_mc)) != NULL) { dk3app_mc_delete(mcptr); } dk3sto_it_close(app->i_mc); } dk3sto_close(app->s_mc); } app->s_mc = NULL; app->i_mc = NULL; $? ". release cmd args" if(app->argv) { dkChar const **ptr; ptr = (dkChar const **)(app->argv); for(i = 0; i < app->argc; i++) { dk3_release(*ptr); ptr++; } } $? ". release other names" dk3_release(app->n_app); dk3_release(app->n_execfile); dk3_release(app->n_bindir); dk3_release(app->n_etcdir); dk3_release(app->n_sharedir); dk3_release(app->n_vardir); dk3_release(app->n_logname); dk3_release(app->n_homedir); dk3_release(app->n_appgroup); dk3_release(app->n_logfilename); dk3_release(app->n_tmpdir); dk3_release(app->n_language); dk3_release(app->n_region); dk3_release(app->n_langstr); dk3_release(app->n_hostname); dk3_delete(app); } $? "- dk3app_close" } int dk3app_get_default_stdin_encoding(dk3_app_t const *app) { int back = 0; if(app) { back = app->i_output_encoding; #if DK3_CHAR_SIZE > 1 #if DK3_ON_WINDOWS back = DK3_FILE_ENCODING_ASCII; #endif #endif } return back; } int dk3app_get_default_file_encoding(dk3_app_t const *app) { int back = 0; if(app) { back = app->i_output_encoding; #if DK3_CHAR_SIZE > 1 #if DK3_ON_WINDOWS back = DK3_FILE_ENCODING_ASCII; #endif #endif } return back; } /** Initialize application structure. @param app Application to initialize. */ static void dk3app_init(dk3_app_t *app) { $? "+ dk3app_init" app->app_type = 0; app->msg = NULL; app->n_sourcefile = NULL; app->sourceline = 0UL; app->ll_file = DK3_LL_PROGRESS; app->ll_stderr = DK3_LL_INFO; app->ll_file_keep = DK3_LL_ERROR; app->ll_tmp_keep = DK3_LL_NONE; app->ll_highest = DK3_LL_IGNORE; app->argv = NULL; app->argc = 0; app->n_app = NULL; app->n_execfile = NULL; app->n_bindir = NULL; app->n_etcdir = NULL; app->n_sharedir = NULL; app->n_vardir = NULL; app->n_logname = NULL; app->n_homedir = NULL; app->n_appgroup = NULL; app->n_logfilename = NULL; app->n_tmpdir = NULL; app->n_language = NULL; app->n_region = NULL; app->n_langstr = NULL; app->ul_tmpname = 0UL; app->u_tmpsuffix = 0U; app->i_tmpcarry = 0; app->n_hostname = NULL; #if DK3_CHAR_SIZE > 1 app->i_encoding = DK3_ENCODING_UTF16; #if DK3_BIGENDIAN app->i_output_encoding = DK3_FILE_ENCODING_UTF16_MSB_FIRST; #else app->i_output_encoding = DK3_FILE_ENCODING_UTF16_LSB_FIRST; #endif #else app->i_encoding = DK3_ENCODING_PLAIN; app->i_output_encoding = DK3_FILE_ENCODING_ASCII; #endif app->i_stdin_input_encoding = dk3app_get_default_stdin_encoding(app); $? "+ i_stdin_input_encoding=%d", app->i_stdin_input_encoding app->i_file_input_encoding = dk3app_get_default_file_encoding(app); app->de = 0; /* No error found yet. */ $? "- dk3app_init" app->s_mc = NULL; app->i_mc = NULL; app->s_cmdprefs = NULL; app->i_cmdprefs = NULL; app->s_selfprefs = NULL; app->i_selfprefs = NULL; app->f_unconfigure = 0; app->f_prefschanged = 0; app->f_readytolog = 0; app->s_sysprefs = NULL; app->i_sysprefs = NULL; app->s_constprefs = NULL; app->i_constprefs = NULL; app->s_varprefs = NULL; app->i_varprefs = NULL; app->f_first_file_log = 1; app->f_rand_initialized = 0; app->f_rand_success = 0; app->rand_type = 0; app->t_last_log_stderr = (dk3_time_t)0UL; app->t_last_log_file = (dk3_time_t)0UL; } /** Copy binary directory name to other directory names. @param app Application structure. */ static void dk3app_copy_bin_to_others(dk3_app_t *app) { $? "+ dk3app_copy_bin_to_others" app->n_etcdir = dk3str_dup_app(app->n_bindir, NULL); if(app->n_etcdir) { app->n_sharedir = dk3str_dup_app(app->n_bindir, NULL); if(app->n_sharedir) { app->n_vardir = dk3str_dup_app(app->n_bindir, NULL); if(!(app->n_vardir)) { app->de = 9; } } else { app->de = 8; } } else { app->de = 7; } $? "- dk3app_copy_bin_to_others" } #if DK3_ON_WINDOWS #if VERSION_BEFORE_20131022 /** Open a registry key. @param k Parent key (HKLM or HKCU). @param n Key name. @param p Permissions needed. @param kp Pointer to result key variable. @return ERROR_SUCCESS on success, other values indicate an error. */ static long dk3app_reg_open_key(HKEY k, dkChar const *n, int p, HKEY *kp) { long back = 0L; #if DK3_CHAR_SIZE > 1 back = RegOpenKeyExW(k, n, (DWORD)0, p, kp); #else back = RegOpenKeyExA(k, n, (DWORD)0, p, kp); #endif return back; } /** Retrieve a value from the registry. @param k Registry key. @param n Entry name. @param tp Entry type. @param b Result buffer address. @param len In: size of buffer, out: number of bytes used. @return ERROR_SUCCESS on success, any other value indicates an error. */ static long dk3app_reg_query(HKEY k, dkChar const *n, DWORD *tp, LPBYTE b, DWORD *len) { long back = 0L; #if DK3_CHAR_SIZE > 1 back = RegQueryValueExW(k, n, NULL, tp, b, len); #else back = RegQueryValueExA(k, n, NULL, tp, b, len); #endif return back; } /** Retrieve string value from registry. @param k Key. @param n Entry name. @param b Result buffer. @param sz Size of \a b (number of characters). @return 1 on success, 0 on error. */ static int dk3app_reg_query_str(HKEY k, dkChar const *n, dkChar *b, size_t sz) { int back = 0; DWORD tp = REG_SZ; /* Registry entry type. */ DWORD len = 0L; /* Length of arguments and results. */ LONG res = 0L; /* Registry operation result. */ tp = REG_SZ; len = (DWORD)(sz * DK3_CHAR_SIZE); res = dk3app_reg_query(k, n, &tp, (LPBYTE)b, &len); if(ERROR_SUCCESS == res) { if((REG_SZ == tp) || (REG_EXPAND_SZ == tp)) { if(len > 0) { #if DK3_CHAR_SIZE > 1 len = len / DK3_CHAR_SIZE; #endif b[(((size_t)len) < sz) ? len : (sz - 1)] = dkT('\0'); back = 1; } } } return back; } #endif #endif /** Get users language/region/encoding setting. @param app Application structure. @param db Result buffer. @param sz Size of \a db (number of characters). @return 1 on success, 0 on error. */ static int dk3app_get_language_string(dk3_app_t *app, dkChar *db, size_t sz) { int back = 0; $? "+ dk3app_get_language_string" #if DK3_ON_WINDOWS #if VERSION_BEFORE_20131022 { LONG res = 0L; /* Registry operation result. */ HKEY key; /* Registry key. */ res = dk3app_reg_open_key( HKEY_CURRENT_USER, dk3app_no_loc[12], KEY_READ, &key ); if(ERROR_SUCCESS == res) { back = dk3app_reg_query_str(key, dk3app_no_loc[13], db, sz); if(back == 0) { back = dk3app_reg_query_str(key, dk3app_no_loc[14], db, sz); if(back) { db[2] = dkT('\0'); } } RegCloseKey(key); } } #else { HKEY hk; /* Registry key. */ if(dk3wreg_key_open_read(HKEY_CURRENT_USER, dk3app_no_loc[12], &hk, NULL)) { if(dk3wreg_get_sz(hk, dk3app_no_loc[13],db,sz,NULL)) { back = 1; } else { if(dk3wreg_get_sz(hk, dk3app_no_loc[14],db,sz,NULL)) { back = 1; } } dk3wreg_key_close(hk, dk3app_no_loc[12], NULL); } } #endif #else #if DK3_CHAR_SIZE == 1 { char *ptr; /* Pointer to environment variable contents. */ ptr = getenv(dk3app_no_loc[11]); if(ptr) { if(dk3str_c8_len(ptr) < sz) { dk3str_c8_cpy_not_overlapped(db, ptr); back = 1; } else { dk3app_log_i1(app, DK3_LL_ERROR, 39); } } } #endif #endif $? "- dk3app_get_language_string %d", back return back; } /** Find language, region and encoding. @param app Application structure. @param argc Number of command line arguments. @param argv Command line arguments array. */ static void dk3app_language_and_region(dk3_app_t *app, int argc, dkChar const * const *argv) { dkChar buffer[DK3_MAX_PATH]; /* Buffer to store language/region name. */ dkChar *ptr; /* Used to find region. */ dkChar *p2; /* Used to convert to lower characters. */ $? "+ dk3app_language_and_region" if(dk3app_get_language_string(app, buffer, DK3_SIZEOF(buffer,dkChar))) { app->n_langstr = dk3str_dup_app(buffer, NULL); $? ". buffer=%s", buffer if(app->n_langstr) { ptr = dk3str_chr(buffer, dkT('.')); if(ptr) { *(ptr++) = dkT('\0'); $? ". encoding found" #if DK3_CHAR_SIZE == 1 if(dk3str_casecmp(ptr, dk3app_no_loc[15]) == 0) { app->i_encoding = DK3_ENCODING_UTF8; app->i_output_encoding = DK3_FILE_ENCODING_UTF8; } if(dk3str_casecmp(ptr, dk3app_no_loc[16]) == 0) { app->i_encoding = DK3_ENCODING_UTF8; app->i_output_encoding = DK3_FILE_ENCODING_UTF8; } #endif } ptr = dk3str_chr(buffer, dkT('_')); #if DK3_ON_WINDOWS if(!(ptr)) { ptr = dk3str_chr(buffer, dkT('-')); } #endif if(ptr) { $? ". region found" *(ptr++) = dkT('\0'); $? ". buffer=%s", buffer p2 = ptr; while(*p2) { *p2 = dk3str_tolower(*p2); p2++; } app->n_region = dk3str_dup_app(ptr, NULL); if(!(app->n_region)) { $? "! region" app->de = 29; } } if(!(app->de)) { $? ". buffer=%s", buffer p2 = buffer; while(*p2) { *p2 = dk3str_tolower(*p2); p2++; } app->n_language = dk3str_dup_app(buffer, NULL); if(!(app->n_language)) { $? "! language" app->de = 30; } } } else { $? "! language string" app->de = 28; } } $? "- dk3app_language_and_region" } /** Check whether a directory name is a root directory. @param dirname Directory name to check. @return 1 for root directory, 0 for others. */ static int dk3app_is_root_directory(dkChar const *dirname) { int back = 0; #if DK3_ON_WINDOWS size_t sz; sz = dk3str_len(dirname); if(1 == sz) { if(dkT('\\') == dirname[0]) { back = 1; } } else { if(3 == sz) { if((dkT('a') <= dirname[0]) && (dkT('z') >= dirname[0])) { back = 1; } else { if((dkT('A') <= dirname[0]) && (dkT('Z') >= dirname[0])) { back = 1; } } if(back) { back = 0; if(dkT(':') == dirname[1]) { if(dkT('\\') == dirname[2]) { back = 1; } } } } } #else if(dk3str_len(dirname) == 1) { if(dkT('/') == dirname[0]) { back = 1; } } #endif return back; } /** Reduce a directory name referring to a bin (or sbin or libexec/xxx directory. @param dirname Directory name to modify. @return 1 on success, 0 on error. */ static int dk3app_reduce_bindir_name(dkChar *dirname) { dkChar buffer[DK3_MAX_PATH]; dkChar *pCurrent; /* Current path component. */ dkChar *pPrevious; /* Previous path component. */ size_t sz; int ai; /* Array index. */ int cc; /* Flag: Can continue. */ int back = 0; $? "+ dk3app_reduce_bindir_name \"%s\"", dirname if(dk3str_len(dirname) < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, dirname); pCurrent = NULL; pPrevious = NULL; cc = 1; while(cc) { $? ". while \"%s\"", buffer cc = 0; if(dk3str_len(buffer) > 1) { $? ". length ok" if(!dk3app_is_root_directory(buffer)) { $? ". not root" pCurrent = dk3str_rchr(buffer, DK3_CHAR_SEP); if(pCurrent) { $? ". separator found" cc = 1; $? ". dir \"%s\"",&(pCurrent[1]) #if DK3_ON_WINDOWS ai = dk3str_array_index(dk3app_bindir_candidates,&(pCurrent[1]),0); #else ai = dk3str_array_index(dk3app_bindir_candidates,&(pCurrent[1]),1); #endif if(-1 < ai) { $? ". this is a final name" cc = 0; sz = dk3str_len(buffer); dirname[sz] = dkT('\0'); back = 1; } else { $? ". not a final name" if(pPrevious) { *pPrevious = DK3_CHAR_SEP; } pPrevious = pCurrent; *pCurrent = dkT('\0'); } } } } } } $? "- dk3app_reduce_bindir_name %d \"%s\"", back, dirname return back; } /** Find all the names. Set app->de on errors, don't report directly. @param app Application to configure. @param wd Current working directory. @param argc Number of command line arguments. @param argv Command line arguments array. */ static void dk3app_find_names( dk3_app_t *app, dkChar const *wd, int argc, dkChar const * const *argv ) { int must_relocate = 0; /* Flag: Must relocate. */ int redres; /* Result from reduce directory. */ #if DK3_HAVE_UMASK mode_t oldumask; /* Umask before mkdir. */ #endif dkChar *n_app = NULL; /* Application name. */ dkChar *p = NULL; /* Modify application name. */ dkChar const *q = NULL; /* Installation bin directory. */ dkChar *x = NULL; /* Deal with executable name. */ dkChar buffer[DK3_MAX_PATH]; /* Used to construct file names. */ char pidbuffer[128]; /* Buffer for PID number (8-bit). */ dkChar dkpidbuffer[128]; /* Buffer for PID number. */ size_t tsl = 0; /* Buffer size needed. */ $? "+ dk3app_find_names" p = dk3str_rchr(argv[0], DK3_CHAR_SEP); if(p) { p++; } else { p = (dkChar *)(argv[0]); } n_app = dk3str_dup_app(p, NULL); $? ". program name \"%s\"", p if(n_app) { $? ". program name \"%s\"", n_app app->n_app = (dkChar const *)n_app; $? ". program name \"%s\"", app->n_app p = dk3str_chr(n_app, DK3_CHAR_DOT); if(p) { *p = DK3_CHAR_0; } if(dk3sf_find_exec_app(buffer,DK3_SIZEOF(buffer,dkChar),wd,argv[0], NULL)) { x = dk3str_dup_app(buffer, NULL); app->n_execfile = x; if(app->n_execfile) { p = dk3str_rchr(buffer, DK3_CHAR_SEP); if(p) { *p = DK3_CHAR_0; app->n_bindir = dk3str_dup_app(buffer, NULL); if(app->n_bindir) { redres = dk3app_reduce_bindir_name(buffer); q = dk3inst_get_directory(DK3_INST_BIN); if(dk3str_fncmp(buffer, q)) { q = dk3inst_get_directory(DK3_INST_SBIN); if(dk3str_fncmp(buffer, q)) { q = dk3inst_get_directory(DK3_INST_LIB); if(dk3str_fncmp(buffer, q)) { q = dk3inst_get_directory(DK3_INST_LIBEXEC); if(dk3str_fncmp(buffer, q)) { must_relocate = 1; } } } } if(must_relocate) { p = dk3str_rchr(buffer, DK3_CHAR_SEP); if(p) { p++; if(redres) { *p = DK3_CHAR_0; tsl = dk3str_len(buffer); tsl += dk3str_len(dk3app_no_loc[1]); if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(p, dk3app_no_loc[1]); app->n_etcdir = dk3str_dup_app(buffer, NULL); if(app->n_etcdir) { *p = DK3_CHAR_0; tsl = dk3str_len(buffer); tsl += dk3str_len(dk3app_no_loc[2]); if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(p, dk3app_no_loc[2]); app->n_sharedir = dk3str_dup_app(buffer, NULL); if(app->n_sharedir) { *p = DK3_CHAR_0; tsl = dk3str_len(buffer); tsl += dk3str_len(dk3app_no_loc[3]); if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(p, dk3app_no_loc[3]); app->n_vardir = dk3str_dup_app(buffer, NULL); if(!(app->n_vardir)) { app->de = 9; } } else { app->de = 13; } } else { app->de = 8; } } else { app->de = 12; } } else { app->de = 7; } } else { app->de = 11; } } else { dk3app_copy_bin_to_others(app); } } else { dk3app_copy_bin_to_others(app); } } else { q = dk3inst_get_directory(DK3_INST_SYSCONF); app->n_etcdir = dk3str_dup_app(q, NULL); if(app->n_etcdir) { q = dk3inst_get_directory(DK3_INST_DATAROOT); app->n_sharedir = dk3str_dup_app(q, NULL); if(app->n_sharedir) { q = dk3inst_get_directory(DK3_INST_LOCALSTATE); app->n_vardir = dk3str_dup_app(q, NULL); if(!(app->n_vardir)) { app->de = 9; } } else { app->de = 8; } } else { app->de = 7; } } if(!(app->de)) { if(dk3sf_get_logname_app(buffer,DK3_SIZEOF(buffer,dkChar),NULL)) { app->n_logname = dk3str_dup_app(buffer,NULL); if(!(app->n_logname)) { app->de = 15; } } else { app->de = 14; } } if(!(app->de)) { if(dk3sf_get_hostname_app(buffer,DK3_SIZEOF(buffer,dkChar),NULL)) { app->n_hostname = dk3str_dup_app(buffer, NULL); if(!(app->n_hostname)) { app->de = 37; } } else { app->de = 38; } } if(!(app->de)) { if(dk3sf_get_home_app(buffer,DK3_SIZEOF(buffer,dkChar), NULL)) { app->n_homedir = dk3str_dup_app(buffer,NULL); if(!(app->n_homedir)) { app->de = 17; } } else { app->de = 16; } } if(!(app->de)) { switch(app->app_type) { case DK3_APP_TYPE_COMMAND: case DK3_APP_TYPE_GUI: { tsl = dk3str_len(app->n_homedir); tsl += dk3str_len(dk3app_no_loc[4]); tsl += dk3str_len(dk3app_no_loc[20]); tsl += dk3str_len(app->n_app); tsl += dk3str_len(dk3app_no_loc[5]); (void)dk3ma_um_to_c8_string( pidbuffer, sizeof(pidbuffer), dk3sf_getpid() ); if(dk3str_cnv_c8_to_str_app( dkpidbuffer, DK3_SIZEOF(dkpidbuffer,dkChar), pidbuffer, NULL ) ) { tsl += dk3str_len(dkpidbuffer); tsl += dk3str_len(dk3app_no_loc[6]); if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, app->n_homedir); dk3str_cat(buffer, dk3app_no_loc[4]); dk3str_correct_filename(buffer); if(dk3sf_mkdir_app(buffer, 0700, NULL)) { dk3str_cat(buffer, dk3app_no_loc[20]); dk3str_cat(buffer, app->n_app); dk3str_cat(buffer, dk3app_no_loc[5]); dk3str_cat(buffer, dkpidbuffer); dk3str_cat(buffer, dk3app_no_loc[6]); dk3str_correct_filename(buffer); app->n_logfilename = dk3str_dup_app(buffer,NULL); if(!(app->n_logfilename)) { app->de = 21; } } else { app->de = 20; } } else { app->de = 19; } } else { app->de = 22; } } break; case DK3_APP_TYPE_DAEMON: { tsl = dk3str_len(app->n_vardir); tsl += dk3str_len(dk3app_no_loc[4]); tsl += dk3str_len(dk3app_no_loc[20]); tsl += dk3str_len(app->n_app); tsl += dk3str_len(dk3app_no_loc[20]); tsl += dk3str_len(app->n_app); tsl += dk3str_len(dk3app_no_loc[6]); #if DK3_HAVE_UMASK oldumask = umask(0); #endif if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, app->n_vardir); dk3str_cat(buffer, dk3app_no_loc[4]); if(dk3sf_mkdir_app(buffer, 0755, NULL)) { dk3str_cat(buffer, dk3app_no_loc[20]); dk3str_cat(buffer, app->n_app); if(dk3sf_mkdir_app(buffer, 0755, NULL)) { dk3str_cat(buffer, dk3app_no_loc[20]); dk3str_cat(buffer, app->n_app); dk3str_cat(buffer, dk3app_no_loc[6]); app->n_logfilename = dk3str_dup_app(buffer, NULL); if(!(app->n_logfilename)) { app->de = 21; } } else { $? "! mkdir \"%s\"", buffer app->de = 20; } } else { $? "! mkdir \"%s\"", buffer app->de = 20; } } else { app->de = 19; } #if DK3_HAVE_UMASK umask(oldumask); #endif } break; } } if(!(app->de)) { $? ". find tmp dir" switch(app->app_type) { case DK3_APP_TYPE_DAEMON: { if(app->n_vardir) { if(app->n_app) { (void)dk3ma_um_to_c8_string( pidbuffer, sizeof(pidbuffer), dk3sf_getpid() ); if(dk3str_cnv_c8_to_str_app( dkpidbuffer, DK3_SIZEOF(dkpidbuffer,dkChar), pidbuffer, NULL ) ) { tsl = dk3str_len(app->n_vardir); tsl += dk3str_len(dk3app_no_loc[10]); tsl += dk3str_len(dk3app_no_loc[20]); tsl += dk3str_len(app->n_app); tsl += dk3str_len(dk3app_no_loc[20]); tsl += dk3str_len(dkpidbuffer); if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, app->n_vardir); dk3str_cat(buffer, dk3app_no_loc[10]); dk3str_correct_filename(buffer); (void)dk3sf_mkdir_app(buffer,0700,NULL); dk3str_cat(buffer, dk3app_no_loc[20]); dk3str_cat(buffer, app->n_app); dk3str_correct_filename(buffer); (void)dk3sf_mkdir_app(buffer,0700,NULL); dk3str_cat(buffer, dk3app_no_loc[20]); dk3str_cat(buffer, dkpidbuffer); if(dk3sf_mkdir_app(buffer,0700,NULL)) { app->n_tmpdir = dk3str_dup_app(buffer, NULL); if(!(app->n_tmpdir)) { app->de = 25; dk3sf_remove_dir_app(buffer, NULL); } } else { app->de = 26; } } else { app->de = 19; } } else { app->de = 22; } } else { app->de = 24; } } else { app->de = 27; } } break; default: { if(app->n_homedir) { if(app->n_app) { (void)dk3ma_um_to_c8_string( pidbuffer, sizeof(pidbuffer), dk3sf_getpid() ); if(dk3str_cnv_c8_to_str_app( dkpidbuffer, DK3_SIZEOF(dkpidbuffer,dkChar), pidbuffer, NULL ) ) { tsl = dk3str_len(app->n_homedir); tsl += dk3str_len(dk3app_no_loc[9]); tsl += dk3str_len(dk3app_no_loc[20]); tsl += dk3str_len(app->n_app); tsl += dk3str_len(dk3app_no_loc[5]); tsl += dk3str_len(dkpidbuffer); if(tsl < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, app->n_homedir); dk3str_cat(buffer, dk3app_no_loc[9]); dk3str_correct_filename(buffer); if(dk3sf_mkdir_app(buffer,0700,NULL)) { dk3str_cat(buffer, dk3app_no_loc[20]); dk3str_cat(buffer, app->n_app); dk3str_cat(buffer, dk3app_no_loc[5]); dk3str_cat(buffer, dkpidbuffer); dk3str_correct_filename(buffer); if(dk3sf_mkdir_app(buffer,0700,NULL)) { app->n_tmpdir = dk3str_dup_app(buffer, NULL); if(!(app->n_tmpdir)) { app->de = 25; dk3sf_remove_dir_app(buffer, NULL); } } else { app->de = 26; } } else { app->de = 26; } } else { app->de = 19; } } else { app->de = 22; } } else { app->de = 24; } } else { app->de = 23; } } break; } } } else { app->de = 6; } } else { app->de = 5; } } else { app->de = 4; } } else { app->de = 3; } } else { app->de = 2; } $? "- dk3app_find_names %d", app->de } /** Test whether a configuration file name candidate is valid. @param app Application structure. @param fn File name. @param db Destination buffer. @param sz Size of \a db (number of characters). @param passno Pass number. @param verb Flag: Diagnostic messages enabled. @return 1 on success, 0 on error. */ static int dk3app_check_config_file( dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz, int passno, int verb ) { int back = 0; dk3_stat_t stb; /* Stat buffer used to check existance of files. */ $? "+ dk3app_check_config_file \"%s\" passno=%d", TR_STR(fn), passno if(dk3app_config_name(app, fn, db, sz, passno, verb)) { if(dk3sf_stat_app(&stb, db, NULL)) { switch((stb.ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_REGULAR: { back = 1; } break; } } if(back) { /* DEBUG Config file ... found. */ dk3app_log_i3(app, DK3_LL_DEBUG, 152, 153, db); } else { /* DEBUG Config file ... not found. */ dk3app_log_i3(app, DK3_LL_DEBUG, 154, 155, db); } } $? "- dk3app_check_config_file %d", back return back; } /** Add preference key/value entry to storage. Check whether an entry for the key already exists. @param app Application structure for diagnostics, may be NULL. @param s Storage. @param i Storage iterator. @param k Preference key. @param v Preference value. */ static int dk3app_add_pref( dk3_app_t *app, dk3_sto_t *s, dk3_sto_it_t *i, dkChar const *k, dkChar const *v ) { int back = 0; dk3app_pref_t p; /* Preference search. */ dk3app_pref_t *pref = NULL; /* Existing preference for name. */ dkChar *nv = NULL; /* New value string for preference. */ $? "+ dk3app_add_pref \"%s\"=\"%s\"", TR_STR(k), TR_STR(v) p.k = k; p.v = v; pref = (dk3app_pref_t *)dk3sto_it_find_like(i, &p, 0); if(pref) { nv = dk3str_dup_app(v, NULL); if(nv) { dk3_delete(pref->v); pref->v = nv; back = 1; } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } } else { pref = dk3app_pref_new(k, v); if(pref) { if(dk3sto_add(s, pref)) { back = 1; } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } dk3app_pref_delete(pref); pref = NULL; } } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 9); } } } $? "- dk3app_add_pref %d", back return back; } /** Save one preference entry. Do not report problems directly, set app->de instead. @param app Application structure. @param pt Preference text. */ static void dk3app_save_one_preference(dk3_app_t *app, dkChar const *pt) { dkChar b[DK3_MAX_PATH]; /* Buffer for input line. */ dkChar *p1 = NULL; /* Value position. */ $? "+ dk3app_save_one_preference \"%s\"", TR_STR(pt) if(dk3str_len(pt) < DK3_SIZEOF(b,dkChar)) { dk3str_cpy_not_overlapped(b, pt); p1 = dk3str_chr(b, dkT('=')); if(p1) { *(p1++) = dkT('\0'); p1 = dk3str_start(p1, NULL); if(p1) { dk3str_chomp(b, NULL); dk3str_chomp(p1, NULL); if(!(app->s_cmdprefs)) { app->s_cmdprefs = dk3sto_open_app(NULL); if(app->s_cmdprefs) { dk3sto_set_comp(app->s_cmdprefs, dk3app_compare_pref, 0); } else { app->de = 36; $? "! failed to create storage" } } if(!(app->i_cmdprefs)) { if(app->s_cmdprefs) { app->i_cmdprefs = dk3sto_it_open(app->s_cmdprefs); } else { app->de = 35; $? "! failed to create iterator" } } if((app->s_cmdprefs) && (app->i_cmdprefs)) { if(!dk3app_add_pref(NULL,app->s_cmdprefs,app->i_cmdprefs,b,p1)) { app->de = 33; $? "! failed to add to storage" } } } else { app->de = 32; $? "! no value" } } else { app->de = 32; $? "! no \"=\"" } } else { app->de = 31; $? "! too long" } $? "- dk3app_save_one_preference" } /** Set application to silent mode if --/silent=yes was provided as command line argument. @param app Application structure. */ static void dk3app_first_set_silent(dk3_app_t *app) { app->ll_stderr = DK3_LL_NONE; switch(app->app_type) { case DK3_APP_TYPE_COMMAND: { app->app_type = DK3_APP_TYPE_SILENT; } break; } } int dk3app_first_silence_check(dk3_app_t *app, int argc, dkChar const * const *argv) { int back = 0; int i; /* Index of current argument. */ dkChar const * const *lfdptr; /* Pointer to traverse arguments. */ dkChar const *ptr; /* Current argument. */ dkChar buffer[2 * DK3_MAX_PATH]; /* Local copy. */ dkChar *p1; /* Option keyword. */ dkChar *p2; /* Option argument. */ lfdptr = argv; lfdptr++; i = 1; while(i < argc) { ptr = *lfdptr; if(*ptr == dkT('-')) { ptr++; if(*ptr == dkT('-')) { ptr++; if(dk3str_len(ptr) < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, ptr); p1 = dk3str_start(buffer, NULL); if(p1) { p2 = dk3str_chr(p1, dkT('=')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); } if(dk3str_cmp(dk3app_no_loc[50], p1) == 0) { if(p2) { if(dk3str_is_on(p2)) { back = 1; if(app) { dk3app_first_set_silent(app); } } } else { back = 1; if(app) { dk3app_first_set_silent(app); } } } } } else { /* ERROR: Too long! */ } } } lfdptr++; i++; } return back; } /** Save command line arguments for later use. Don't report errors directly, set app->de instead. @param app Application structure. @param argc Number of command line arguments. @param argv Command line arguments array. */ static void dk3app_save_arguments(dk3_app_t *app, int argc, dkChar const * const *argv) { int myargc = 0; /* Number of options used. */ dkChar const **myargv = NULL; /* Private copy of options. */ dkChar const **ptr = NULL; /* Traverse myargv. */ dkChar const * const *sptr = NULL; /* Traverse original argv. */ dkChar const *tptr = NULL; /* String tests in sptr. */ int ispref = 0; /* Flag: Is a preference. */ int i = 0; /* Index of current argv. */ $? "+ dk3app_save_arguments" myargv = dk3_new_app(DK3_PCDKCHAR,(argc+1),app); if(myargv) { ptr = myargv; for(i = 0; i < (argc + 1); i++) { *(ptr++) = NULL; } ptr = myargv; myargc = 0; sptr = argv; for(i = 0; i < argc; i++) { tptr = *(sptr++); $? ". tptr=\"%s\"", tptr ispref = 0; if(*tptr == DK3_CHAR_MINUS) { if(tptr[1] == DK3_CHAR_MINUS) { if(tptr[2] == DK3_CHAR_SLASH) { ispref = 1; $? ". is preference" } } } if(ispref) { dk3app_save_one_preference(app, &(tptr[2])); } else { *ptr = dk3str_dup_app(tptr, NULL); if(*ptr) { myargc++; ptr++; } else { app->de = 1; } } } app->argc = myargc; app->argv = myargv; } $? "- dk3app_save_arguments de=%d", app->de } /** Save application group name. @param app Application structure. @param gn Group name to save. */ static void dk3app_save_group_name(dk3_app_t *app, dkChar const *gn) { $? "+ dk3app_save_group_name \"%s\"", TR_STR(gn) app->n_appgroup = dk3str_dup_app(gn,NULL); if(!(app->n_appgroup)) { app->de = 18; } $? "- dk3app_save_group_name de=%d", app->de } /** Retrieve preferences from a storage. @param app Application structure for diagnostics, may be NULL. @param p Storage iterator. @param k Key (preference name). @param d Destination buffer. @param s Size of \a d (number of characters). @return 1 on success, 0 on error. */ static int dk3app_sto_pref( dk3_app_t *app, dk3_sto_it_t *p, dkChar const *k, dkChar *d, size_t s) { int back = 0; dk3app_pref_t pr; /* Used for comparisons in search. */ dk3app_pref_t *pref = NULL; /* Entry found. */ $? "+ dk3app_sto_pref \"%s\"", TR_STR(k) if(p) { pr.k = k; pr.v = NULL; pref = (dk3app_pref_t *)dk3sto_it_find_like(p, &pr, 0); if(pref) { if(pref->v) { if(dk3str_len(pref->v) < s) { dk3str_cpy_not_overlapped(d, pref->v); back = 1; } else { if(app) { /* Destination buffer too short! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } } } $? "- dk3app_sto_pref %d", back return back; } /** Find number of entries for a string table file. @param dv String table value array. @return Number of entries in array, including final NULL entry. */ static size_t dk3app_mc_array_size(dkChar const * const *dv) { size_t back = 0; dkChar const * const *ptr = NULL; /* Traverse the dv array. */ $? "+ dk3app_mc_array_size" if(dv) { ptr = dv; while(*(ptr++)) { back++; } back++; } $? "- dk3app_mc_array_size %u", (unsigned)back return back; } void dk3app_squeeze_line(char *lb) { char *pd = NULL; /* Destination in copy operations. */ char *ps = NULL; /* Source in copy operations. */ char *px = NULL; /* Position to continue. */ ps = lb; $? "+ dk3app_squeeze_line \"%s\"", lb /* Remove trailing newline. */ while(*ps) { if((*ps == '\r') || (*ps == '\n')) { *ps = '\0'; } else { ps++; } } /* Correct escape sequences */ ps = lb; while(*ps) { if(*ps == '\\') { px = pd = ps; ps++; if(*ps) { switch(*ps) { case 't': { *(pd++) = '\t'; ps++; dk3str_c8_cpy(pd, ps); } break; case 'n': { *(pd++) = '\n'; ps++; dk3str_c8_cpy(pd, ps); } break; case 'r': { *(pd++) = '\r'; ps++; dk3str_c8_cpy(pd, ps); } break; default: { dk3str_c8_cpy(pd, ps); } break; } ps = px; ps++; } } else { ps++; } } $? "- dk3app_squeeze_line \"%s\"", lb } /** Get message catalog contents. @param app Application structure. @param fn File name for message catalog. @param dv Default values. @param verb Flag: Diagnostics enabled. @return Pointer to message array. */ static dkChar const * const * dk3app_my_messages( dk3_app_t *app, dkChar const *fn, dkChar const * const *dv, int verb ) { dkChar const * const *back = NULL; dkChar const *source_file = NULL; /* File name for source file. */ dk3app_mc_t mc; /* Used for comparisons. */ dk3app_mc_t *mcptr = NULL; /* Message catalog. */ int errors_occured = 0; /* Flag: We had errors. */ unsigned long source_line = 0UL; /* Number of source line. */ unsigned long line_number = 0UL; /* NUmber of current line. */ size_t sz_defaults = 0; /* Number entries in default table. */ size_t i = 0; /* Walk through table. */ size_t current_index = 0; /* Index of current entry to process. */ dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */ char lb[4096]; /* Input line (8-bit characters). */ dkChar const **rb = NULL; /* Array of strings to return. */ FILE *fipo; /* Input file. */ $? "+ dk3app_my_messages" if((app) && (fn) && (dv)) { $? ". args ok" /* Find array size. */ sz_defaults = dk3app_mc_array_size(dv); if(sz_defaults) { $? ". sz = %u", (unsigned)sz_defaults if((app->s_mc) && (app->i_mc)) { $? ". have existing tables" mc.n = fn; mc.msg = NULL; mc.f = 0; mc.nmsg = sz_defaults; mcptr = (dk3app_mc_t *)dk3sto_it_find_like(app->i_mc, &mc, 0); if(mcptr) { $? ". message catalog found" if(mcptr->nmsg >= sz_defaults) { back = mcptr->msg; $? ". can re-use loaded catalog." } else { $? "! message catalog loaded but too short" errors_occured = 1; /* Too short */ } } else { $? "! message catalog not found" } } else { $? "! no message catalogs loaded so far" } if((!(back)) && (errors_occured == 0)) { $? ". attempt to find file" if(dk3app_my_find_data_file(app, fn, fnb, DK3_MAX_PATH, verb)) { source_file = dk3app_get_source_file(app); $? ". file found" source_line = dk3app_get_source_line(app); dk3app_set_source_file(app, fnb); dk3app_set_source_line(app, 0UL); /* UTF8 */ fipo = dk3sf_fopen_app(fnb, dk3app_no_loc[22], (verb ? app : NULL)); if(fipo) { $? ". file opened successfully" rb = dk3_new_app(DK3_PCDKCHAR,sz_defaults,(verb ? app : NULL)); if(rb) { $? ". memory allocation ok" for(i = 0; i < sz_defaults; i++) { rb[i] = NULL; } current_index = 0; /* We explicitly used 8-bit characters, the file is UTF-8 */ while(fgets(lb, sizeof(lb), fipo)) { line_number++; dk3app_set_source_line(app, line_number); if(lb[0] != '#') { dk3app_squeeze_line(lb); if(current_index < (sz_defaults - 1)) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "Can not handle 4-byte characters here!" #else rb[current_index] = (dkChar const *)dk3str_cnvnew_c8u_to_c16_app( lb, (verb ? app : NULL) ); if(rb[current_index]) { current_index++; } else { errors_occured = 2; } #endif #else switch(app->i_encoding) { case DK3_ENCODING_PLAIN: { rb[current_index] = dk3str_cnvnew_c8u_to_c8p_app(lb, (verb ? app : NULL)); if(rb[current_index]) { current_index++; } else { errors_occured = 2; } } break; default: { rb[current_index] = dk3str_dup_app(lb, (verb ? app : NULL)); if(rb[current_index]) { current_index++; } else { errors_occured = 2; } } break; } #endif } /* current_index++; */ } } $? ". file handled completely" dk3app_set_source_line(app, 0UL); if((current_index >= (sz_defaults - 1)) && (!(errors_occured))) { if(!(app->s_mc)) { $? ". must create new storage" app->s_mc = dk3sto_open_app(verb ? app : NULL); if(app->s_mc) { $? ". storage ok" dk3sto_set_comp(app->s_mc, dk3app_mc_compare, 0); } else { $? "! failed to create storage" } } if(!(app->i_mc)) { $? ". must create iterator" if(app->s_mc) { $? ". storage available" app->i_mc = dk3sto_it_open(app->s_mc); } else { $? "! no storage, no iterator" } } if((app->s_mc) && (app->i_mc)) { $? ". storage/iterator" mcptr = dk3app_mc_new(fn, rb, sz_defaults, 1, (verb ? app: NULL)); if(mcptr) { $? ". new entry ok" if(dk3sto_add(app->s_mc, mcptr)) { $? ". full success" back = rb; } else { dk3app_mc_table_delete(rb, sz_defaults); rb = NULL; } } else { $? "! failed to create new entry" dk3app_mc_table_delete(rb, sz_defaults); rb = NULL; } } else { $? "! storage or iterator not available" dk3app_mc_table_delete(rb, sz_defaults); rb = NULL; } } else { /* Error occured or not enough strings. */ if(errors_occured) { $? "! we had an error" if(verb) { /* Errors while reading file! */ } } else { $? "! too few entries" if(verb) { /* Too few entries in file! */ } } dk3app_mc_table_delete(rb, sz_defaults); rb = NULL; } } else { $? "! failed to allocate memory" } fclose(fipo); } else { $? "! failed to open file" } dk3app_set_source_file(app, source_file); dk3app_set_source_line(app, source_line); } else { $? "! file not found" } } else { $? ". either succeeded yet or errors" } } else { $? "! size of default message array is 0" } if(!(back)) { $? ". Using default values" back = dv; } } else { $? "! invalid arguments" } $? "- dk3app_my_messages %s", TR_PTR(back) return back; } /** Read one preferences file. @param app Application structure. @param fn File name to process. @param s Storage to save preference entries. @param i Iterator through storage. */ static void dk3app_rd_pref_file( dk3_app_t *app, dkChar const *fn, dk3_sto_t *s, dk3_sto_it_t *i ) { dkChar buffer[4096]; char bombuf[4]; dkChar *p1 = NULL; /* Preference key (name). */ dkChar *p2 = NULL; /* Preference value. */ dkChar *p3 = NULL; /* Scope attribute value. */ dkChar const *oldsourcename; /* Old source file name. */ FILE *fipo = NULL; /* Input file. */ unsigned long lineno = 0UL; /* Current line number. */ unsigned long oldsourceline; /* Old source line number. */ size_t skb; /* Bytes to skip at start. */ int scope_valid = 1; /* Flag: In a valid scope. */ int last_was_scope = 0; /* Flag: Previous line was scope. */ int scope_action = 0; /* 0=yes, 1=no */ int conditions_ok; /* Flag: All conditions ok. */ int ie = DK3_FILE_ENCODING_ASCII; /* Input encoding. */ skb = 0; ie = dk3sf_inspect_bom_skip_app(fn, DK3_FILE_ENCODING_ASCII, &skb, NULL); dk3app_log_i3(app, DK3_LL_DEBUG, 230, 231, fn); fipo = dk3sf_fopen_app(fn, dk3app_no_loc[22], NULL); /* READ */ if(fipo) { oldsourcename = dk3app_get_source_file(app); oldsourceline = dk3app_get_source_line(app); dk3app_set_source_file(app, fn); dk3app_set_source_line(app, 0UL); (void)dk3sf_apply_bom_to_file_app(fipo, ie, NULL); lineno = 0UL; if((skb > 0) && (skb <= 4)) { dk3sf_fread_app(bombuf, 1, skb, fipo, NULL); } while(dk3sf_fgets(buffer, DK3_SIZEOF(buffer,dkChar), fipo)) { lineno++; dk3app_set_source_line(app, lineno); $? ". MYSTIC set_source_line %lu", lineno p1 = dk3str_start(buffer, NULL); if(p1) { if(*p1 != dkT('#')) { if(*p1 == dkT('[')) { if(!last_was_scope) { scope_valid = 0; } scope_action = 0; p2 = dk3str_chr(p1, dkT(']')); if(p2) { *p2 = dkT('\0'); } p1++; dk3str_chomp(p1, NULL); if(*p1 == dkT('-')) { scope_action = 1; p1++; } p1 = dk3str_start(p1, NULL); conditions_ok = 1; while(p1) { p2 = dk3str_chr(p1, dkT(',')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); } p3 = dk3str_chr(p1, dkT('=')); if(p3) { *(p3++) = dkT('\0'); p3 = dk3str_start(p3, NULL); if(p3) { dk3str_chomp(p1, NULL); dk3str_chomp(p3, NULL); $? ". p1=\"%s\" p3=\"%s\"", p1, p3 switch(dk3str_array_index(dk3app_scope_attributes, p1, 0)) { case 0: { /* user */ if(dk3str_cmp(p3, dk3app_no_loc[33])) { if(app->n_logname) { #if DK3_ON_WINDOWS || DK3_HAVE_USER_NAMES_CASE_INSENSITIVE if(dk3str_casecmp(p3, app->n_logname)) { conditions_ok = 0; } #else if(dk3str_cmp(p3, app->n_logname)) { conditions_ok = 0; } #endif } else { conditions_ok = 0; } } } break; case 1: { /* application */ if(dk3str_cmp(p3, dk3app_no_loc[33])) { if(app->n_app) { #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS if(dk3str_casecmp(p3, app->n_app)) { conditions_ok = 0; } #else if(dk3str_cmp(p3, app->n_app)) { conditions_ok = 0; } #endif } else { conditions_ok = 0; } } } break; case 2: { /* application-group */ if(dk3str_cmp(p3, dk3app_no_loc[33])) { if(app->n_appgroup) { #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS if(dk3str_casecmp(p3, app->n_appgroup)) { conditions_ok = 0; } #else if(dk3str_cmp(p3, app->n_appgroup)) { conditions_ok = 0; } #endif } else { conditions_ok = 0; } } } break; case 3: { /* host */ if(dk3str_cmp(p3, dk3app_no_loc[33])) { if(app->n_hostname) { if(dk3str_casecmp(p3, app->n_hostname)) { conditions_ok = 0; } } else { conditions_ok = 0; } } } break; case 4: { /* language */ if(dk3str_cmp(p3, dk3app_no_loc[33])) { if(app->n_language) { if(dk3str_cmp(p3, app->n_language)) { conditions_ok = 0; } } else { conditions_ok = 0; } } } break; case 5: { /* region */ if(dk3str_cmp(p3, dk3app_no_loc[33])) { if(app->n_region) { if(dk3str_cmp(p3, app->n_region)) { conditions_ok = 0; } } else { conditions_ok = 0; } } } break; } } } p1 = p2; } last_was_scope = 1; if(conditions_ok) { if(scope_action) { scope_valid = 0; } else { scope_valid = 1; } } } else { last_was_scope = 0; if(scope_valid) { dk3str_chomp(p1, NULL); p2 = dk3str_chr(p1, dkT('=')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { dk3str_chomp(p1, NULL); dk3str_chomp(p2, NULL); if(!dk3app_add_pref(NULL, s, i, p1, p2)) { app->de = 33; } } } } } } } } fclose(fipo); dk3app_set_source_file(app, oldsourcename); dk3app_set_source_line(app, oldsourceline); } else { dk3app_log_i3(app, DK3_LL_DEBUG, 152, 153, fn); } } /** Read all preference files for an application. @param app Application structure. */ static void dk3app_read_preference_files(dk3_app_t *app) { dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */ int i = 0; /* Pass. */ $? "+ dk3app_read_preference_files" for(i = 0; i < 16; i++) { if(dk3app_config_name(app, dk3app_no_loc[21], fnb, DK3_MAX_PATH, i, 0)) { switch(i) { case 14: { $? ". varprefs %d \"%s\"", i, fnb if(!(app->s_varprefs)) { app->s_varprefs = dk3sto_open_app(NULL); if(app->s_varprefs) { dk3sto_set_comp(app->s_varprefs, dk3app_compare_pref, 0); } else { app->de = 36; } } if(!(app->i_varprefs)) { if(app->s_varprefs) { app->i_varprefs = dk3sto_it_open(app->s_varprefs); if(!(app->i_varprefs)) { app->de = 36; } } } if((app->s_varprefs) && (app->i_varprefs)) { dk3app_rd_pref_file(app, fnb, app->s_varprefs, app->i_varprefs); } } break; case 12: case 13: case 15: { $? ". constprefs %d \"%s\"", i, fnb if(!(app->s_constprefs)) { app->s_constprefs = dk3sto_open_app(NULL); if(app->s_constprefs) { dk3sto_set_comp(app->s_constprefs, dk3app_compare_pref, 0); } else { app->de = 36; } } if(!(app->i_constprefs)) { if(app->s_constprefs) { app->i_constprefs = dk3sto_it_open(app->s_constprefs); if(!(app->i_constprefs)) { app->de = 36; } } } if((app->s_constprefs) && (app->i_constprefs)) { dk3app_rd_pref_file(app,fnb,app->s_constprefs,app->i_constprefs); } } break; default: { $? ". sysprefs %d \"%s\"", i, fnb if(!(app->s_sysprefs)) { app->s_sysprefs = dk3sto_open_app(NULL); if(app->s_sysprefs) { dk3sto_set_comp(app->s_sysprefs, dk3app_compare_pref, 0); } else { app->de = 36; } } if(!(app->i_sysprefs)) { if(app->s_sysprefs) { app->i_sysprefs = dk3sto_it_open(app->s_sysprefs); if(!(app->i_sysprefs)) { app->de = 36; } } } if((app->s_sysprefs) && (app->i_sysprefs)) { dk3app_rd_pref_file(app, fnb, app->s_sysprefs, app->i_sysprefs); } } break; } } } $? "- dk3app_read_preference_files" } /** Find log level. @param app Application structure. @param ind Index of preference name in \a dk3app_no_loc. @param buffer Buffer for preference value. @param sz Size of \a buffer (number of characters). @param dv Default value to use if preference is not set. @return Log level found in preference or default value. */ static int dk3app_find_ll(dk3_app_t *app, int ind, dkChar *buffer, size_t sz, int dv) { int back = 0; dkChar *p1 = NULL; /* Value string. */ int i = 0; /* Index search result. */ back = dv; $? "+ dk3app_find_ll %d", dv if(dk3app_get_pref(app, dk3app_no_loc[ind], buffer, sz)) { $? ". pref ok" p1 = dk3str_start(buffer, NULL); if(p1) { #if DK3_CHAR_SIZE > 1 $? ". p1 = \"%ls\"", p1 #else $? ". p1 = \"%s\"", p1 #endif dk3str_chomp(p1, NULL); #if DK3_CHAR_SIZE > 1 $? ". p1 = \"%ls\"", p1 #else $? ". p1 = \"%s\"", p1 #endif i = dk3str_array_abbr(dk3app_log_levels, p1, dkT('$'), 0); if(i >= 0) { $? ". index ok" if(i <= DK3_LL_IGNORE) { back = i; $? ". new ll ok" } } else { $? "! index -1" } } else { $? "! no contents" } } else { $? "! pref not found" } $? "- dk3app_find_ll %d", back return back; } /** Preferences processing at application startup. @param app Application structure. */ static void dk3app_process_preferences(dk3_app_t *app) { dkChar buffer[4096]; dkChar *p1 = NULL; /* Start of language/region/encoding string. */ dkChar *p2 = NULL; /* Encoding, later region. */ dkChar *p3 = NULL; /* Used to convert to lower case. */ dkChar *p4 = NULL; /* New string for region. */ int i; /* Input encoding. */ if(dk3app_get_pref(app,dk3app_no_loc[27],buffer,DK3_SIZEOF(buffer,dkChar))) { p1 = dk3str_start(buffer, NULL); if(p1) { p2 = dk3str_chr(buffer, dkT('.')); if(p2) { *p2 = dkT('\0'); } p2 = dk3str_chr(buffer, dkT('_')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { dk3str_chomp(p2, NULL); p3 = p2; while(*p3) { *p3 = dk3str_tolower(*p3); p3++; } } } p3 = p1; while(*p3) { *p3 = dk3str_tolower(*p3); p3++; } dk3str_chomp(p1, NULL); p3 = dk3str_dup_app(p1, NULL); p4 = NULL; if(p2) { p4 = dk3str_dup_app(p2, NULL); } if(p3) { dk3_delete(app->n_language); app->n_language = p3; } if(p4) { dk3_delete(app->n_region); app->n_region = p4; } } } app->ll_file = dk3app_find_ll( app, 28, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_file ); app->ll_file_keep = dk3app_find_ll( app, 29, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_file_keep ); app->ll_stderr = dk3app_find_ll( app, 30, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_stderr ); app->ll_tmp_keep = dk3app_find_ll( app, 31, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_tmp_keep ); app->i_stdin_input_encoding = dk3app_get_default_stdin_encoding(app); $? "+ i_stdin_input_encoding=%d", app->i_stdin_input_encoding app->i_file_input_encoding = dk3app_get_default_file_encoding(app); if(dk3app_get_pref(app,dk3app_no_loc[51],buffer,DK3_SIZEOF(buffer,dkChar))) { p1 = dk3str_start(buffer, NULL); if(p1) { dk3str_chomp(p1, NULL); i = dk3enc_get_text_encoding_app(buffer, NULL); if(i >= 0) { app->i_file_input_encoding = i; } } } if(dk3app_get_pref(app,dk3app_no_loc[52],buffer,DK3_SIZEOF(buffer,dkChar))) { p1 = dk3str_start(buffer, NULL); if(p1) { dk3str_chomp(p1, NULL); i = dk3enc_get_text_encoding_app(buffer, NULL); if(i >= 0) { app->i_stdin_input_encoding = i; $? ". i_stdin_input_encoding=%d", app->i_stdin_input_encoding } } } } /** Create new application. @param wd Current working directory. @param argc Number of command line arguments. @param argv Command line arguments array. @param gn Application group name. @param tp Application type. @return Pointer to new application on success, NULL on error. */ static dk3_app_t * dk3app_open( dkChar const * wd, int argc, dkChar const * const * argv, dkChar const *gn, int tp ) { dk3_app_t *back = NULL; $? "+ dk3app_open" back = dk3_new(dk3_app_t,1); if(back) { dk3app_init(back); switch(tp) { case DK3_APP_TYPE_DAEMON: { back->ll_file = DK3_LL_INFO; } break; } back->app_type = tp; if(!(back->de)) { dk3app_save_group_name(back, gn); } if(!(back->de)) { dk3app_first_silence_check(back, argc, argv); } if(!(back->de)) { dk3app_language_and_region(back, argc, argv); } if(!(back->de)) { dk3app_find_names(back, wd, argc, argv); } if(!(back->de)) { dk3app_save_arguments(back, argc, argv); } if(!(back->de)) { dk3app_read_preference_files(back); } if(!(back->de)) { dk3app_process_preferences(back); } if(!(back->de)) { back->msg = dk3app_my_messages(back, dk3app_no_loc[23], dk3app_kw, 0); } back->f_readytolog = 1; if(back->de) { /* Delayed error occured. Report error, destroy structure. */ switch(back->de) { case 1: /* Error while saving command line arguments. */ case 2: /* Error while saving application name. */ case 4: /* Error while saving exec file name. */ case 6: /* Error while saving bin directory. */ case 7: /* Error while saving etc directory. */ case 8: /* Error while saving share directory. */ case 9: /* Error while saving var directory. */ case 15: /* Error while saving logname. */ case 17: /* Error while saving home directory. */ case 18: /* Error while saving application group name. */ case 21: /* Error while saving log file name. */ case 25: /* Error while saving temp dir name. */ case 28: /* Error while saving language string. */ case 29: /* Failed to save region! */ case 30: /* Failed to save language! */ case 33: /* Pref */ case 34: /* Pref storage */ case 35: /* Cmd prefs iterator */ case 36: /* Cmd prefs storage */ case 37: /* Store host name */ { dk3app_log_i1(back, DK3_LL_ERROR, 9); } break; case 3: /* Failed to find executable file name. */ { /* Failed to find executable file name. */ dk3app_log_i1(back, DK3_LL_ERROR, 40); } break; case 5: /* Incomplete exec file name. */ { /* No separator in executable file name! */ dk3app_log_i1(back, DK3_LL_ERROR, 40); } case 10: /* Program is started from root directory. */ { /* Too few directories in hierarchy! */ dk3app_log_i1(back, DK3_LL_ERROR, 41); } break; case 11: /* Error while creating etc directory name! */ case 12: /* Error while creating share directory name! */ case 13: /* Error while creating var directory name! */ { /* Name of executable file too long! */ dk3app_log_i1(back, DK3_LL_ERROR, 42); } break; case 14: { /* Failed to retrieve log name! */ /* Failed to retrieve log name! */ dk3app_log_i1(back, DK3_LL_ERROR, 43); } break; case 16: { /* Failed to retrieve home directory! */ /* Failed to retrieve home directory! */ dk3app_log_i1(back, DK3_LL_ERROR, 44); } break; case 19: { /* Log file name too long. */ /* Log file name gets too long! */ dk3app_log_i1(back, DK3_LL_ERROR, 45); } break; case 20: { /* Failed to create log directory! */ dk3app_log_i1(back, DK3_LL_ERROR, 46); } break; case 22: { /* Failed to convert PID to dkChar! */ dk3app_log_i1(back, DK3_LL_ERROR, 47); } break; case 23: { /* Home directory name missing! */ dk3app_log_i1(back, DK3_LL_ERROR, 44); } break; case 24: { /* Application name missing! */ dk3app_log_i1(back, DK3_LL_ERROR, 48); } break; case 26: { /* Name of tmp dir gets too long! */ dk3app_log_i1(back, DK3_LL_ERROR, 49); } break; case 27: { /* var dir name missing! */ dk3app_log_i1(back, DK3_LL_ERROR, 50); } break; case 31: { /* Preference name too long! */ dk3app_log_i1(back, DK3_LL_ERROR, 51); } break; case 32: { /* Not a preference entry! */ dk3app_log_i1(back, DK3_LL_ERROR, 52); } break; case 38: { dk3app_log_i1(back, DK3_LL_ERROR, 131); } break; } dk3app_close(back); back = NULL; } else { $? ". now write debug log messages" dk3app_log_i3(back, DK3_LL_DEBUG, 19, 20, back->n_app); dk3app_log_i2( back, DK3_LL_DEBUG, 23, ((back->n_app) ? back->n_app: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 24, ((back->n_appgroup) ? back->n_appgroup: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 25, ((back->n_execfile) ? back->n_execfile: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 26, ((back->n_bindir) ? back->n_bindir: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 27, ((back->n_etcdir) ? back->n_etcdir: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 28, ((back->n_sharedir) ? back->n_sharedir: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 29, ((back->n_vardir) ? back->n_vardir: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 30, ((back->n_homedir) ? back->n_homedir: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 31, ((back->n_tmpdir) ? back->n_tmpdir: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 32, ((back->n_logname) ? back->n_logname: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 132, ((back->n_hostname) ? back->n_hostname: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 33, ((back->n_logfilename) ? back->n_logfilename: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 34, ((back->n_language) ? back->n_language: ((back->msg) ? back->msg : dk3app_kw)[36]) ); dk3app_log_i2( back, DK3_LL_DEBUG, 35, ((back->n_region) ? back->n_region: ((back->msg) ? back->msg : dk3app_kw)[36]) ); } } else { if(tp == DK3_APP_TYPE_COMMAND) { /* ERROR: Not enough memory */ dk3sf_initialize_stderr(); dk3sf_fputs(dk3app_kw[9], stderr); dk3sf_fputs(dk3app_kw[0], stderr); fflush(stderr); } } $? "- dk3app_open %s", TR_PTR(back) return back; } dk3_app_t * dk3app_open_command(int argc, dkChar const * const * argv, dkChar const *gn) { dk3_app_t *back = NULL; dkChar wd[DK3_MAX_PATH]; /* Current working directory. */ if((argc) && (argv) && (gn)) { if(dk3sf_getcwd_app(wd, DK3_SIZEOF(wd,dkChar), NULL)) { back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_COMMAND); } else { /* ERROR: Failed to find current working directory. */ if(!dk3app_first_silence_check(NULL, argc, argv)) { dk3sf_initialize_stderr(); dk3sf_fputs(dk3app_kw[3], stderr); dk3sf_fputs(dk3app_kw[11], stderr); dk3sf_fputs(dk3app_kw[8], stderr); dk3sf_fputs(dk3app_kw[53], stderr); dk3sf_fputs(dk3app_kw[0], stderr); fflush(stderr); } } } return back; } dk3_app_t * dk3app_open_gui(int argc, dkChar const * const * argv, dkChar const *gn) { dk3_app_t *back = NULL; dkChar wd[DK3_MAX_PATH]; /* Current working directory. */ if((argc) && (argv) && (gn)) { if(dk3sf_getcwd_app(wd, DK3_SIZEOF(wd,dkChar),NULL)) { back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_GUI); } else { /* ERROR: Failed to find current working directory. */ } } return back; } dk3_app_t * dk3app_open_daemon( dkChar const *wd, int argc, dkChar const * const * argv, dkChar const *gn ) { dk3_app_t *back = NULL; if((wd) && (argc) && (argv) && (gn)) { back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_DAEMON); } return back; } dk3_app_t * dk3app_open_silent(int argc, dkChar const * const * argv, dkChar const *gn) { dk3_app_t *back = NULL; dkChar wd[DK3_MAX_PATH]; /* Current working directory. */ if((argc) && (argv) && (gn)) { if(dk3sf_getcwd_app(wd, DK3_SIZEOF(wd,dkChar),NULL)) { back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_SILENT); } else { /* ERROR: Failed to find current working directory. */ } } return back; } dkChar const * const * dk3app_get_argv(dk3_app_t const *app) { dkChar const * const *back = NULL; if(app) { back = (dkChar const * const *)(app->argv); } return back; } int dk3app_get_argc(dk3_app_t const *app) { int back = 0; if(app) { back = app->argc; } return back; } dkChar const * dk3app_get_appname(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_app; } $? "= dk3app_get_appname %s", TR_STR(back) return back; } dkChar const * dk3app_get_execfilename(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_execfile; } return back; } dkChar const * dk3app_get_bindir(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_bindir; } return back; } dkChar const * dk3app_get_etcdir(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_etcdir; } return back; } dkChar const * dk3app_get_sharedir(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_sharedir; } return back; } dkChar const * dk3app_get_vardir(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_vardir; } return back; } dkChar const * dk3app_get_logname(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_logname; } return back; } dkChar const * dk3app_get_hostname(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_hostname; } return back; } dkChar const * dk3app_get_homedir(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_homedir; } return back; } dkChar const * dk3app_get_appgroup(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_appgroup; } return back; } int dk3app_get_temp_file_name(dk3_app_t *app, dkChar *db, size_t sz) { int back = 0; char fn[16]; /* BUffer for sprintf(). */ dkChar fn2[16]; /* Short file name buffer. */ size_t s = 0; /* Buffer length needed. */ $? "+ dk3app_get_temp_file_name" if((app) && (db) && (sz)) { if(app->n_tmpdir) { if(!(app->i_tmpcarry)) { sprintf(fn, "/%08lx.%03x", app->ul_tmpname, app->u_tmpsuffix); back = 1; app->u_tmpsuffix += 1U; if(app->u_tmpsuffix >= 0x1000U) { app->u_tmpsuffix = 0U; app->ul_tmpname += 1UL; if(app->ul_tmpname == 0UL) { app->i_tmpcarry = 1; back = 0; /* Too many temporary file names asked! */ dk3app_log_i1(app, DK3_LL_ERROR, 54); } } if(back) { back = 0; if(dk3str_cnv_c8_to_str_app(fn2, 15, fn, app)) { s = dk3str_len(app->n_tmpdir) + dk3str_len(fn2); if(s < sz) { dk3str_cpy_not_overlapped(db, app->n_tmpdir); dk3str_cat(db, fn2); dk3str_correct_filename(db); back = 1; } else { /* Destination buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } } } else { /* Not directory for temporary files available! */ dk3app_log_i1(app, DK3_LL_ERROR, 55); } } $? "- dk3app_get_temp_file_name %d", back return back; } dkChar const * dk3app_get_language(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_language; } return back; } dkChar const * dk3app_get_region(dk3_app_t const *app) { dkChar const *back = NULL; if(app) { back = app->n_region; } return back; } int dk3app_get_encoding(dk3_app_t const *app) { int back = 0; if(app) { back = app->i_encoding; } return back; } int dk3app_get_output_encoding(dk3_app_t const *app) { int back = 0; if(app) { back = app->i_output_encoding; } return back; } int dk3app_get_input_stdin_encoding(dk3_app_t const *app) { int back = 0; if(app) { back = app->i_stdin_input_encoding; } return back; } int dk3app_get_input_file_encoding(dk3_app_t const *app) { int back = 0; if(app) { back = app->i_file_input_encoding; } return back; } int dk3app_set_pref(dk3_app_t *app, dkChar const *k, dkChar const *v) { int back = 0; if((app) && (k) && (v)) { if(!(app->s_selfprefs)) { app->s_selfprefs = dk3sto_open_app(app); if(app->s_selfprefs) { dk3sto_set_comp(app->s_selfprefs, dk3app_compare_pref, 0); } } if(!(app->i_selfprefs)) { if(app->s_selfprefs) { app->i_selfprefs = dk3sto_it_open(app->s_selfprefs); } } if((app->s_selfprefs) && (app->i_selfprefs)) { back = dk3app_add_pref(app, app->s_selfprefs, app->i_selfprefs, k, v); app->f_prefschanged = 1; } if(!back) { /* Failed to save preference value! */ dk3app_log_i5(app, DK3_LL_ERROR, 56, 57, 58, k, v); } } return back; } int dk3app_get_pref(dk3_app_t *app, dkChar const *k, dkChar *d, size_t s) { int back = 0; $? "+ dk3app_get_pref" if((app) && (k) && (d) && (s)) { #if DK3_CHAR_SIZE > 1 $? ". k=\"%ls\"", k #else $? ". k=\"%s\"", k #endif back = dk3app_sto_pref(app, app->i_selfprefs, k, d, s); if(back == 0) { back = dk3app_sto_pref(app, app->i_cmdprefs, k, d, s); if(back == 0) { back = dk3app_sto_pref(app, app->i_varprefs, k, d, s); if(back == 0) { back = dk3app_sto_pref(app, app->i_constprefs, k, d, s); if(back == 0) { back = dk3app_sto_pref(app, app->i_sysprefs, k, d, s); } } } } $!trace-code if(back) { #if DK3_CHAR_SIZE > 1 $? ". v=\"%ls\"", d #else $? ". v=\"%s\"", d #endif $!trace-code } } $? "- dk3app_get_pref %d", back return back; } int dk3app_get_sys_pref(dk3_app_t *app, dkChar const *k, dkChar *d, size_t s) { int back = 0; if((app) && (k) && (d) && (s)) { back = dk3app_sto_pref(app, app->i_selfprefs, k, d, s); if(back == 0) { back = dk3app_sto_pref(app, app->i_sysprefs, k, d, s); } } return back; } /** Check whether the use of system configuration files is allowed for a file name. @param app Application structure. @param fn Short file name. @return 1 for system config files allowed, 0 for user files only. */ static int dk3app_allow_system_config_files(dk3_app_t *app, dkChar const *fn) { int back = 1; dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */ dkChar il[1024 + DK3_MAX_PATH]; /* Input line buffer. */ char bombuf[4]; /* Buffer to skip BOM. */ dkChar *p1 = NULL; /* Key (entry name). */ dkChar *p2 = NULL; /* Value. */ FILE *fipo = NULL; /* Input file. */ int ie = DK3_FILE_ENCODING_ASCII; /* Input encoding for file. */ int cc = 1; /* Flag: Can continue. */ size_t sz = 0; /* Buffer size needed. */ size_t skb; /* Number of bytes to skip. */ if(app->n_homedir) { sz = dk3str_len(app->n_homedir); sz += (2 * dk3str_len(dk3app_no_loc[20])); sz += dk3str_len(dk3app_no_loc[18]); sz += dk3str_len(dk3app_no_loc[34]); if(sz < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, app->n_homedir); dk3str_cat(fnb, dk3app_no_loc[20]); dk3str_cat(fnb, dk3app_no_loc[18]); dk3str_cat(fnb, dk3app_no_loc[20]); dk3str_cat(fnb, dk3app_no_loc[34]); skb = 0; ie = dk3sf_inspect_bom_skip_app(fnb, DK3_FILE_ENCODING_ASCII, &skb, NULL); fipo = dk3sf_fopen_app(fnb, dk3app_no_loc[22], NULL); /* READ */ if(fipo) { (void)dk3sf_apply_bom_to_file_app(fipo, ie, NULL); cc = 1; if((skb > 0) && (skb <= 4)) { dk3sf_fread_app(bombuf, 1, skb, fipo, NULL); } while(cc) { if(dk3sf_fgets(il, DK3_SIZEOF(il,dkChar), fipo)) { p1 = dk3str_start(il, NULL); if(p1) { if(*p1 != dkT('#')) { p2 = dk3str_chr(p1, dkT('=')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { dk3str_chomp(p2, NULL); dk3str_normalize(p1, NULL, dkT('-')); switch(dk3str_array_index(dk3app_conf_file, p1, 0)) { case 0: { /* use system config files */ if(dk3str_cmp(p2, dk3app_no_loc[33]) == 0) { back = 1; cc = 0; } else { if(dk3str_cmp(p2, fn) == 0) { back = 1; cc = 0; } } } break; case 1: { /* ignore system config files */ if(dk3str_cmp(p2, dk3app_no_loc[33]) == 0) { back = 0; cc = 0; } else { if(dk3str_cmp(p2, fn) == 0) { back = 0; cc = 0; } } } break; } } } } } } else { cc = 0;} } fclose(fipo); } } else { /* ERROR: Home directory name too long! */ dk3app_log_i1(app, DK3_LL_ERROR, 194); } } return back; } /** Find configuration files for a given name. @param app Application structure. @param fn File name. @param res Flag: Reverse search order. @param exclu Flag: Exclude user files. @return Pointer to search result collection on success, NULL on error. */ static dk3_search_t * dk3app_my_find_config_file(dk3_app_t *app, dkChar const *fn, int res, int exclu) { dk3_search_t *back = NULL; unsigned long items_found = 0; /* Number of items found. */ int error_occured = 0; /* Flag: Error occured. */ int i = 0; /* Current pass number. */ int r = 0; /* Result from check for conf file. */ int max = 0; /* Maximum pass number. */ int min = 0; /* Minimum pass number. */ dkChar buffer[DK3_MAX_PATH]; /* File name buffer. */ if((app) && (fn)) { back = dk3search_open_app(res, app); if(back) { min = 0; max = 16; if(app->app_type == DK3_APP_TYPE_DAEMON) { max = 6; } else { if(exclu) { max = 12; } else { if(!dk3app_allow_system_config_files(app, fn)) { min = 12; /* DEBUG: System config files skipped by user. */ dk3app_log_i1(app, DK3_LL_DEBUG, 195); } } } for(i = min; i < max; i++) { r = dk3app_check_config_file(app, fn, buffer, DK3_MAX_PATH, i, 1); if(r) { if(dk3search_add(back, buffer)) { items_found++; } else { error_occured = 1; } } } if(error_occured) { dk3search_close(back); back = NULL; } else { if(items_found == 0UL) { dk3search_close(back); back = NULL; } } } } return back; } dk3_search_t * dk3app_find_config_file(dk3_app_t *app, dkChar const *fn, int exclu) { dk3_search_t *back = NULL; if((app) && (fn)) { back = dk3app_my_find_config_file(app, fn, 0, exclu); } return back; } dk3_search_t * dk3app_find_config_file_revers(dk3_app_t *app, dkChar const *fn, int exclu) { dk3_search_t *back = NULL; if((app) && (fn)) { back = dk3app_my_find_config_file(app, fn, 1, exclu); } return back; } int dk3app_find_data_file(dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz) { int back = 0; if((app) && (fn) && (db) && (sz)) { back = dk3app_my_find_data_file(app, fn, db, sz, 1); } return back; } void dk3app_unconfigure(dk3_app_t *app) { if(app) { app->f_unconfigure = 1; } } dkChar const * const * dk3app_messages(dk3_app_t *app, dkChar const *fn, dkChar const * const *dv) { dkChar const * const *back; $? "+ dk3app_messages" back = dk3app_my_messages(app, fn, dv, 0); $? "- dk3app_messages %s", TR_PTR(back) return back; } void dk3app_help(dk3_app_t *app, dkChar const *fn, dkChar const * const *dt) { int had_success = 0; /* Flag: Success. */ dkChar buffer[DK3_MAX_PATH]; /* File name buffer. */ char lb[1024]; /* Input line buffer. */ dkChar db[1024]; /* Output line buffer. */ FILE *fipo = NULL; /* Input file. */ dkChar const * const *ptr = NULL; /* Help text line. */ $? "+ dk3app_help" if((app) && (fn) && (dt)) { dk3sf_initialize_stdout(); if(dk3app_my_find_data_file(app, fn, buffer, DK3_SIZEOF(buffer,dkChar), 0)) { fipo = dk3sf_fopen_app(buffer, dk3app_no_loc[22], app); /* UTF-8 */ if(fipo) { had_success = 1; while(fgets(lb, sizeof(lb), fipo)) { $? ". \"%s\"", lb #if DK3_CHAR_SIZE == 2 if(dk3str_cnv_c8u_to_c16_app(db, DK3_SIZEOF(db,dkChar), lb, app)) { dk3sf_fputs(db, stdout); } #else switch(app->i_encoding) { case DK3_ENCODING_PLAIN: { if(dk3str_cnv_c8u_to_c8p_app(db, DK3_SIZEOF(db,dkChar), lb, app)) { fputs(db, stdout); } } break; default: { fputs(lb, stdout); } break; } #endif } fclose(fipo); } } if(!had_success) { ptr = dt; while(*ptr) { dk3sf_fputs(*(ptr++), stdout); dk3sf_fputc(dkT('\n'), stdout); } } } $? "- dk3app_help" } int dk3app_get_stderr_log_level(dk3_app_t const *app) { int back = DK3_LL_ERROR; if(app) { back = app->ll_stderr; } return back; } void dk3app_set_stderr_log_level(dk3_app_t *app, int ll) { if(app) { app->ll_stderr = ll; } } void dk3app_log_write_error(dk3_app_t *app, int ll, size_t wished, size_t written) { dkChar b1[128]; /* Number of bytes wished to write. */ dkChar b2[128]; /* Number of bytes really written. */ #if VERSION_BEFORE_20140716 dk3sf_sprintf3(b1,dk3app_no_loc[35],((unsigned long)wished)); dk3sf_sprintf3(b2,dk3app_no_loc[35],((unsigned long)written)); dk3app_log_i5(app, ll, 170, 171, 172, b2, b1); #else if (dk3ma_um_to_string(b1, DK3_SIZEOF(b1,dkChar), (dk3_um_t)wished)) { if (dk3ma_um_to_string(b2, DK3_SIZEOF(b2,dkChar), (dk3_um_t)written)) { dk3app_log_i5(app, ll, 170, 171, 172, b2, b1); } } #endif } void dk3app_log_fwrite_error(dk3_app_t *app, int ll, size_t wished, size_t written) { dkChar b1[128]; /* Number of bytes wished to write. */ dkChar b2[128]; /* Number of bytes really written. */ #if VERSION_BEFORE_20140716 dk3sf_sprintf3(b1,dk3app_no_loc[35],((unsigned long)wished)); dk3sf_sprintf3(b2,dk3app_no_loc[35],((unsigned long)written)); dk3app_log_i5(app, ll, 174, 175, 176, b2, b1); #else if (dk3ma_um_to_string(b1, DK3_SIZEOF(b1,dkChar), (dk3_um_t)wished)) { if (dk3ma_um_to_string(b2, DK3_SIZEOF(b2,dkChar), (dk3_um_t)written)) { dk3app_log_i5(app, ll, 174, 175, 176, b2, b1); } } #endif } dkChar const * dk3app_localized(dk3_app_t const *app, size_t num) { dkChar const *back = NULL; if(app) { if(app->msg) { back = (app->msg)[num]; } else { back = dk3app_kw[num]; } } return back; } dkChar const * dk3app_not_localized(size_t num) { dkChar const *back = NULL; back = dk3app_no_loc[num]; return back; } int dk3app_get_pref_bool(dk3_app_t *app, dkChar const *name, int dv) { int back; dkChar buffer[256]; /* Buffer for preference value. */ dkChar *p1; /* Start of text. */ back = dv; if(app) { if(dk3app_get_pref(app, name, buffer, DK3_SIZEOF(buffer,dkChar))) { p1 = dk3str_start(buffer, NULL); if(p1) { dk3str_chomp(p1, NULL); if(dk3str_is_bool(p1)) { back = ((dk3str_is_on(p1)) ? 1 : 0); } } } } return back; } int dk3app_get_pref_int(dk3_app_t *app, dkChar const * name, int dv) { int back; int x; dkChar buffer[256]; dkChar *p1; $? "+ dk3app_get_pref_int" back = dv; if(app) { if(dk3app_get_pref(app, name, buffer, DK3_SIZEOF(buffer,dkChar))) { p1 = dk3str_start(buffer, NULL); if(p1) { #if VERSION_BEFORE_20140716 if(dk3sf_sscanf3(p1, dkT("%d"), &x) == 1) #else if (0 != dk3ma_i_from_string(&x, p1, NULL)) #endif { back = x; } } } } $? "- dk3app_get_pref_int %d", back return back; } #if 0 int dk3app_get_allowed_prng_types(dk3_app_t *app, dkChar const *il) { int back = 0; dkChar buffer[256]; dkChar *p1 = NULL; dkChar *p2 = NULL; int i = 0; if((app) && (il)) { if(dk3str_len(il) < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, il); p1 = dk3str_start(buffer, NULL); while(p1) { p2 = dk3str_chr(p1, dkT(',')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); } i = dk3str_array_index(dk3app_prng_type_names, p1, 0); switch(i) { case 0: { #if DK3_HAVE_OPENSSL_RAND_H back |= DK3_PRNG_OPENSSL; #else /* ERROR: Openssl PRNG not available! */ dk3app_log_i1(app, DK3_LL_ERROR, 192); #endif } break; case 1: { #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM back |= DK3_PRNG_STATE; #else /* ERROR: initstate()/setstate()/random() not available. */ dk3app_log_i1(app, DK3_LL_ERROR, 191); #endif } break; case 2: { #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 back |= DK3_PRNG_RAND48; #else /* ERROR: lrand48()/lrand48() not available. */ dk3app_log_i1(app, DK3_LL_ERROR, 190); #endif } break; case 3: { #if DK3_HAVE_RAND && DK3_HAVE_SRAND back |= DK3_PRNG_SIMPLE; #else /* ERROR: srand()/rand() not available! */ dk3app_log_i1(app, DK3_LL_ERROR, 189); #endif } break; default: { /* Unknown PRNG type name! */ dk3app_log_i3(app, DK3_LL_ERROR, 187, 188, p1); } break; } p1 = p2; } } else { /* ERROR: Line too long for buffer! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } return back; } /** Find allowed PRNG types using preferences. @param app Application structure. @return Or-combination of DK3_PRNG_xxx. */ static int dk3app_rand_find_allowed_types(dk3_app_t *app) { int back = DK3_PRNG_ALL; dkChar buffer[256]; $? "+ dk3app_rand_find_allowed_types" if(dk3app_get_pref(app,dk3app_no_loc[37],buffer,DK3_SIZEOF(buffer,dkChar))) { $? ". preference value \"%s\"", buffer back = dk3app_get_allowed_prng_types(app, buffer); } $? "- dk3app_rand_find_allowed_types %d", back return back; } /** Get bytes to seed random number generator. @param app Application structure. @param dp Destination buffer pointer. @param sz Number of bytes required. @param fn File name for seed file. @return Number of bytes found. */ static size_t dk3app_read_bytes_from_file( dk3_app_t *app, void *dp, size_t sz, dkChar const *fn ) { size_t back = 0; FILE *fipo; fipo = dk3sf_fopen_app(fn, dk3app_no_loc[36], app); if(fipo) { back = dk3sf_fread_app(dp, 1, sz, fipo, app); fclose(fipo); } return back; } /** Get bytes to seed random number generator. @param app Application structure. @param dp Destination buffer pointer. @param sz Number of bytes required. @param fn File name for seed file. @return Number of bytes found. */ static size_t dk3app_get_seed_from_source(dk3_app_t *app,void *dp,size_t sz,dkChar const *fn) { size_t back = 0; dk3_stat_t stb; int can_use_file = 1; int mode_denied; $? "+ dk3app_get_seed_from_source \"%s\"", fn /* DEBUG: Attempting to get seed data from ... */ dk3app_log_i3(app, DK3_LL_DEBUG, 196, 197, fn); if(dk3sf_stat_app(&stb, fn, NULL)) { $? ". file exists" switch((stb.ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_DIRECTORY: { /* Ignore it. */ } break; case DK3_FT_REGULAR: { /* Security checks before using the file. */ mode_denied = DK3_FPERM_G_READ | DK3_FPERM_G_WRITE | DK3_FPERM_O_READ | DK3_FPERM_O_WRITE; if((stb.ft) & DK3_FT_SYMLINK) { if((stb.ai) & DK3_STAT_AI_USER_DIFFERS) { can_use_file = 0; /* WARNING: Symlink owner is not file owner. */ dk3app_log_i3(app, DK3_LL_ERROR, 185, 186, fn); } if((stb.perm) & mode_denied) { can_use_file = 0; /* WARNING: File not used (permissions). */ dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn); } else { if((stb.lperm) & mode_denied) { can_use_file = 0; /* WARNING: File not used (permissions). */ dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn); } } } else { if((stb.perm) & mode_denied) { can_use_file = 0; /* WARNING: File not used (permissions). */ dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn); } } if(can_use_file) { back = dk3app_read_bytes_from_file(app, dp, sz, fn); } } break; default: { /* Use file. */ back = dk3app_read_bytes_from_file(app, dp, sz, fn); } break; } } $? "- dk3app_get_seed_from_source %u", (unsigned)back /* DEBUG: Seed data: ... bytes. */ { char b1[64]; dkChar b2[64]; sprintf(b1, "%lu", (unsigned long)back); if(dk3str_cnv_c8_to_str_app(b2, DK3_SIZEOF(b2,dkChar), b1, app)) { dk3app_log_i3(app, DK3_LL_DEBUG, 198, 199, b2); } } return back; } /** Get bytes to seed random number generator. @param app Application structure. @param dp Destination buffer pointer. @param sz Number of bytes required. @param fn File name for seed file. @param passno Pass number (only 0 uses files). @return Number of bytes found. */ static size_t dk3app_get_seed_bytes( dk3_app_t *app, void *dp, size_t sz, dkChar const *fn, int passno ) { size_t back = 0; dkChar const *p1; dkChar const *p2; dkChar const *p3; dkChar const *p4; dkChar const *p5; dkChar *p6; size_t s; dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */ if((app) && (dp) && (sz)) { /* $HOME/.rnd-xxx-application */ if(passno == 0) { if(dk3app_get_pref_bool(app, dk3app_no_loc[46], 1)) { p1 = dk3app_get_homedir(app); p2 = dk3app_no_loc[20]; p3 = fn; p4 = dk3app_no_loc[5]; p5 = dk3app_get_appname(app); if((p1) && (p2) && (p3) && (p4) && (p5)) { s = dk3str_len(p1); s += dk3str_len(p2); s += dk3str_len(p3); s += dk3str_len(p4); s += dk3str_len(p5); if(s < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, p1); dk3str_cat(fnb, p2); dk3str_cat(fnb, p3); dk3str_cat(fnb, p4); dk3str_cat(fnb, p5); back = dk3app_get_seed_from_source(app, dp, sz, fnb); } } } } /* EGD socket from environment. */ if(back == 0) { p1 = dk3sf_getenv(dk3app_no_loc[43]); if(p1) { back = dk3app_get_seed_from_source(app, dp, sz, p1); } } /* EGD socket from preferences. */ if(back == 0) { if(dk3app_get_pref(app, dk3app_no_loc[42], fnb, DK3_SIZEOF(fnb,dkChar))) { p6 = dk3str_start(fnb, NULL); if(p6) { dk3str_chomp(p6, NULL); back = dk3app_get_seed_from_source(app, dp, sz, p6); } } } #if !DK3_ON_WINDOWS /* /dev/urandom */ if(back == 0) { back = dk3app_get_seed_from_source(app, dp, sz, dk3app_no_loc[44]); } /* /dev/random */ if(back == 0) { back = dk3app_get_seed_from_source(app, dp, sz, dk3app_no_loc[45]); } #endif } return back; } #if DK3_HAVE_OPENSSL_H /** Initialize OpenSSL PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_openssl(dk3_app_t *app) { int back = 0; int cc = 0; int passno = 0; size_t sz; char seedval[DK3_SEED_OPENSSL_BYTES]; do { cc = 0; sz = dk3app_get_seed_bytes(app,seedval,sizeof(seedval),dk3app_no_loc[41],passno); if(sz > 0) { cc = 1; RAND_seed(seedval, sz); if(RAND_status() == 1) { cc = 0; back = 1; } #if DK3_ON_WINDOWS if(back == 0) { RAND_screen(); if(RAND_status() == 1) { cc = 0; back = 1; } } #endif passno++; } } while(cc); if(!back) { /* Warning: Failed to seed OpenSSL PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 182); } return back; } #endif #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM /** Initialize state PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_state(dk3_app_t *app) { int back = 0; unsigned int seedval = 0; if(dk3app_get_seed_bytes( app, (void *)(&seedval), sizeof(unsigned int), dk3app_no_loc[40], 0 ) ) { srandom(seedval); back = 1; } if(!back) { /* Warning: Failed to seed random() PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 181); } return back; } #endif #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 /** Initialize lrand48() PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_rand48(dk3_app_t *app) { int back = 0; long int seedval = 0L; if(dk3app_get_seed_bytes( app, (void *)(&seedval), sizeof(long int), dk3app_no_loc[39], 0 ) ) { srand48(seedval); back = 1; } if(!back) { /*Warning: Failed to seed lrand48() PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 180); } return back; } #endif #if DK3_HAVE_RAND && DK3_HAVE_SRAND /** Initialize simple rand() PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_simple(dk3_app_t *app) { int back = 0; unsigned int ui; if( dk3app_get_seed_bytes( app, (void *)(&ui), sizeof(unsigned int), dk3app_no_loc[38], 0 ) ) { srand(ui); back = 1; } if(!back) { /* Warning: Failed to seed simple PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 179); } return back; } #endif /** Attempt to initialize a PRNG. @param app Application structure. @param il Input line listing allowed PRNGs comma-separated. @return 1 on success (at least one PRNG usable), 0 on error. */ int dk3app_rand_init(dk3_app_t *app, dkChar const *il) { int back = 0; int allowed_types; if(app) { if(app->f_rand_initialized) { back = app->f_rand_success; } else { app->f_rand_initialized = 1; if(il) { allowed_types = dk3app_get_allowed_prng_types(app, il); } else { allowed_types = dk3app_rand_find_allowed_types(app); } if(!back) { if(allowed_types & DK3_PRNG_OPENSSL) { #if DK3_HAVE_OPENSSL_H back = dk3app_init_prng_openssl(app); if(back) { app->rand_type = DK3_PRNG_OPENSSL; } #endif } } if(!back) { if(allowed_types & DK3_PRNG_STATE) { #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM back = dk3app_init_prng_state(app); if(back) { app->rand_type = DK3_PRNG_STATE; } #endif } } if(!back) { if(allowed_types & DK3_PRNG_RAND48) { #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 back = dk3app_init_prng_rand48(app); if(back) { app->rand_type = DK3_PRNG_RAND48; } #endif } } if(!back) { if(allowed_types & DK3_PRNG_SIMPLE) { #if DK3_HAVE_RAND && DK3_HAVE_SRAND back = dk3app_init_prng_simple(app); if(back) { app->rand_type = DK3_PRNG_SIMPLE; } #endif } } if(back) { app->f_rand_success = 1; } } } if(!back) { /* ERROR: No PRNG usable! */ dk3app_log_i1(app, DK3_LL_ERROR, 178); } return back; } /** Get random bytes. @param app Application structure. @param db Destination buffer. @param sz Size of \a db (number of bytes). @param f_crypto Flag: For cryptographic purposes. @return Number of bytes written to \a db. */ static size_t dk3app_rand_bytes_internal(dk3_app_t *app, void *db, size_t sz, int f_crypto) { size_t back = 0; unsigned char *ucptr = NULL; size_t i = 0; unsigned u = 0; if((app) && (db) && (sz)) { ucptr = (unsigned char *)db; if(!(app->f_rand_initialized)) { dk3app_rand_init(app, NULL); } if(app->f_rand_success) { switch(app->rand_type) { case DK3_PRNG_OPENSSL: { #if DK3_HAVE_OPENSSL_RAND_H if(f_crypto) { if(RAND_bytes(ucptr, (int)sz) == 1) { back = sz; } } else { if(RAND_pseudo_bytes(ucptr, (int)sz) > -1) { back = sz; } } #else /* BUG: Not available! */ #endif } break; case DK3_PRNG_STATE: { #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM long lval; size_t position; lval = random() >> 8; position = 0; for(i = 0; i < sz; i++) { *(ucptr++) = (unsigned char)(lval & 0x000000FFL); position++; lval = lval >> 8; if(position >= (sizeof(long) - 1)) { lval = random() >> 8; position = 0; } } back = sz; #else /* BUG: Not available! */ #endif } break; case DK3_PRNG_RAND48: { #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 long lval; size_t position; lval = lrand48() >> 8; position = 0; for(i = 0; i < sz; i++) { *(ucptr++) = (unsigned char)(lval & 0x000000FFL); position++; lval = lval >> 8; if(position >= (sizeof(long) - 1)) { lval = lrand48() >> 8; position = 0; } } back = sz; #else /* BUG: Not available! */ #endif } break; default: { #if DK3_HAVE_RAND && DK3_HAVE_SRAND for(i = 0; i < sz; i++) { u = rand(); #if DK3_SIZEOF_INT > 2 #if DK3_SIZEOF_INT > 4 u = u >> 28; #else u = u >> 12; #endif #else u = u >> 4; #endif u &= 0x00FFU; *(ucptr++) = (unsigned char)u; } back = sz; #else /* BUG: Not available! */ #endif } break; } } } if(back < sz) { /* ERROR: Failed to obtain enough random bytes! */ dk3app_log_i1(app, DK3_LL_ERROR, 177); } return back; } size_t dk3app_rand_bytes(dk3_app_t *app, void *db, size_t sz) { size_t back; back = dk3app_rand_bytes_internal(app, db, sz, 1); return back; } size_t dk3app_rand_bytes_non_crypto(dk3_app_t *app, void *db, size_t sz) { size_t back; back = dk3app_rand_bytes_internal(app, db, sz, 0); return back; } #endif int dk3app_process_stdin_lines( dk3_app_t *app, void *obj, dk3_line_handler_t *hf, dkChar *buffer, size_t szbuffer, int de ) { int back = 0; int must_run_directly = 0; int ie; FILE *fipo; dkChar tfn[DK3_MAX_PATH]; char b[4096]; size_t sz; #if DK3_ON_WINDOWS int oldmode; #endif if((app) && (hf) && (buffer) && (szbuffer)) { ie = de; if(ie < 0) { ie = app->i_stdin_input_encoding; } if(dk3app_get_temp_file_name(app, tfn, DK3_SIZEOF(tfn,dkChar))) { fipo = dk3sf_fopen_app(tfn, dk3app_no_loc[53], app); if(fipo) { #if DK3_ON_WINDOWS oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif while((sz = dk3sf_fread_app(b, 1, sizeof(b), stdin, app)) > 0) { dk3sf_fwrite_app(b, 1, sz, fipo, app); } fclose(fipo); #if DK3_ON_WINDOWS _setmode(_fileno(stdin), oldmode); #endif back = dk3stream_process_filename_lines_app( obj, hf, tfn, buffer, szbuffer, dk3app_get_encoding(app), de, app ); dk3sf_remove_file_app(tfn, app); } else { must_run_directly = 1; } } else { must_run_directly = 1; } if(must_run_directly) { #if DK3_ON_WINDOWS oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif back = dk3stream_process_file_lines_app( obj, hf, stdin, NULL, buffer, szbuffer, dk3app_get_encoding(app), de, app ); #if DK3_ON_WINDOWS _setmode(_fileno(stdin), oldmode); #endif } } return back; } int dk3app_process_stdin_chars( dk3_app_t *app, void *obj, dk3_char_handler_t *hf, int de ) { int back = 0; int must_run_directly = 0; int ie; dkChar tfn[DK3_MAX_PATH]; char b[4096]; FILE *fipo; size_t sz; #if DK3_ON_WINDOWS int oldmode; #endif $? "+ dk3app_process_stdin_chars" if((app) && (hf)) { $? ". default encoding = %d", de ie = de; if(ie < 0) { ie = app->i_stdin_input_encoding; } $? ". input encoding now = %d", ie if(dk3app_get_temp_file_name(app, tfn, DK3_SIZEOF(tfn,dkChar))) { fipo = dk3sf_fopen_app(tfn, dk3app_no_loc[53], app); if(fipo) { #if DK3_ON_WINDOWS oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif while((sz = dk3sf_fread_app(b, 1, sizeof(b), stdin, app)) > 0) { dk3sf_fwrite_app(b, 1, sz, fipo, app); } fclose(fipo); #if DK3_ON_WINDOWS _setmode(_fileno(stdin), oldmode); #endif back = dk3stream_process_filename_chars_app(obj, hf, tfn, ie, app); dk3sf_remove_file_app(tfn, app); } else { must_run_directly = 1; } } else { must_run_directly = 1; } if(must_run_directly) { #if DK3_ON_WINDOWS oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif back = dk3stream_process_file_chars_app(obj, hf, stdin, NULL, ie, app); #if DK3_ON_WINDOWS _setmode(_fileno(stdin), oldmode); #endif } } $? "- dk3app_process_stdin_chars %d", back return back; } #if !DK3_ON_WINDOWS #if DK3_HAVE_SETUID && DK3_HAVE_SETGID && DK3_HAVE_CHOWN #if DK3_CHAR_SIZE == 1 /** Change owner for one file if the file exists. @param app Application structure. @param ul1 File name. @param ul2 File name suffix. @param uid New user ID for file ownership. @param gid New group ID for file ownership. @return 1 on success (owner modified or file does not exist). */ static int dk3app_change_owner_for_file( dk3_app_t *app, unsigned long ul1, unsigned ul2, uid_t uid, gid_t gid ) { dkChar fnb[DK3_MAX_PATH]; /* Full name buffer. */ dkChar smb[32]; /* Small buffer. */ char tmb[32]; dk3_stat_t stb; int back = 1; $? "+ dk3app_change_owner_for_file %08lx.%03x %u %u", ul1, ul2, (unsigned)uid, (unsigned)gid sprintf(tmb, "/%08lx.%03x", ul1, ul2); if(dk3str_c8_to_str_simple_app(smb,DK3_SIZEOF(smb,dkChar),tmb,app)) { if(dk3str_len(app->n_tmpdir) < DK3_SIZEOF(fnb,dkChar)) { $? ". length" dk3str_cpy_not_overlapped(fnb, app->n_tmpdir); if((dk3str_len(fnb) + dk3str_len(smb)) < DK3_SIZEOF(fnb,dkChar)) { dk3str_cat(fnb, smb); dk3str_correct_filename(fnb); if(dk3sf_stat_app(&stb, fnb, NULL)) { $? ". file" if(0 != chown(fnb, uid, gid)) { $? "! chown" back = 0; } else { $? ". chown" } } else { $? ". no file" /* If there is no such file, there is no need to change owner. */ } } else { $? "! length" back = 0; } } else { $? "! length" back = 0; } } else { $? "! fn conv" } $? "- dk3app_change_owner_for_file %d", back return back; } int dk3app_change_user(dk3_app_t *app, uid_t uid, gid_t gid) { FILE *fipo; unsigned long ul1; unsigned ul2; int back = 1; $? "+ dk3app_change_user" if((app) && ((uid) || (gid))) { $? ". args ok" if(app->n_logfilename) { $? ". have logfile" fipo = dk3sf_fopen_app(app->n_logfilename, dkT("a"), app); if(fipo) { fclose(fipo); } if(0 != chown(app->n_logfilename, uid, gid)) { $? ". ownership changed" back = 0; } else { $? "! log owner change %d", errno } } else { $? "! no logfile" } if(app->n_tmpdir) { $? ". have tmpdir" if(0 != chown(app->n_tmpdir, uid, gid)) { back = 0; } if(app->i_tmpcarry) { $? "! tmpdir overflow" for(ul1 = 0UL; ul1 < 0xFFFFFFFFUL; ul1++) { for(ul2 = 0U; ul2 < 0x00001000U; ul2++) { if(!dk3app_change_owner_for_file(app, ul1, ul2, uid, gid)) { back = 0; $? "! tmp owner change" } } } for(ul2 = 0U; ul2 < 0x00001000U; ul2++) { if(!dk3app_change_owner_for_file(app, 0xFFFFFFFFUL, ul2, uid, gid)) { back = 0; $? "! tmp owner change" } } } else { for(ul1 = 0UL; ul1 < app->ul_tmpname; ul1++) { for(ul2 = 0U; ul2 < 0x00001000U; ul2++) { if(!dk3app_change_owner_for_file(app, ul1, ul2, uid, gid)) { back = 0; $? "! tmp owner change" } } } for(ul2 = 0U; ul2 < app->u_tmpsuffix; ul2++) { if(!dk3app_change_owner_for_file(app,app->ul_tmpname,ul2,uid,gid)) { back = 0; $? "! tmp owner change" } } } } else { $? "! no tmpdir" } } else { $? "! args" } $? "- dk3app_change_user %d", back return back; } #endif #endif #endif int dk3app_get_dir_from_pref( dk3_app_t *app, dkChar const *pn, dkChar *buf, size_t bs, int ch ) { int back = 0; if((app) && (pn) && (buf) && (bs)) { if(dk3app_get_pref(app, pn, buf, bs)) { if(ch) { if(dk3sf_is_dir_app(buf, NULL)) { back = 1; } else { /* ERROR: Directory does not exist! */ dk3app_log_i3(app, DK3_LL_ERROR, 369, 370, pn); } } else { back = 1; } } } return back; } /* vim: set ai sw=2 : */