%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% header #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif #if DK3_ON_WINDOWS /** Retrieve information about a file. @param st File information buffer. @param fn File name. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_c16_stat_app(dk3_stat_t *st, dk3_c16_t const *fn, dk3_app_t *app); /** Open a file. @param fn File name. @param mo Mode. @param app Application structure, used for diagnostics. @return FILE pointer on success, NULL on error. */ FILE * dk3sf_c16_fopen_app(dk3_c16_t const *fn, dk3_c16_t const *mo, dk3_app_t *app); /** Convert timestamp to text. @param dest Destination buffer. @param sz Size of \a dest (number of characters). @param timer Timestamp to convert. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_c16_time_convert_app( dk3_c16_t *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ); /** Get current working directory. @param dest Destination buffer. @param sz Size of \a dest. The size must not exceed INT_MAX/2. Practically this is not a limitation as the useful buffer size is DK3_MAX_PATH elements. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_c16_getcwd_app(dk3_c16_t *dest, size_t sz, dk3_app_t *app); /** Find executable file. @param d Destination buffer. @param s Size of \a d (number of characters). The size must not exceed 2^31-1. Practically this is not a limitation as the useful buffer size is DK3_MAX_PATH elements. @param w Current working directory. @param c Command as typed in the command line. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_find_exec_app( dk3_c16_t *d, size_t s, dk3_c16_t const *w, dk3_c16_t const *c, dk3_app_t *app ); /** Find users home directory. @param d Destination buffer. @param s Size of \a d (number of characters). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_get_home_app(dk3_c16_t *d, size_t s, dk3_app_t *app); /** Remove (unlink) path. @param n Path name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_remove_file_app(dk3_c16_t const *n, dk3_app_t *app); /** Remove directory. @param n Directory name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_remove_dir_app(dk3_c16_t const *n, dk3_app_t *app); /** Retrieve host name (short name, without DNS domain). @param db Destination buffer. @param sz Size of \a db (number of characters). The size must not exceed INT_MAX. Practically this is not a limitation as I have never seen host names longer than 80 characters. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_get_hostname_app(dk3_c16_t *db, size_t sz, dk3_app_t *app); /** Get login name. @param d Destination buffer. @param s Size of \a d (number of characters). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_get_logname_app(dk3_c16_t *d, size_t s, dk3_app_t *app); /** Create directory if it does not yet exist. @param p Path name. @param mo Creation mode. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c16_mkdir_app(dk3_c16_t const *p, int mo, dk3_app_t *app);; /** Get environment variable. @param name Environment variable name. @return Value on success, NULL on error. */ dk3_c16_t * dk3sf_c16_getenv(dk3_c16_t const *name); #else #endif /** Retrieve information about a file. @param st File information buffer. @param fn File name. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_c8_stat_app(dk3_stat_t *st, char const *fn, dk3_app_t *app); /** Open a file. @param fn File name. @param mo Mode. @param app Application structure, used for diagnostics. @return FILE pointer on success, NULL on error. */ FILE * dk3sf_c8_fopen_app(char const *fn, char const *mo, dk3_app_t *app); /** Convert timestamp to text. @param dest Destination buffer. @param sz Size of \a dest (number of characters). @param timer Timestamp to convert. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_c8_time_convert_app( char *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ); /** Get current working directory. @param dest Destination buffer. @param sz Size of \a dest. On some platforms the size is converted to int, so it should not exceed 32767. Practically this is not a limitation as the userful buffer size is DK3_MAX_PATH. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_c8_getcwd_app(char *dest, size_t sz, dk3_app_t *app); /** Read input line. @param db Destination buffer. @param sz Size of \a db (number of characters). @param fi Input file. @return 1 on success, 0 on error. */ int dk3sf_fgets(dkChar *db, size_t sz, FILE *fi); /** Read input line. @param db Destination buffer. @param sz Size of \a db (number of characters). The size must not exceed 32767 as it is converted to int on some systems. @param fi Input file. @param fn Input file name, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_fgets_fn_app( dkChar *db, size_t sz, FILE *fi, dkChar const *fn, dk3_app_t *app ); /** Write string to file. @param st String to write. @param fi File to write to. @return 1 on success, 0 on error. */ int dk3sf_fputs(dkChar const *st, FILE *fi); /** Write string to file, report errors if any. @param st String to write. @param fi Output file to write to. @param fn File name for error messages, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_fputs_fn_app(dkChar const *st,FILE *fi,dkChar const *fn,dk3_app_t *app); /** Write array of line strings to file. @param txt Pointer to array of lines. @param fi Output file to write to. @return 1 on success, 0 on error. */ int dk3sf_fputt(dkChar const * const *txt, FILE *fi); /** Write one character to file. @param ch Character to write. @param fi File to write to. @return 1 on success, 0 on error. */ int dk3sf_fputc(dkChar ch, FILE *fi); /** Write one character to file. @param ch Character to write. @param fi File to write to. @param fn File name of output file. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_fputc_fn_app(dkChar ch, FILE *fi, dkChar const *fn, dk3_app_t *app); /** Write byte order marker 0xFEFF to standard output. */ void dk3sf_initialize_stdout(void); /** Only set stdout mode, do not write byte order marker 0xFEFF to standard output. */ void dk3sf_initialize_stdout_no_bom(void); /** Write byte order marker 0xFEFF to standard error output. */ void dk3sf_initialize_stderr(void); /** Write byte order marker 0xFEFF to file. @param fipo File to set up. */ void dk3sf_initialize_file(FILE *fipo); /** Prepare standard output and standard error output for multibyte characters (write byte order marker 0xFEFF). */ void dk3sf_initialize_output(void); /** Get current timestamp. @param timer Pointer to result variable. @return 1 on success, 0 on error. */ int dk3sf_time(dk3_time_t *timer); /** Find executable file. @param d Destination buffer. @param s Size of \a d (number of characters). The size should not exceed 2^32-1 as it is converted to a DWORD. Practically this is not a restriction as DK3_MAX_PATH is the useful buffer size. @param w Current working directory. @param c Command as typed in the command line. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c8_find_exec_app( char *d, size_t s, char const *w, char const *c, dk3_app_t *app ); /** Find users home directory. @param d Destination buffer. @param s Size of \a d (number of characters). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c8_get_home_app(char *d, size_t s, dk3_app_t *app); /** Get current users login name. @param d Destination buffer. @param s Size of \a d (number of characters). @param app Application structure for diagnostics, may be NULL. */ int dk3sf_c8_get_logname_app(char *d, size_t s, dk3_app_t *app); /** Create directory if it does not yet exist. @param p Path name. @param mo Creation mode. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c8_mkdir_app(char const *p, int mo, dk3_app_t *app); /** Remove (unlink) path. @param n Path name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c8_remove_file_app(char const *n, dk3_app_t *app); /** Remove directory. @param n Directory name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c8_remove_dir_app(char const *n, dk3_app_t *app); /** Get current process ID. @return Process ID. */ dk3_um_t dk3sf_getpid(void); /** Check whether we must expand a file name. @param fn File name to check. @return 1 for "must expand", 0 for "no need to expand". */ int dk3sf_must_expand(dkChar const *fn); /** Retrieve host name (short name). @param db Destination buffer. @param sz Size of \a db (number of characters). The size must not exceed 2^32-1. Practically this is not a limitation as the useful buffer size for host name is below 256. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_c8_get_hostname_app(char *db, size_t sz, dk3_app_t *app); /** Print 8-bit character to file, convert to 16 bit if necessary. @param c Character to print. @param f File to write to. @return 1 on success, 0 on error. */ int dk3sf_c8_fputc(char c, FILE *f); /** Print 8-bit character string to file, convert to 16 bit if necessary. @param s String to print. @param f File to write to. @return 1 on success, 0 on error. */ int dk3sf_c8_fputs(char const *s, FILE *f); /** Read bytes from file descriptor into buffer. @param fd File descriptor. @param buf Buffer. @param s Size of \a buf. The size must not exceed 65535 as it is converted to unsigned int on some systems. @param app Application structure for diagnostics, may be NULL. @return Number of bytes read. */ size_t dk3sf_read_app(int fd, void *buf, size_t s, dk3_app_t *app); /** Write bytes to file descriptor. @param fd File descriptor. @param buf Buffer to write. @param s Size of \a buf in bytes. The size must not exceed 65535 as it is converted to unsigned int on some systems. @param app Application structure for diagnostics, may be NULL. @return 1 for success (all bytes written), 0 on error. */ int dk3sf_write_app(int fd, char const *buf, size_t s, dk3_app_t *app); /** Read from file. @param db Destination buffer. @param sz Size of one element. @param ne Number of elements. @param fi File to read from. @param app Application structure for diagnostics, may be NULL. @return Number of elements read. */ size_t dk3sf_fread_app(void *db, size_t sz, size_t ne, FILE *fi, dk3_app_t *app); /** Write to file. @param sb Source buffer. @param sz Size of one element. @param ne Number of elements. @param fi File to write to. @param app Application structure for diagnostics, may be NULL. @return 1 on success (all elements written), 0 on error. */ int dk3sf_fwrite_app(void const *sb,size_t sz,size_t ne,FILE *fi,dk3_app_t *app); /** Inspect file, search for byte order marker. The function inspects the first 4 bytes from file and attempts to find the file encoding (DK3_FILE_ENCODING_xxx). If there is no BOM at the beginning of the file the default value \a dv is returned. A value for \a dv can be obtained from dk3app_get_output_encoding() or by inspecting the DK3_CHAR_SIZE value and the language setting (ending on "UTF-8" or "utf8"?). @param fn File name. @param dv Default value for file encoding. @param app Application structure for diagnostics, may be NULL. @return File encoding if BOM found, default value \a dv otherwise. */ int dk3sf_inspect_bom_app(dkChar const *fn, int dv, dk3_app_t *app); /** Inspect file, search for byte order marker. If byte order marker is found save number of bytes to skip at beginning of file to variable. The function inspects the first 4 bytes from file and attempts to find the file encoding (DK3_FILE_ENCODING_xxx). If there is no BOM at the beginning of the file the default value \a dv is returned. A value for \a dv can be obtained from dk3app_get_output_encoding() or by inspecting the DK3_CHAR_SIZE value and the language setting (ending on "UTF-8" or "utf8"?). @param fn File name. @param dv Default value for file encoding. @param skb Pointer to size_t variable for number of bytes to skip at the beginning of the file. @param app Application structure for diagnostics, may be NULL. @return File encoding if BOM found, default value \a dv otherwise. */ int dk3sf_inspect_bom_skip_app( dkChar const *fn, int dv, size_t *skb, dk3_app_t *app ); /** Attempt to apply an encoding found from BOM to an input FILE. This function has an effect on Windows systems only. For \a enc we can handle DK3_FILE_ENCODING_ASCII (mapped to _O_TEXT), DK3_FILE_ENCODING_UTF8 (mapped to _O_U8TEXT) and DK3_FILE_ENCODING_UTF16_LSB (mapped to _O_U16TEXT). @param fipo File pointer. @param enc Encoding found from dk3sf_inspect_bom_app(). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_apply_bom_to_file_app(FILE *fipo, int enc, dk3_app_t *app); /** Get environment variable. @param name Environment variable name. @return Value on success, NULL on error. */ char * dk3sf_c8_getenv(char const *name); /** Check whether or not the given file name is a directory. @param n File name. @param app Application structure for diagnostics, may be NULL. @return 1 on success (is directory), 0 on error. */ int dk3sf_is_dir_app(dkChar const *n, dk3_app_t *app); /** Change into directory. * @param dn Directory name. * @param app Application structure for diagnostics, may be NULL. * @return 1 on success, 0 on error. */ int dk3sf_chdir_app(dkChar const *dn, dk3_app_t *app); /** Check whether we need to re-build a destination file from a source. * @param dn Destination file name. * @param sn Source file name. * @return 1 for rebuild necessary, 0 for not necessary. */ int dk3sf_must_rebuild(dkChar const *dn, dkChar const *sn); /** Create 8-bit file name from dkChar file name. @param fnb File name buffer for result. @param szfnb Size of @a fnb (number of bytes). @param src Source file name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_filename_to_c8( char *fnb, size_t szfnb, dkChar const *src, dk3_app_t *app ); /** Retrieve a double value in POSIX notation from a string. The sscanf() function depends on the current locale setting. This function retrieves and saves the current locale setting, establishes C locale temporarily for the the sscanf() call and restores the original setting before exiting. @param txt Text to inspect. @param v Pointer to result variable. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_scan_double_app(dkChar const *txt, double *v, dk3_app_t *app); /** Convert timestamp to human readable date and time. @param dest Destination structure. @param timer Source timestamp. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_localtime_app(dk3_tm_t *dest, dk3_time_t *timer, dk3_app_t *app); /** Retrieve maximum number of open files. @return Maximum number of open files. */ int dk3sf_get_max_files(void); /** Report error detailes. @param app Application structure for diagnostics. @param err Error code from errno. @param fctn Function name. */ void dk3sf_report_errno(dk3_app_t *app, int err, dkChar const *fctn); /** Close a file. @param fipo FILE to close. @param fn File name, may be NULL. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_fclose_fn_app(FILE *fipo, dkChar const *fn, dk3_app_t *app); /** Close a file. @param fipo FILE to close. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_fclose_app(FILE *fipo, dk3_app_t *app); /** Retrieve information about a file. @param st File information buffer. @param fn File name. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_stat_app(dk3_stat_t *st, dkChar const *fn, dk3_app_t *app); /** Open a file. @param fn File name. @param mo Mode. @param app Application structure, used for diagnostics. @return FILE pointer on success, NULL on error. */ FILE * dk3sf_fopen_app(dkChar const *fn, dkChar const *mo, dk3_app_t *app); /** Convert timestamp to text. @param dest Destination buffer. @param sz Size of \a dest (number of dkChar). @param timer Timestamp to convert. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_time_convert_app( dkChar *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ); /** Get current working directory. @param dest Destination buffer. @param sz Size of \a dest (number of dkChar). The size must not exceed INT_MAX/2. Practically this is not a limitation as the useful buffer size is DK3_MAX_PATH elements. @param app Application structure, used for diagnostics. @return 1 on success, 0 on error. */ int dk3sf_getcwd_app(dkChar *dest, size_t sz, dk3_app_t *app); /** Find executable file. @param d Destination buffer. @param s Size of \a d (number of dkChar). The size must not exceed 2^31-1. Practically this is not a limitation as the useful buffer size is DK3_MAX_PATH elements. @param w Current working directory. @param c Command as typed in the command line. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_find_exec_app( dkChar *d, size_t s, dkChar const *w, dkChar const *c, dk3_app_t *app ); /** Get login name. @param d Destination buffer. @param s Size of \a d (number of dkChar). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_get_logname_app(dkChar *d, size_t s, dk3_app_t *app); /** Find users home directory. @param d Destination buffer. @param s Size of \a d (number of dkChar). @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_get_home_app(dkChar *d, size_t s, dk3_app_t *app); /** Create directory if it does not yet exist. @param p Path name. @param mo Creation mode. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_mkdir_app(dkChar const *p, int mo, dk3_app_t *app); /** Remove (unlink) path. @param n Path name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_remove_file_app(dkChar const *n, dk3_app_t *app); /** Remove directory. @param n Directory name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_remove_dir_app(dkChar const *n, dk3_app_t *app); /** Retrieve host name (short name, without DNS domain). @param db Destination buffer. @param sz Size of \a db (number of dkChar). The size must not exceed 2^31-1. Practically this is not a limitation as I have never seen host names longer than 80 characters. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk3sf_get_hostname_app(dkChar *db, size_t sz, dk3_app_t *app); /** Get environment variable. @param name Environment variable name. @return Value on success, NULL on error. */ dkChar * dk3sf_getenv(dkChar const *name); #ifdef __cplusplus } #endif #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "No functions to support large characters!" #else #if DK3_ON_WINDOWS /** Macro to choose correct character size for sscanf()/swscanf(). */ #define dk3sf_sscanf3(s,f,d) swscanf(s,f,d) /** Macro to choose correct character size for sprintf()/swprintf(). NOTE: The first argument must be a *buffer*, *not* a pointer. */ #define dk3sf_sprintf3(s,f,d) swprintf(s,(sizeof(s)/sizeof(wchar_t)),f,d) #else #error "16 bit characters are supported on Windows platforms only!" #endif #endif #else /** Macro to choose correct character size for sscanf(). */ #define dk3sf_sscanf3(s,f,d) sscanf(s,f,d) /** Macro to choose correct character size for sprintf(). NOTE: The first argument *must* be a buffer, *not* a pointer. */ #define dk3sf_sprintf3(s,f,d) sprintf(s,f,d) #endif %% module #include "dk3all.h" $(trace-include) #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH /** File path component separator. */ #define DK3_C8_SEP '\\' /** Not a file path component separator. */ #define DK3_C8_NOSEP '/' #else /** File path component separator. */ #define DK3_C8_SEP '/' /** Not a file path component separator. */ #define DK3_C8_NOSEP '\\' #endif /** Add bit to set after testing another bit. */ #define DK3SF_ADDIF(a,b) if(m & a) { back |= b; } /** Function names used in error messages. */ dkChar const * const dk3sf_function_names[] = { $!string-table macro=dkT # # 0 # # # 1 # fclose: # # 2 # rmdir: # # 3 # unlink: # # 4 # getpwuid: # # 5 # lstat64: # # 6 # stat64: # # 7 # stat: # # 8 # lstat: # # 9 # fopen: # # 10 # localtime_r: # # 11 # getcwd: # # 12 # mkdir: # # 13 # gethostname: # # 14 # read: # # 15 # _read: # # 16 # write: # # 17 # _write: # # 18 # fread: # # 19 # _fread: # # 20 # fwrite: # # 21 # _fwrite: # # 22 # chdir: # # 23 # fputs: # # 24 # fputc: # # 25 # fgets: $!end }; void dk3sf_report_errno(dk3_app_t *app, int err, dkChar const *fctn) { #if (DK3_CHAR_SIZE == 1) && DK3_HAVE_STRERROR && (!DK3_ON_WINDOWS) dkChar const *msgarray[2]; #if DK3_HAVE_GETENV && DK3_HAVE_SETLOCALE char const *oldlocale = NULL; char const *langptr = NULL; #endif if((app) && (fctn)) { msgarray[0] = fctn; errno = 0; #if DK3_HAVE_GETENV && DK3_HAVE_SETLOCALE langptr = getenv("LANG"); if(langptr) { oldlocale = setlocale(LC_MESSAGES, langptr); } #endif msgarray[1] = strerror(err); if(0 == errno) { dk3app_log_3(app, DK3_LL_ERROR, msgarray, 0, 1, dk3sf_function_names[0]); } #if DK3_HAVE_GETENV && DK3_HAVE_SETLOCALE if(langptr) { if(oldlocale) { setlocale(LC_MESSAGES, oldlocale); } } #endif } #endif } #if DK3_ON_WINDOWS /* +++ Windows +++ */ /** Unlocalized 8-bit character keywords used by module. */ static char const * const dk3sf_kw_win_c8[] = { /* 0 */ "HOMEDRIVE", /* 1 */ "HOMEPATH", /* 2 */ "USERPROFILE", /* 3 */ "LOCALAPPDATA", /* 4 */ "\\AppData\\Local", /* 5 */ "APPDATA", /* 6 */ "\\AppData\\Roaming", /* 7 */ "TEMP", /* 8 */ "TMP", /* 9 */ "\\AppData\\Local\\Temp", NULL }; /** Unlocalized 16-bit character keywords used by module. */ static wchar_t const * const dk3sf_kw_win_c16[] = { /* 0 */ L"HOMEDRIVE", /* 1 */ L"HOMEPATH", /* 2 */ L"USERPROFILE", /* 3 */ L"LOCALAPPDATA", /* 4 */ L"\\AppData\\Local", /* 5 */ L"APPDATA", /* 6 */ L"\\AppData\\Roaming", /* 7 */ L"TEMP", /* 8 */ L"TMP", /* 9 */ L"\\AppData\\Local\\Temp", NULL }; dk3_um_t dk3sf_getpid(void) { dk3_um_t back; back = (dk3_um_t)_getpid(); return back; } dk3_c16_t * dk3sf_c16_getenv(dk3_c16_t const *name) { dk3_c16_t *back = NULL; if(name) { back = _wgetenv(name); } return back; } dk3_c8_t * dk3sf_c8_getenv(char const *name) { char *back = NULL; if(name) { back = getenv(name); } return back; } int dk3sf_c16_remove_dir_app(dk3_c16_t const *n, dk3_app_t *app) { int back = 0; if(n) { if(_wrmdir(n) == 0) { back = 1; } else { if(app) { /* Failed to remove directory! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 69, 70, n); #else dk3app_log_i1(app, DK3_LL_ERROR, 68); #endif } } } return back; } int dk3sf_c8_remove_dir_app(char const *n, dk3_app_t *app) { int back = 0; if(n) { if(_rmdir(n) == 0) { back = 1; } else { if(app) { /* Failed to remove directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 69, 70, n); #else dk3app_log_i1(app, DK3_LL_ERROR, 68); #endif } } } return back; } int dk3sf_c16_remove_file_app(dk3_c16_t const *n, dk3_app_t *app) { int back = 0; if(n) { if(_wunlink(n) == 0) { back = 1; } else { if(app) { /* Failed to remove file! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 88, 89, n); #else dk3app_log_i1(app, DK3_LL_ERROR, 90); #endif } } } return back; } int dk3sf_c8_remove_file_app(char const *n, dk3_app_t *app) { int back = 0; if(n) { if(_unlink(n) == 0) { back = 1; } else { if(app) { /* ERROR: Failed to remove file! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 88, 89, n); #else dk3app_log_i1(app, DK3_LL_ERROR, 90); #endif } } } return back; } /** Attempt to retrieve home directory name. @param d Destination buffer. @param sz Size of \a d (number of characters). @param n1 Name of first environment variable to check. @param n2 Name of second environment variable to check. @param n3 Trailing string to remove if found. @return 1 on success, 0 on error. */ static int dk3sf_c8_attempt_home( char *d, size_t sz, char const *n1, char const *n2, char const *n3 ) { int back = 0; char *p1 = NULL; /* Value of first environment variable. */ char *p2 = NULL; /* Value of second environment variable. */ size_t s = 0; /* Buffer size needed. */ size_t s2 = 0; /* Size of trailing part to remove. */ p2 = NULL; $? "+ dk3sf_c8_attempt_home \"%s\" \"%s\" \"%s\"", TR_STR(n1), TR_STR(n2), TR_STR(n3) p1 = getenv(n1); if(p1) { if(n2) { p2 = getenv(n2); } if((p2) || (!(n2))) { s = dk3str_c8_len(p1); if(p2) { s += dk3str_c8_len(p2); } if(s < sz) { dk3str_c8_cpy_not_overlapped(d, p1); if(p2) { dk3str_c8_cat(d, p2); } if(n3) { s2 = dk3str_c8_len(n3); if(s2 < 2) { if(dk3str_c8_casecmp(&(d[s - s2]), n3) == 0) { d[s - s2] = '\0'; back = 1; } } } else { back = 1; } } } $!trace-code if(back) { $? ". home = \"%s\"", d $!trace-code } } $? "- dk3sf_c8_attempt_home %d", back return back; } int dk3sf_c8_get_home_app(char *d, size_t s, dk3_app_t *app) { int back = 0; if((d) && (s)) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[0], dk3sf_kw_win_c8[1], NULL); if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[2], NULL, NULL); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[3], NULL, dk3sf_kw_win_c8[4]); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[5], NULL, dk3sf_kw_win_c8[6]); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[7], NULL, dk3sf_kw_win_c8[9]); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[8], NULL, dk3sf_kw_win_c8[9]); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[3], NULL, NULL); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[5], NULL, NULL); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[7], NULL, NULL); } if(!back) { back = dk3sf_c8_attempt_home(d, s, dk3sf_kw_win_c8[8], NULL, NULL); } $!trace-code if(back) { $? ". home = \"%s\"", d $!trace-code } } return back; } /** Check long string pointer for NULL value. */ #define TR_LSTR(n) (n ? n : L"(NULL)") /** Attempt to retrieve home directory name. @param d Destination buffer. @param sz Size of \a d (number of characters). @param n1 Name of first environment variable to check. @param n2 Name of second environment variable to check. @param n3 Trailing string to remove if found. @return 1 on success, 0 on error. */ static int dk3sf_c16_attempt_home( dk3_c16_t *d, size_t sz, dk3_c16_t const *n1, dk3_c16_t const *n2, dk3_c16_t const *n3 ) { int back = 0; dk3_c16_t *p1 = NULL; /* Value of first environment variable. */ dk3_c16_t *p2 = NULL; /* Value of second environment variable. */ size_t s = 0; /* Buffer size needed. */ size_t s2 = 0; /* Size of trailing text to remove. */ p2 = NULL; $? "+ dk3sf_c8_attempt_home \"%ls\" \"%ls\" \"%ls\"", TR_LSTR(n1), TR_LSTR(n2), TR_LSTR(n3) p1 = _wgetenv(n1); if(p1) { if(n2) { p2 = _wgetenv(n2); } if((p2) || (!(n2))) { s = dk3str_c16_len(p1); if(p2) { s += dk3str_c16_len(p2); } if(s < sz) { dk3str_c16_cpy(d, p1); if(p2) { dk3str_c16_cat(d, p2); } if(n3) { s2 = dk3str_c16_len(n3); if(s2 < 2) { if(dk3str_c16_casecmp(&(d[s - s2]), n3) == 0) { d[s - s2] = 0x0000U; back = 1; } } } else { back = 1; } } } $!trace-code if(back) { $? ". home = \"%ls\"", d $!trace-code } } $? "- dk3sf_c8_attempt_home %d", back return back; } int dk3sf_c16_get_home_app(dk3_c16_t *d, size_t s, dk3_app_t *app) { int back = 0; if((d) && (s)) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[0], dk3sf_kw_win_c16[1], NULL); if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[2], NULL, NULL); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[3], NULL, dk3sf_kw_win_c16[4]); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[5], NULL, dk3sf_kw_win_c16[6]); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[7], NULL, dk3sf_kw_win_c16[9]); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[8], NULL, dk3sf_kw_win_c16[9]); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[3], NULL, NULL); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[5], NULL, NULL); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[7], NULL, NULL); } if(!back) { back = dk3sf_c16_attempt_home(d, s, dk3sf_kw_win_c16[8], NULL, NULL); } $!trace-code if(back) { $? ". home = \"%ls\"", d $!trace-code } } return back; } int dk3sf_c8_get_logname_app(char *d, size_t s, dk3_app_t *app) { int back = 0; DWORD sz = 0; /* Buffer size / Result length. */ sz = (DWORD)s; if((d) && (s)) { if(GetUserNameA(d, &sz)) { if(sz) { d[((size_t)sz < s) ? ((size_t)sz) : (s - 1)] = '\0'; back = 1; } } else { if(app) { /* Failed to find current user name */ dk3app_log_i1(app, DK3_LL_ERROR, 43); } } } return back; } int dk3sf_c16_get_logname_app(dk3_c16_t *d, size_t s, dk3_app_t *app) { int back = 0; DWORD sz = 0; /* Buffer size / result length. */ if((d) && (s)) { sz = (DWORD)s; if(GetUserNameW(d, &sz)) { if(sz) { d[((size_t)sz < s) ? ((size_t)sz) : (s - 1)] = 0U; back = 1; } } else { if(app) { /* Failed to find current user name */ dk3app_log_i1(app, DK3_LL_ERROR, 43); } } } return back; } int dk3sf_time(dk3_time_t *timer) { int back = 1; _time64(timer); return back; } static int dk3sf_convert_file_type(int m) { int back = 0; switch(m & _S_IFMT) { #ifdef _S_IFIFO case _S_IFIFO: back = DK3_FT_FIFO; break; #endif #ifdef _S_IFCHR case _S_IFCHR: back = DK3_FT_SPECIAL_CHAR; break; #endif #ifdef _S_IFDIR case _S_IFDIR: back = DK3_FT_DIRECTORY; break; #endif #ifdef _S_IFBLK case _S_IFBLK: back = DK3_FT_SPECIAL_BLOCK; break; #endif #ifdef _S_IFREG case _S_IFREG: back = DK3_FT_REGULAR; break; #endif } return back; } static int dk3sf_convert_file_permissions(int m) { int back = 0; DK3SF_ADDIF(_S_IREAD,DK3_FPERM_U_READ) DK3SF_ADDIF(_S_IWRITE,DK3_FPERM_U_WRITE) DK3SF_ADDIF(_S_IEXEC,DK3_FPERM_U_EXEC) return back; } /** Convert file permissions back from dktools to system values. @param m File permissions in dktools notation. @return File permissions in system notation. */ static int dk3sf_convert_back_file_permissions(int m) { int back = 0; DK3SF_ADDIF(DK3_FPERM_U_READ,S_IREAD) DK3SF_ADDIF(DK3_FPERM_U_WRITE,S_IWRITE) DK3SF_ADDIF(DK3_FPERM_U_EXEC,S_IEXEC) return back; } static void dk3sf_convert_filetime(dk3_time_t *pd, FILETIME *ps) { __int64 i1; __int64 i2; i1 = (__int64)(ps->dwHighDateTime); i2 = (__int64)(ps->dwLowDateTime); i1 = ((i1 << 32) & 0xFFFFFFFF00000000UL) | (i2 & 0x00000000FFFFFFFFUL); *pd = (dk3_time_t)i1; } int dk3sf_c8_stat_app(dk3_stat_t *st, char const *fn, dk3_app_t *app) { WIN32_FIND_DATAA wfd; DWORD dwFileAttributes; HANDLE hFFF; int ec = 0; int back = 0; struct __stat64 stb; /* Internal buffer for _stat64(). */ $? "+ dk3sf_c8_stat_app \"%s\"", fn if((st) && (fn)) { dk3mem_res((void *)st, sizeof(dk3_stat_t)); st->cReparse = 0x00; st->dwReparse = (DWORD)0; if(_stat64(fn, &stb) == 0) { back = 1; st->u = (dk3_um_t)(stb.st_uid); st->g = (dk3_um_t)(stb.st_gid); st->device = (dk3_um_t)(stb.st_dev); st->rdev = (dk3_um_t)(stb.st_rdev); st->inode = (dk3_um_t)(stb.st_ino); st->nlink = (dk3_um_t)(stb.st_nlink); st->cre = (dk3_time_t)(stb.st_ctime); st->mod = (dk3_time_t)(stb.st_mtime); st->acc = (dk3_time_t)(stb.st_atime); st->ft = dk3sf_convert_file_type(stb.st_mode); st->perm = dk3sf_convert_file_permissions(stb.st_mode); st->sz = (dk3_um_t)(stb.st_size); st->lsz = st->sz; st->ai = 0x00; dk3mem_cpy((void *)(&(st->lcre)), (void *)(&(st->cre)), sizeof(dk3_time_t)); dk3mem_cpy((void *)(&(st->lmod)), (void *)(&(st->mod)), sizeof(dk3_time_t)); dk3mem_cpy((void *)(&(st->lacc)), (void *)(&(st->acc)), sizeof(dk3_time_t)); st->lu = st->u; st->lg = st->g; st->ldevice = st->device; st->lrdev = st->rdev; st->linode = st->inode; st->lnlink = st->nlink; st->lft = st->ft; st->lperm = st->perm; st->lsz = st->sz; #if VERSION_BEFORE_2012_04_14 if(DK3_FT_DIRECTORY == st->ft) { WIN32_FIND_DATAA wfdFileDetails; HANDLE hFileSearch; $? ". check directory" hFileSearch = FindFirstFileA(fn, &wfdFileDetails); if(INVALID_HANDLE_VALUE != hFileSearch) { if(FILE_ATTRIBUTE_REPARSE_POINT & (wfdFileDetails.dwFileAttributes)) { if(IO_REPARSE_TAG_MOUNT_POINT == wfdFileDetails.dwReserved0) { /* ##### st->ft = DK3_FT_WINDOWS_MOUNT_POINT; */ } else { if(IO_REPARSE_TAG_SYMLINK == wfdFileDetails.dwReserved0) { /* Symbolic link */ st->lsz = dk3ma_um_add_ok( dk3ma_um_mul_ok( (dk3_um_t)(wfdFileDetails.nFileSizeHigh), dk3ma_um_add_ok( (dk3_um_t)(MAXDWORD), DK3_UM_1, &ec ), &ec ), (dk3_um_t)(wfdFileDetails.nFileSizeLow), &ec ); dk3sf_convert_filetime(&(st->lcre), &(wfdFileDetails.ftCreationTime)); dk3sf_convert_filetime(&(st->lmod), &(wfdFileDetails.ftLastWriteTime)); dk3sf_convert_filetime(&(st->lacc), &(wfdFileDetails.ftLastAccessTime)); st->ft |= DK3_FT_SYMLINK; } else { } } } FindClose(hFileSearch); } } #else dwFileAttributes = GetFileAttributesA(fn); if(INVALID_FILE_ATTRIBUTES != dwFileAttributes) { if(dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { st->cReparse = 'r'; hFFF = FindFirstFileA(fn, &wfd); if(INVALID_HANDLE_VALUE != hFFF) { if((wfd.dwFileAttributes) & FILE_ATTRIBUTE_REPARSE_POINT) { st->dwReparse = wfd.dwReserved0; switch(wfd.dwReserved0) { case IO_REPARSE_TAG_MOUNT_POINT: { st->cReparse = 'm'; } break; case IO_REPARSE_TAG_SYMLINK: { st->cReparse = 'l'; } break; } } FindClose(hFFF); } } } #endif } else { if(app) { /* stat() failed! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 61, 62, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 73); #endif } } } $? "- dk3sf_c8_stat_app %d", back return back; } /** Check whether opening a file is allowed. @param fn File name. @param want_to_write Flag: Write access is wanted. @param app Application structure for diagnostics, may be NULL. @return 1 for write allowed, 0 for write denied. */ static int dk3sf_c8_check_open_file(char const *fn, int want_to_write, dk3_app_t *app) { int back = 1; dk3_stat_t stb; /* Internal buffer for checks. */ if(dk3sf_c8_stat_app(&stb, fn, NULL)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { if(app) { back = 0; /* ERROR: Name refers a directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 74, 75, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 76); #endif } } if(want_to_write) { /* Place for additional checks to write files here. */ } } return back; } FILE * dk3sf_c8_fopen_app(char const *fn, char const *mo, dk3_app_t *app) { FILE *back = NULL; char const *moptr = NULL; /* Check mode string. */ int want_to_write = 0; /* Flag: Write access wanted. */ $? "+ dk3sf_c8_fopen_app \"%s\"", TR_STR(fn) if((fn) && (mo)) { moptr = mo; while(*moptr) { switch(*moptr) { case 'w': case 'a': case '+': { want_to_write = 1; } break; } moptr++; } if(dk3sf_c8_check_open_file(fn, want_to_write, app)) { back = fopen(fn, mo); if(!(back)) { if(app) { /* Failed to open file for writing! */ if(want_to_write) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 77, 78, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 79); #endif } else { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 143, 144, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 145); #endif } } } } } $? "- dk3sf_c8_fopen_app %s", TR_PTR(back) return back; } int dk3sf_localtime_app( dk3_tm_t *dest, dk3_time_t *timer, dk3_app_t *app ) { int back = 0; struct tm res; if((dest) && (timer)) { if(0 == _localtime64_s(&res, timer)) { back = 1; dest->Y = 1900 + res.tm_year; dest->M = 1 + res.tm_mon; dest->D = res.tm_mday; dest->h = res.tm_hour; dest->m = res.tm_min; dest->s = res.tm_sec; } else { if(app) { /* ERROR: _localtime64_s failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 268); } } } return back; } int dk3sf_c8_time_convert_app( char *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ) { int back = 0; char buffer[64]; /* Buffer for sprintf() result. */ struct tm res; /* Result from localtime(). */ if((dest) && (sz) && (timer)) { if(0 == _localtime64_s(&res, timer)) { sprintf( buffer, "%04d-%02d-%02d %02d:%02d:%02d", (1900 + res.tm_year), (1 + res.tm_mon), res.tm_mday, res.tm_hour, res.tm_min, res.tm_sec ); if(sz > dk3str_c8_len(buffer)) { dk3str_c8_cpy_not_overlapped(dest, buffer); back = 1; } else { if(app) { /* Buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { if(app) { /* _localtime64_s failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 80); } } } return back; } int dk3sf_c8_getcwd_app(char *dest, size_t sz, dk3_app_t *app) { int back = 0; if((dest) && (sz)) { if(_getcwd(dest, (int)sz)) { back = 1; } else { if(app) { switch(errno) { case ERANGE: { /* Buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } break; default: { dk3app_log_i1(app, DK3_LL_ERROR, 53); } break; } } } } return back; } int dk3sf_c8_find_exec_app( char *d, size_t s, char const *w, char const *c, dk3_app_t *app ) { int back = 0; if((d) && (s)) { if(GetModuleFileNameA(GetModuleHandle(NULL),d,(DWORD)s)) { back = 1; } else { if(app) { /* Failed to find name of executable! */ dk3app_log_i1(app, DK3_LL_ERROR, 40); } } } return back; } static int dk3sf_c8_is_drive(char const *p) { int back = 0; $? "+ dk3sf_c8_is_drive \"%s\"", TR_STR(p) if(dk3str_c8_len(p) == 2) { if((*p >= 'a') && (*p <= 'z')) { back = 1; } if((*p >= 'A') && (*p <= 'Z')) { back = 1; } if(back) { back = 0; if(p[1] == ':') { back = 1; } } } $? "- dk3sf_c8_is_drive %d", back return back; } int dk3sf_c8_mkdir_app(char const *p, int mo, dk3_app_t *app) { int back = 0; char buffer[DK3_MAX_PATH]; /* Path name for parent directories. */ char *ptr = NULL; /* Slash/backslash position. */ int cc = 1; /* Flag: Can continue. */ int m = 0; /* File permissions. */ dk3_stat_t stb; $? "+ dk3sf_c8_mkdir_app \"%s\"", TR_STR(p) if(p) { m = dk3sf_convert_back_file_permissions(mo); if(dk3str_c8_len(p) < sizeof(buffer)) { $? ". length ok" dk3str_c8_cpy_not_overlapped(buffer, p); ptr = buffer; cc = 1; while((cc) && (ptr)) { $? ". loop ptr=\"%s\"", TR_STR(ptr) ptr = dk3str_c8_chr(ptr, '\\'); if(ptr) { *ptr = '\0'; $? ". directory=\"%s\"", buffer if((dk3str_c8_len(buffer) > 0) && (!dk3sf_c8_is_drive(buffer))) { if(dk3sf_c8_stat_app(&stb, buffer, NULL)) { $? ". path exists" if(((stb.ft) & (~(DK3_FT_SYMLINK))) != DK3_FT_DIRECTORY) { cc = 0; $? ". path \"%s\" no directory", buffer if(app) { /* Not a directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 81, 82, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 83); #endif } } } else { $? ". must create directory \"%s\"", buffer if(_mkdir(buffer) != 0) { $? "! failed to create \"%s\"", buffer cc = 0; if(app) { /* Failed to create directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 84, 85, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 86); #endif } } } } *ptr = '\\'; ptr++; } } if(cc) { $? ". all parents ok" if(dk3sf_c8_stat_app(&stb, buffer, NULL)) { $? ". \"%s\" exists", buffer if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { back = 1; $? ". is directory" } else { $? ". \"%s\" is not a directory", buffer if(app) { /* Not a directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 81, 82, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 83); #endif } } } else { $? ". must create \"%s\"", buffer if(_mkdir(buffer) == 0) { back = 1; } else { $? "! failed to create \"%s\"", buffer #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 84, 85, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 86); #endif } } } } else { $? "! directory name too long" if(app) { /* Path too long! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, p); #else dk3app_log_i1(app, DK3_LL_ERROR, 87); #endif } } } $? "- dk3sf_c8_mkdir_app %d", back return back; } int dk3sf_c16_stat_app(dk3_stat_t *st, dk3_c16_t const *fn, dk3_app_t *app) { WIN32_FIND_DATAW wfd; DWORD dwFileAttributes; HANDLE hFFF; int ec = 0; int back = 0; struct __stat64 stb; /* Result from _wstat64(). */ $? "+ dk3sf_c16_stat_app \"%s\"", fn if((st) && (fn)) { dk3mem_res((void *)st, sizeof(dk3_stat_t)); st->cReparse = 0x00; st->dwReparse = (DWORD)0; if(_wstat64(fn, &stb) == 0) { back = 1; st->u = (dk3_um_t)(stb.st_uid); st->g = (dk3_um_t)(stb.st_gid); st->device = (dk3_um_t)(stb.st_dev); st->rdev = (dk3_um_t)(stb.st_rdev); st->inode = (dk3_um_t)(stb.st_ino); st->nlink = (dk3_um_t)(stb.st_nlink); st->cre = (dk3_time_t)(stb.st_ctime); st->mod = (dk3_time_t)(stb.st_mtime); st->acc = (dk3_time_t)(stb.st_atime); st->ft = dk3sf_convert_file_type(stb.st_mode); st->perm = dk3sf_convert_file_permissions(stb.st_mode); st->sz = (dk3_um_t)(stb.st_size); st->lsz = st->sz; st->ai = 0x00; dk3mem_cpy((void *)(&(st->lcre)), (void *)(&(st->cre)), sizeof(dk3_time_t)); dk3mem_cpy((void *)(&(st->lmod)), (void *)(&(st->mod)), sizeof(dk3_time_t)); dk3mem_cpy((void *)(&(st->lacc)), (void *)(&(st->acc)), sizeof(dk3_time_t)); st->lu = st->u; st->lg = st->g; st->ldevice = st->device; st->lrdev = st->rdev; st->linode = st->inode; st->lnlink = st->nlink; st->lft = st->ft; st->lperm = st->perm; st->lsz = st->sz; #if VERSION_BEFORE_2012_04_14 if(DK3_FT_DIRECTORY == st->ft) { WIN32_FIND_DATAW wfdFileDetails; HANDLE hFileSearch; $? ". directory special check" hFileSearch = FindFirstFileW(fn, &wfdFileDetails); if(INVALID_HANDLE_VALUE != hFileSearch) { $? ". handle ok" if(FILE_ATTRIBUTE_REPARSE_POINT & (wfdFileDetails.dwFileAttributes)) { $? ". reparse point" if(IO_REPARSE_TAG_MOUNT_POINT == wfdFileDetails.dwReserved0) { $? ". mount point" /* ##### st->ft = DK3_FT_WINDOWS_MOUNT_POINT; */ } else { if(IO_REPARSE_TAG_SYMLINK == wfdFileDetails.dwReserved0) { $? ". symbolic link" /* Symbolic link */ st->lsz = dk3ma_um_add_ok( dk3ma_um_mul_ok( (dk3_um_t)(wfdFileDetails.nFileSizeHigh), dk3ma_um_add_ok( (dk3_um_t)(MAXDWORD), DK3_UM_1, &ec ), &ec ), (dk3_um_t)(wfdFileDetails.nFileSizeLow), &ec ); dk3sf_convert_filetime(&(st->lcre), &(wfdFileDetails.ftCreationTime)); dk3sf_convert_filetime(&(st->lmod), &(wfdFileDetails.ftLastWriteTime)); dk3sf_convert_filetime(&(st->lacc), &(wfdFileDetails.ftLastAccessTime)); st->ft |= DK3_FT_SYMLINK; } else { } } } FindClose(hFileSearch); } } #else dwFileAttributes = GetFileAttributesW(fn); if(INVALID_FILE_ATTRIBUTES != dwFileAttributes) { if(dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { st->cReparse = 'r'; hFFF = FindFirstFileW(fn, &wfd); if(INVALID_HANDLE_VALUE != hFFF) { if((wfd.dwFileAttributes) & FILE_ATTRIBUTE_REPARSE_POINT) { st->dwReparse = wfd.dwReserved0; switch(wfd.dwReserved0) { case IO_REPARSE_TAG_MOUNT_POINT: { st->cReparse = 'm'; } break; case IO_REPARSE_TAG_SYMLINK: { st->cReparse = 'l'; } break; } } FindClose(hFFF); } } } #endif } else { if(app) { /* _wstat64() failed! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 61, 163, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 73); #endif } } } $? "- dk3sf_c16_stat_app %d", back return back; } static int dk3sf_c16_check_open_file(dk3_c16_t const *fn, int want_to_write, dk3_app_t *app) { int back = 1; dk3_stat_t stb; /* Check for existing file. */ if(dk3sf_c16_stat_app(&stb, fn, NULL)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { if(app) { back = 0; /* Name refers a directory! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 74, 75, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 76); #endif } } if(want_to_write) { /* Place for additional checks to write files here. */ } } return back; } FILE * dk3sf_c16_fopen_app(dk3_c16_t const *fn, dk3_c16_t const *mo, dk3_app_t *app) { FILE *back = NULL; dk3_c16_t const *moptr = NULL; /* Traverse mode string. */ int want_to_write = 0; /* Flag: Write access wanted. */ if((fn) && (mo)) { moptr = mo; while(*moptr) { switch(*moptr) { case L'w': case L'a': case L'+': { want_to_write = 1; } break; } moptr++; } if(dk3sf_c16_check_open_file(fn, want_to_write, app)) { back = _wfopen(fn, mo); if(!(back)) { if(app) { /* Failed to open file for writing! */ if(want_to_write) { #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 77, 78, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 79); #endif } else { #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 143, 144, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 145); #endif } } } } } return back; } int dk3sf_c16_time_convert_app( dk3_c16_t *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ) { int back = 0; char buffer[64]; if(dk3sf_c8_time_convert_app(buffer, sizeof(buffer), timer, app)) { back = dk3str_cnv_c8p_to_c16_app(dest, sz, buffer, app); } return back; } int dk3sf_c16_getcwd_app(dk3_c16_t *dest, size_t sz, dk3_app_t *app) { int back = 0; if((dest) && (sz)) { if(_wgetcwd(dest, (int)sz)) { back = 1; } else { if(app) { switch(errno) { #ifdef ERANGE case ERANGE: { /* Buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } break; #endif default: { /* Failed to find current working directory! */ dk3app_log_i1(app, DK3_LL_ERROR, 53); } break; } } } } return back; } int dk3sf_c16_find_exec_app( dk3_c16_t *d, size_t s, dk3_c16_t const *w, dk3_c16_t const *c, dk3_app_t *app ) { int back = 0; if((d) && (s)) { if(GetModuleFileNameW(GetModuleHandle(NULL),d,(DWORD)s)) { back = 1; } else { if(app) { /* Failed to find name of executable! */ dk3app_log_i1(app, DK3_LL_ERROR, 40); } } } return back; } static int dk3sf_c16_is_drive(dk3_c16_t const *p) { int back = 0; if(dk3str_c16_len(p) == 2) { if((*p >= L'A') && (*p <= L'Z')) { back = 1; } if((*p >= L'a') && (*p <= L'z')) { back = 1; } if(back) { back = 0; if(p[1] == L':') { back = 1; } } } return back; } int dk3sf_c16_mkdir_app(dk3_c16_t const *p, int mo, dk3_app_t *app) { int back = 0; dk3_c16_t buffer[DK3_MAX_PATH]; /* File names of parent directories. */ dk3_c16_t *ptr = NULL; /* Current slash/backslash position. */ int cc = 1; /* Flag: Can continue. */ int m = 0; /* Permissions. */ dk3_stat_t stb; /* Test whether file/dir exists. */ if(p) { m = dk3sf_convert_back_file_permissions(mo); if(dk3str_c16_len(p) < sizeof(buffer)) { dk3str_c16_cpy(buffer, p); ptr = buffer; cc = 1; while((cc) && (ptr)) { ptr = dk3str_c16_chr(ptr, 0x005CU); if(ptr) { *ptr = 0U; if((dk3str_c16_len(buffer) > 0) && (!dk3sf_c16_is_drive(buffer))) { if(dk3sf_c16_stat_app(&stb, buffer, NULL)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) != DK3_FT_DIRECTORY) { cc = 0; if(app) { /* Not a directory! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 81, 82, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 83); #endif } } } else { if(_wmkdir(buffer) != 0) { cc = 0; if(app) { /* Failed to create directory! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 84, 85, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 86); #endif } } } } *ptr = 0x005CU; ptr++; } } if(cc) { if(dk3sf_c16_stat_app(&stb, buffer, NULL)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { back = 1; } else { if(app) { /* Not a directory! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 81, 82, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 83); #endif } } } else { if(_wmkdir(buffer) == 0) { back = 1; } else { #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 84, 85, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 86); #endif } } } } else { if(app) { /* Path too long! */ #if DK3_CHAR_SIZE == 2 dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, p); #else dk3app_log_i1(app, DK3_LL_ERROR, 87); #endif } } } return back; } int dk3sf_c16_get_hostname_app(dk3_c16_t *db, size_t sz, dk3_app_t *app) { int back = 0; DWORD s = 0; /* Buffer size / result length. */ if((db) && (sz)) { s = (DWORD)sz; if(GetComputerNameExW(ComputerNameNetBIOS, db, &s)) { if((size_t)s < sz) { db[(size_t)s] = L'\0'; } else { db[sz - 1] = L'\0'; } back = 1; } else { if(app) { /* ERROR: Failed to find NetBIOS name! */ dk3app_log_i1(app, DK3_LL_ERROR, 131); } } } return back; } int dk3sf_c8_get_hostname_app(char *db, size_t sz, dk3_app_t *app) { int back = 0; DWORD s = 0; /* Buffer size / result length. */ if((db) && (sz)) { s = (DWORD)sz; if(GetComputerNameExA(ComputerNameNetBIOS, db, &s)) { if((size_t)s < sz) { db[(size_t)s] = '\0'; } else { db[sz - 1] = '\0'; } back = 1; } else { if(app) { /* ERROR: Failed to find NetBIOS name! */ dk3app_log_i1(app, DK3_LL_ERROR, 131); } } } return back; } #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "dkChar must be 8 or 16 bit!" #else /* +++ Windows, dkChar 16 bit +++ */ int dk3sf_fgets_fn_app( dkChar *db, size_t sz, FILE *fi, dkChar const *fn, dk3_app_t *app ) { int back = 0; $? "+ dk3sf_fgets" if((db) && (sz) && (fi)) { if(fgetws(db, (int)sz, fi)) { if(db[0] == DK3_CHAR_BOM) { $? ". BOM at start of line" dk3str_c16_cpy(db, &(db[1])); } back = 1; } else { if(!feof(fi)) { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 346, 347, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 345); } } } } } $? "- dk3sf_fgets %d", back return back; } int dk3sf_fputc_fn_app(dkChar ch, FILE *fi, dkChar const *fn, dk3_app_t *app) { int back = 0; if(fi) { if(fputwc(ch, fi) != WEOF) { back = 1; } else { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 343, 344, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 120); } } } } return back; } int dk3sf_fputs_fn_app(dkChar const *st,FILE *fi,dkChar const *fn,dk3_app_t *app) { int back = 0; if((st) && (fi)) { if(fputws(st, fi) != WEOF) { back = 1; } else { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 343, 344, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 120); } } } } return back; } void dk3sf_initialize_stdout(void) { static int not_bom_written_to_stdout = 1; if(not_bom_written_to_stdout) { not_bom_written_to_stdout = 0; (void)_setmode(_fileno(stdout), _O_U16TEXT); if(!_isatty(_fileno(stdout))) { fputwc(0xFEFF, stdout); } } } void dk3sf_initialize_stdout_no_bom(void) { static int not_bom_written_to_stdout = 1; if(not_bom_written_to_stdout) { not_bom_written_to_stdout = 0; (void)_setmode(_fileno(stdout), _O_U16TEXT); } } void dk3sf_initialize_stderr(void) { static int not_bom_written_to_stderr = 1; if(not_bom_written_to_stderr) { not_bom_written_to_stderr = 0; (void)_setmode(_fileno(stderr), _O_U16TEXT); if(!_isatty(_fileno(stderr))) { fputwc(0xFEFF, stderr); } } } void dk3sf_initialize_file(FILE *fipo) { (void)_setmode(_fileno(fipo), _O_U16TEXT); fputwc(0xFEFF, fipo); } /* --- Windows, dkChar 16 bit --- */ #endif #else /* +++ Windows, dkChar 8 bit +++ */ int dk3sf_fgets_fn_app( dkChar *db, size_t sz, FILE *fi, dkChar const *fn, dk3_app_t *app ) { int back = 0; if((db) && (sz) && (fi)) { if(fgets(db, sz, fi)) { back = 1; } else { if(!feof(fi)) { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 346, 347, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 345); } } } } } return back; } int dk3sf_fputs_fn_app(dkChar const *st,FILE *fi,dkChar const *fn,dk3_app_t *app) { int back = 0; if((st) && (fi)) { if(fputs(st, fi) != EOF) { back = 1; } else { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 343, 344, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 120); } } } } return back; } int dk3sf_fputc_fn_app(dkChar ch, FILE *fi, dkChar const *fn, dk3_app_t *app) { int back = 0; if(fi) { if(fputc(ch, fi) != EOF) { back = 1; } else { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 343, 344, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 120); } } } } return back; } void dk3sf_initialize_stdout(void) { } void dk3sf_initialize_stderr(void) { } void dk3sf_initialize_file(FILE *fipo) { } /* --- Windows, dkChar 8 bit --- */ #endif /* --- Windows --- */ #else /* +++ non-Windows +++ */ /** 8-bit character keywords for use on non-Windows systems. */ static char const * const kw_c8_no_win[] = { /* 0 */ "/", /* 1 */ "PATH", NULL }; dk3_um_t dk3sf_getpid(void) { dk3_um_t back = DK3_UM_0; #if DK3_HAVE_GETPID back = (dk3_um_t)getpid(); #else #if DK3_HAVE__GETPID back = (dk3_um_t)_getpid(); #else #error "No getpid() function!" #endif #endif return back; } dk3_c8_t * dk3sf_c8_getenv(char const *name) { char *back = NULL; if(name) { back = getenv(name); } return back; } int dk3sf_c8_remove_dir_app(char const *n, dk3_app_t *app) { int back = 0; if(n) { #if DK3_HAVE_RMDIR if(rmdir(n) == 0) { back = 1; } else { if(app) { /* Failed to remove directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 69, 70, n); #else dk3app_log_i1(app, DK3_LL_ERROR, 68); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[2]); } } #else #error "No rmdir() function!" #endif } return back; } int dk3sf_c8_remove_file_app(char const *n, dk3_app_t *app) { int back = 0; if(n) { #if DK3_HAVE_UNLINK if(unlink(n) == 0) { back = 1; } else { if(app) { /* ERROR: Failed to unlink file */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 88, 89, n); #else dk3app_log_i1(app, DK3_LL_ERROR, 90); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[3]); } } #else #error "No support for unlink" #endif } return back; } /** Copy logname of user record to buffer. @param d Destination buffer. @param s Size of \a d. @param p User record. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3sf_c8_copy_logname(char *d, size_t s, struct passwd *p, dk3_app_t *app) { int back = 0; $? "+ dk3sf_c8_copy_logname" if(p) { $? ". p ok" if(p->pw_name) { $? ". name ok" if(dk3str_c8_len(p->pw_name) < s) { $? ". name length ok" dk3str_c8_cpy_not_overlapped(d, p->pw_name); back = 1; } else { $? "! name too long" if(app) { /* Destination buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { if(app) { /* No name entry in record! */ dk3app_log_i1(app, DK3_LL_ERROR, 91); } } } $? "- dk3sf_c8_copy_logname %d", back return back; } int dk3sf_c8_get_logname_app(char *d, size_t s, dk3_app_t *app) { int back = 0; uid_t u = 0; /* Current user ID. */ struct passwd *p = NULL; /* Current user to process. */ char uidbuffer[128]; /* Text buffer to store UID. */ $? "+ dk3sf_c8_get_logname_app" if((d) && (s)) { u = getuid(); #if DK3_HAVE_GETPWUID p = getpwuid(u); $? ". getpwuid()" if(p) { $? ". entry found" back = dk3sf_c8_copy_logname(d, s, p, app); } else { $? "! entry not found" if(app) { /* No passwd record for UID! */ #if DK3_CHAR_SIZE == 1 dk3ma_um_to_c8_string(uidbuffer, sizeof(uidbuffer), (dk3_um_t)u); dk3app_log_i3(app, DK3_LL_ERROR, 92, 93, uidbuffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 94); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[4]); } } #else #if DK3_HAVE_SETPWENT setpwent(); #endif { int cc; int found; $? ". getpwent()" cc = 1; found = 0; while(cc) { p = getpwent(); if(p) { if(p->pw_uid == u) { cc = 0; found = 1; $? ". entry found" back = dk3sf_c8_copy_logname(d, s, p, app); } } else { cc = 0; } } if(!found) { $? "! entry not found" if(app) { /* No passwd record for UID! */ #if DK3_CHAR_SIZE == 1 dk3ma_um_to_c8_string(uidbuffer, sizeof(uidbuffer), (dk3_um_t)u); dk3app_log_i3(app, DK3_LL_ERROR, 92, 93, uidbuffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 94); #endif } } } #if DK3_HAVE_SETPWENT endpwent(); #endif #endif } $? "- dk3sf_c8_get_logname_app %d", back return back; } int dk3sf_c8_get_home_app(char *d, size_t s, dk3_app_t *app) { int back = 0; uid_t u = 0; /* Current user ID to process. */ struct passwd *p = NULL; /* Current user to process. */ char uidbuffer[128]; /* Text buffer to store UID. */ if((d) && (s)) { u = getuid(); #if DK3_HAVE_GETPWUID p = getpwuid(u); if(p) { if(p->pw_dir) { if(dk3str_c8_len(p->pw_dir) < s) { dk3str_c8_cpy_not_overlapped(d, p->pw_dir); back = 1; } else { if(app) { /* Destination buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { if(app) { /* Home directory entry empty! */ dk3app_log_i1(app, DK3_LL_ERROR, 95); } } } else { if(app) { /* No passwd record for uid! */ #if DK3_CHAR_SIZE == 1 dk3ma_um_to_c8_string(uidbuffer, sizeof(uidbuffer), (dk3_um_t)u); dk3app_log_i3(app, DK3_LL_ERROR, 92, 93, uidbuffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 94); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[4]); } } #else { int cc; int found; cc = 1; found = 0; #if DK3_HAVE_SETPWENT setpwent(); #endif while(cc) { p = getpwent(); if(p) { if(p->pw_uid == u) { cc = 0; found = 1; if(p->pw_dir) { if(dk3str_c8_len(p->pw_dir) < s) { dk3str_c8_cpy_not_overlapped(d, p->pw_dir); back = 1; } else { if(app) { /* Destination buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { if(app) { /* Home directory entry empty! */ dk3app_log_i1(app, DK3_LL_ERROR, 95); } } } } else { cc = 0; } } #if DK3_HAVE_SETPWENT endpwent(); #endif if(!found) { if(app) { /* No entry for uid! */ #if DK3_CHAR_SIZE == 1 dk3ma_um_to_c8_string(uidbuffer, sizeof(uidbuffer), (dk3_um_t)u); dk3app_log_i3(app, DK3_LL_ERROR, 92, 93, uidbuffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 94); #endif } } } #endif } return back; } int dk3sf_time(dk3_time_t *timer) { int back = 1; time(timer); return back; } /** Convert file type from system representation to DK3_FT_xxx. @param m File type as found by stat(). @return DK3_FT_xxx. */ static int dk3sf_convert_file_type(mode_t m) { int back = 0; switch(m & S_IFMT) { case S_IFIFO: back = DK3_FT_FIFO; break; case S_IFCHR: back = DK3_FT_SPECIAL_CHAR; break; case S_IFDIR: back = DK3_FT_DIRECTORY; break; case S_IFBLK: back = DK3_FT_SPECIAL_BLOCK; break; case S_IFREG: back = DK3_FT_REGULAR; break; case S_IFSOCK: back = DK3_FT_SOCKET; break; #ifdef S_IFMPC case S_IFMPC: back = DK3_FT_MUX_CHAR; break; #endif #ifdef S_IFNAM case S_IFNAM: back = DK3_FT_XENIX_SPECIAL; break; #endif #ifdef S_INSEM case S_INSEM: back = DK3_FT_XENIX_SEMAPHORE; break; #endif #ifdef S_INSHD case S_INSHD: back = DK3_FT_XENIX_SHARED_DATA; break; #endif #ifdef S_IFMPB case S_IFMPB: back = DK3_FT_MUX_BLOCK; break; #endif #ifdef S_IFCMP case S_IFCMP: back = DK3_FT_VXFS_COMPRESSED; break; #endif #ifdef S_IFNWK case S_IFNWK: back = DK3_FT_NETWORK_SPECIAL; break; #endif #ifdef S_IFSHAD case S_IFSHAD: back = DK3_FT_ACL_SHADOW; break; #endif #ifdef S_IFDOOR case S_IFDOOR: back = DK3_FT_DOOR; break; #endif #ifdef S_IFWHT case S_IFWHT: back = DK3_FT_WHITEOUT; break; #endif } return back; } /** Convert file permissions from system representation to DK3_PERM_xxx @param m File mode as obtained from stat(). @return DK3_PERM_xxx value or combination. */ static int dk3sf_convert_file_permissions(mode_t m) { int back = 0; DK3SF_ADDIF(S_IRUSR,DK3_FPERM_U_READ) DK3SF_ADDIF(S_IWUSR,DK3_FPERM_U_WRITE) DK3SF_ADDIF(S_IXUSR,DK3_FPERM_U_EXEC) DK3SF_ADDIF(S_IRGRP,DK3_FPERM_G_READ) DK3SF_ADDIF(S_IWGRP,DK3_FPERM_G_WRITE) DK3SF_ADDIF(S_IXGRP,DK3_FPERM_G_EXEC) DK3SF_ADDIF(S_IROTH,DK3_FPERM_O_READ) DK3SF_ADDIF(S_IWOTH,DK3_FPERM_O_WRITE) DK3SF_ADDIF(S_IXOTH,DK3_FPERM_O_EXEC) DK3SF_ADDIF(S_ISUID,DK3_FPERM_SUID) DK3SF_ADDIF(S_ISGID,DK3_FPERM_SGID) DK3SF_ADDIF(S_ISVTX,DK3_FPERM_VTX) return back; } /** Convert file permissions back from dktools to system values. @param m File permissions in dktools notation. @return File permissions in system notation. */ static mode_t dk3sf_convert_back_file_permissions(int m) { mode_t back = 0; DK3SF_ADDIF(DK3_FPERM_U_READ,S_IRUSR) DK3SF_ADDIF(DK3_FPERM_U_WRITE,S_IWUSR) DK3SF_ADDIF(DK3_FPERM_U_EXEC,S_IXUSR) DK3SF_ADDIF(DK3_FPERM_G_READ,S_IRGRP) DK3SF_ADDIF(DK3_FPERM_G_WRITE,S_IWGRP) DK3SF_ADDIF(DK3_FPERM_G_EXEC,S_IXGRP) DK3SF_ADDIF(DK3_FPERM_O_READ,S_IROTH) DK3SF_ADDIF(DK3_FPERM_O_WRITE,S_IWOTH) DK3SF_ADDIF(DK3_FPERM_O_EXEC,S_IXOTH) DK3SF_ADDIF(DK3_FPERM_SUID,S_ISUID) DK3SF_ADDIF(DK3_FPERM_SGID,S_ISGID) DK3SF_ADDIF(DK3_FPERM_VTX,S_ISVTX) return back; } int dk3sf_c8_stat_app(dk3_stat_t *st, char const *fn, dk3_app_t *app) { int back = 0; $? "+ dk3sf_c8_stat_app \"%s\"", fn if((st) && (fn)) { #if DK3_HAVE_LARGEFILE64_SOURCE && DK3_HAVE_STAT64 struct stat64 stb; /* Result from stat64(). */ #if DK3_HAVE_LSTAT64 struct stat64 lstb; /* Result from lstat64(). */ #endif $? ". use stat64() / lstat64()" if(stat64(fn, &stb) == 0) { $? ". stat64 ok" st->u = (dk3_um_t)(stb.st_uid); st->g = (dk3_um_t)(stb.st_gid); st->device = (dk3_um_t)(stb.st_dev); st->rdev = (dk3_um_t)(stb.st_rdev); st->inode = (dk3_um_t)(stb.st_ino); st->nlink = (dk3_um_t)(stb.st_nlink); st->cre = (dk3_time_t)(stb.st_ctime); st->mod = (dk3_time_t)(stb.st_mtime); st->acc = (dk3_time_t)(stb.st_atime); st->ft = dk3sf_convert_file_type(stb.st_mode); st->perm = dk3sf_convert_file_permissions(stb.st_mode); st->sz = (dk3_um_t)(stb.st_size); st->lsz = st->sz; st->ai = 0x00; #if DK3_HAVE_LSTAT64 if(lstat64(fn, &lstb) == 0) { back = 1; if(((lstb.st_mode) & S_IFMT) == S_IFLNK) { st->ft |= DK3_FT_SYMLINK; st->lu = (dk3_um_t)(lstb.st_uid); st->lg = (dk3_um_t)(lstb.st_gid); st->ldevice = (dk3_um_t)(lstb.st_dev); st->lrdev = (dk3_um_t)(lstb.st_rdev); st->linode = (dk3_um_t)(lstb.st_ino); st->lnlink = (dk3_um_t)(lstb.st_nlink); st->lcre = (dk3_time_t)(lstb.st_ctime); st->lmod = (dk3_time_t)(lstb.st_mtime); st->lacc = (dk3_time_t)(lstb.st_atime); st->lft = dk3sf_convert_file_type(lstb.st_mode); st->lperm = dk3sf_convert_file_permissions(lstb.st_mode); st->lsz = (dk3_um_t)(lstb.st_size); if(lstb.st_uid != stb.st_uid) { st->ai |= DK3_STAT_AI_USER_DIFFERS; } if(lstb.st_gid != stb.st_gid) { st->ai |= DK3_STAT_AI_GROUP_DIFFERS; } if(lstb.st_dev != stb.st_dev) { st->ai |= DK3_STAT_AI_FAR_LINK; } } $? ". ft = %d", st->ft } else { $? "! lstat64() failed" if(app) { /* lstat() failed! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 96, 97, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 98); #endif } } #else back = 1; #endif } else { $? "! stat64() failed for \"%s\"", fn #if DK3_HAVE_LSTAT64 if(lstat64(fn, &lstb) == 0) { back = 1; st->u = DK3_UM_0; st->g = DK3_UM_0; st->device = DK3_UM_0; st->rdev = DK3_UM_0; st->inode = DK3_UM_0; st->nlink = DK3_UM_0; st->cre = (dk3_time_t)0UL; st->mod = (dk3_time_t)0UL; st->acc = (dk3_time_t)0UL; st->ft = DK3_FT_SYMLINK | DK3_FT_BAD_SYMLINK; st->perm = 0; st->sz = DK3_UM_0; st->ai = 0x00; st->lu = (dk3_um_t)(lstb.st_uid); st->lg = (dk3_um_t)(lstb.st_gid); st->ldevice = (dk3_um_t)(lstb.st_dev); st->lrdev = (dk3_um_t)(lstb.st_rdev); st->linode = (dk3_um_t)(lstb.st_ino); st->lnlink = (dk3_um_t)(lstb.st_nlink); st->lcre = (dk3_time_t)(lstb.st_ctime); st->lmod = (dk3_time_t)(lstb.st_mtime); st->lacc = (dk3_time_t)(lstb.st_atime); st->lft = dk3sf_convert_file_type(lstb.st_mode); st->lperm = dk3sf_convert_file_permissions(lstb.st_mode); st->lsz = (dk3_um_t)(lstb.st_size); } else { if(app) { /* stat failed */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 61, 62, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 99); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[5]); } } #else if(app) { /* stat failed */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 61, 62, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 99); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[6]); } #endif } #else #if DK3_HAVE_STAT struct stat stb; #if DK3_HAVE_LSTAT struct stat lstb; #endif $? ". used stat() / lstat()" if(stat(fn, &stb) == 0) { $? ". stat() ok" st->u = (dk3_um_t)(stb.st_uid); st->g = (dk3_um_t)(stb.st_gid); st->device = (dk3_um_t)(stb.st_dev); st->rdev = (dk3_um_t)(stb.st_rdev); st->inode = (dk3_um_t)(stb.st_ino); st->nlink = (dk3_um_t)(stb.st_nlink); st->cre = (dk3_time_t)(stb.st_ctime); st->mod = (dk3_time_t)(stb.st_mtime); st->acc = (dk3_time_t)(stb.st_atime); st->ft = dk3sf_convert_file_type(stb.st_mode); st->perm = dk3sf_convert_file_permissions(stb.st_mode); st->sz = (dk3_um_t)(stb.st_size); sz->lsz = st->sz; st->ai = 0x00; #if DK3_HAVE_LSTAT if(lstat(fn, &lstb) == 0) { back = 1; if(((lstb.st_mode) & S_IFMT) == S_IFLNK) { st->ft |= DK3_FT_SYMLINK; st->lu = (dk3_um_t)(lstb.st_uid); st->lg = (dk3_um_t)(lstb.st_gid); st->ldevice = (dk3_um_t)(lstb.st_dev); st->lrdev = (dk3_um_t)(lstb.st_rdev); st->linode = (dk3_um_t)(lstb.st_ino); st->lnlink = (dk3_um_t)(lstb.st_nlink); st->lcre = (dk3_time_t)(lstb.st_ctime); st->lmod = (dk3_time_t)(lstb.st_mtime); st->lacc = (dk3_time_t)(lstb.st_atime); st->lft = dk3sf_convert_file_type(lstb.st_mode); st->lperm = dk3sf_convert_file_permissions(lstb.st_mode); sz->lsz = (dk3_um_t)(lstb.st_size); if(lstb.st_uid != stb.st_uid) { st->ai |= DK3_STAT_AI_USER_DIFFERS; } if(lstb.st_gid != stb.st_gid) { st->ai |= DK3_STAT_AI_GROUP_DIFFERS; } if(lstb.st_dev != stb.st_dev) { st->ai |= DK3_STAT_AI_FAR_LINK; } } $? ". ft = %d", st->ft } else { $? "! lstat() failed" if(app) { /* lstat() failed! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 96, 97, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 98); #endif } } #else back = 1; #endif } else { $? "! stat() failed" #if DK3_HAVE_LSTAT if(lstat(fn,&lstb) == 0) { back = 1; st->u = DK3_UM_0; st->g = DK3_UM_0; st->device = DK3_UM_0; st->rdev = DK3_UM_0; st->inode = DK3_UM_0; st->nlink = DK3_UM_0; st->cre = (dk3_time_t)0UL; st->mod = (dk3_time_t)0UL; st->acc = (dk3_time_t)0UL; st->ft = DK3_FT_SYMLINK | DK3_FT_BAD_SYMLINK; st->perm = 0; st->sz = DK3_UM_0; st->ai = 0x00; st->lu = (dk3_um_t)(lstb.st_uid); st->lg = (dk3_um_t)(lstb.st_gid); st->ldevice = (dk3_um_t)(lstb.st_dev); st->lrdev = (dk3_um_t)(lstb.st_rdev); st->linode = (dk3_um_t)(lstb.st_ino); st->lnlink = (dk3_um_t)(lstb.st_nlink); st->lcre = (dk3_time_t)(lstb.st_ctime); st->lmod = (dk3_time_t)(lstb.st_mtime); st->lacc = (dk3_time_t)(lstb.st_atime); st->lft = dk3sf_convert_file_type(lstb.st_mode); st->lperm = dk3sf_convert_file_permissions(lstb.st_mode); st->lsz = (dk3_um_t)(lstb.st_size); } else { if(app) { /* stat() failed! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 61, 62, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 99); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[8]); } } #else if(app) { /* stat() failed! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 61, 62, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 99); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[7]); } #endif } #else #error "Not stat() function available!" #endif #endif } $? "- dk3sf_c8_stat_app %d", back return back; } /** Check whether opening a file is allowed. @param fn File name. @param want_to_write Flag: Write access is wanted. @param app Application structure for diagnostics, may be NULL. @return 1 for write allowed, 0 for write denied. */ static int dk3sf_c8_check_open_file(char const *fn, int want_to_write, dk3_app_t *app) { int back = 1; dk3_stat_t stb; /* Check for existing file. */ if(dk3sf_c8_stat_app(&stb, fn, NULL)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { if(app) { back = 0; /* Name refers a directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 74, 75, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 76); #endif } } if(want_to_write) { if((stb.ft) & DK3_FT_SYMLINK) { if((stb.ai) & DK3_STAT_AI_USER_DIFFERS) { back = 0; /* Symlink owner is not file owner! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 100, 101, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 102); #endif } } } } return back; } FILE * dk3sf_c8_fopen_app(char const *fn, char const *mo, dk3_app_t *app) { FILE *back = NULL; char const *moptr = NULL; /* Traverse mode string. */ int want_to_write = 0; /* Flag: Write access wanted. */ $? "+ dk3sf_c8_fopen_app \"%s\" \"%s\"", TR_STR(fn), TR_STR(mo) if((fn) && (mo)) { moptr = mo; while(*moptr) { switch(*moptr) { case 'w': case 'a': case '+': { want_to_write = 1; } break; } moptr++; } if(dk3sf_c8_check_open_file(fn, want_to_write, app)) { #if DK3_HAVE_LARGEFILE64_SOURCE && DK3_HAVE_FOPEN64 back = fopen64(fn, mo); $? ". attempt fopen64" #else back = fopen(fn, mo); $? ". attempt fopen" #endif if(!(back)) { if(app) { /* Failed to open file for writing! */ if(want_to_write) { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 77, 78, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 79); #endif } else { #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 143, 144, fn); #else dk3app_log_i1(app, DK3_LL_ERROR, 145); #endif } dk3sf_report_errno(app, errno, dk3sf_function_names[9]); } } } } $? "- dk3sf_c8_fopen_app %s", TR_PTR(back) return back; } #if DK3_HAVE_LOCALTIME_R int dk3sf_localtime_app( dk3_tm_t *dest, dk3_time_t *timer, dk3_app_t *app ) { int back = 0; struct tm res, *rp; if((dest) && (timer)) { if((rp = localtime_r(timer, &res)) != NULL) { back = 1; dest->Y = 1900 + rp->tm_year; dest->M = 1 + rp->tm_mon; dest->D = rp->tm_mday; dest->h = rp->tm_hour; dest->m = rp->tm_min; dest->s = rp->tm_sec; } else { if(app) { /* ERROR: localtime_r failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 268); dk3sf_report_errno(app, errno, dk3sf_function_names[10]); } } } return back; } int dk3sf_c8_time_convert_app( dkChar *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ) { int back = 0; char buffer[64]; /* Buffer. */ struct tm res, *rp; /* Conversion result. */ if((dest) && (sz) && (timer)) { rp = localtime_r(timer, &res); if(rp) { sprintf( buffer, "%04d-%02d-%02d %02d:%02d:%02d", (1900 + rp->tm_year), (1 + rp->tm_mon), rp->tm_mday, rp->tm_hour, rp->tm_min, rp->tm_sec ); if(sz > dk3str_c8_len(buffer)) { dk3str_c8_cpy_not_overlapped(dest, buffer); back = 1; } else { if(app) { /* Buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { if(app) { /* localtime_r failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 80); dk3sf_report_errno(app, errno, dk3sf_function_names[10]); } } } return back; } #else #error "Function localtime_r() not available!" #endif #if DK3_HAVE_GETCWD || DK3_HAVE__GETCWD int dk3sf_c8_getcwd_app(char *dest, size_t sz, dk3_app_t *app) { int back = 0; if((dest) && (sz)) { #if DK3_HAVE_GETCWD if(getcwd(dest, sz)) #else if(_getcwd(dest, sz)) #endif { back = 1; } else { if(app) { switch(errno) { #ifdef ERANGE case ERANGE: { /* Buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } break; #endif default: { dk3app_log_i1(app, DK3_LL_ERROR, 53); dk3sf_report_errno(app, errno, dk3sf_function_names[11]); } break; } } } } return back; } #else #error "Neither getcwd() or _getcwd() available!" #endif /** Check whether or not a file is executable. @param f File name. @return 1 for exectuable, 0 for not executable. */ static int dk3sf_c8_check_exec(char const *f) { int back = 0; int testperm; /* Permissions of file. */ dk3_stat_t stb; /* stat() result to check for file. */ $? "+ dk3sf_c8_check_exec \"%s\"", f if(dk3sf_c8_stat_app(&stb, f, NULL)) { $? ". file name ok" if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_REGULAR) { $? ". type ok" testperm = (DK3_FPERM_U_EXEC | DK3_FPERM_G_EXEC | DK3_FPERM_O_EXEC); if((stb.perm) & testperm) { $? ". permissions ok" back = 1; } else { $? "! wrong permissions" } } else { $? "! wrong file type" } } else { $? "! file does not exist" } $? "- dk3sf_c8_check_exec %d", back return back; } int dk3sf_c8_find_exec_app( char *d, size_t s, char const *w, char const *c, dk3_app_t *app ) { int back = 0; int cc = 0; /* Flag: Can continue. */ char *pathcopy = NULL; /* Copy of parent directory. */ char *p = NULL; char *pn = NULL; size_t tsl = 0; /* Needed buffer length. */ $? "+ dk3sf_c8_find_exec_app" if((d) && (s) && (w) && (c)) { $? ". args ok" if(dk3str_c8_chr(c, DK3_C8_SEP)) { $? ". combine w and c" if(dk3str_c8_is_abs_path(c)) { $? ". c is absolute path" if(dk3str_c8_len(c) < s) { $? ". buffer length ok" dk3str_c8_cpy_not_overlapped(d, c); back = 1; $? ". result \"%s\"", d } else { $? "! buffer too short" if(app) { /* c too long! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 103, 104, c); #else dk3app_log_i1(app, DK3_LL_ERROR, 105); #endif } } } else { $? ". c is relative path" if(dk3str_c8_len(w) < s) { dk3str_c8_cpy_not_overlapped(d, w); back = dk3str_c8_append_path_app(d, s, c, app); if(back) { $? ". result \"%s\"", d } } else { $? "! buffer too short" if(app) { /* w too long! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, w); #else dk3app_log_i1(app, DK3_LL_ERROR, 87); #endif } } } } else { $? ". search PATH" p = getenv(kw_c8_no_win[1]); if(p) { $? ". PATH ok" pathcopy = dk3str_dup_app(p, app); if(pathcopy) { $? ". copy ok" p = pathcopy; cc = 1; while((p) && (cc) && (back == 0)) { pn = dk3str_c8_chr(p, ':'); if(pn) { *(pn++) = '\0'; } if(dk3str_c8_len(p)) { $? ". one directory" tsl = dk3str_c8_len(p); tsl += dk3str_c8_len(kw_c8_no_win[0]); tsl += dk3str_c8_len(c); if(tsl < s) { $? ". buffer length ok" dk3str_c8_cpy_not_overlapped(d, p); dk3str_c8_cat(d, kw_c8_no_win[0]); dk3str_c8_cat(d, c); back = dk3sf_c8_check_exec(d); } else { $? "! buffer too short" cc = 0; if(app) { /* Destination buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } else { $? ". current directory" tsl = dk3str_c8_len(w); tsl += dk3str_c8_len(kw_c8_no_win[0]); tsl += dk3str_c8_len(c); if(tsl < s) { $? ". buffer length ok" dk3str_c8_cpy_not_overlapped(d, w); dk3str_c8_cat(d, kw_c8_no_win[0]); dk3str_c8_cat(d, c); back = dk3sf_c8_check_exec(d); } else { $? "! buffer too short" cc = 0; if(app) { /* Destination buffer too small! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } } p = pn; } dk3_delete(pathcopy); } else { $? "! memory" } } else { $? "! No PATH" if(app) { /* PATH environment variable not defined. */ dk3app_log_i1(app, DK3_LL_ERROR, 106); } } } } $? "- dk3sf_c8_find_exec_app %d", back return back; } int dk3sf_c8_mkdir_app(char const *p, int mo, dk3_app_t *app) { int back = 0; char buffer[DK3_MAX_PATH]; /* File names of parent directories. */ char *ptr = NULL; /* Current path separator. */ int cc = 0; /* Flag: Can continue. */ mode_t m = 0; /* File creation mode. */ dk3_stat_t stb; /* Check for existance of file or directory. */ $? "+ dk3sf_c8_mkdir_app \"%s\"", TR_STR(p) if(p) { $? ". name ok" m = dk3sf_convert_back_file_permissions(mo); if(dk3str_c8_len(p) < sizeof(buffer)) { $? ". length ok" dk3str_c8_cpy_not_overlapped(buffer, p); ptr = buffer; cc = 1; while((cc) && (ptr)) { $? ". loop \"%s\"", ptr ptr = dk3str_c8_chr(ptr, DK3_C8_SEP); if(ptr) { *ptr = '\0'; $? ". directory \"%s\"", buffer if(dk3str_c8_len(buffer) > 0) { if(dk3sf_c8_stat_app(&stb, buffer, NULL)) { $? ". path exists" if(((stb.ft) & (~(DK3_FT_SYMLINK))) != DK3_FT_DIRECTORY) { cc = 0; $? "! path is not a directory" if(app) { /* Not a directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 81, 82, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 83); #endif } } } else { $? ". must create dir \"%s\"", buffer #if DK3_HAVE_MKDIR #if DK3_HAVE_MKDIR2 if(mkdir(buffer, m) == 0) #else if(mkdir(buffer) == 0) #endif { #if DK3_HAVE_CHMOD (void)chmod(buffer, m); $? ". mode %o", m #endif } else { cc = 0; $? "! failed to create directory" if(app) { /* Failed to create directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 84, 85, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 86); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[12]); } } #else cc = 0; if(app) { $? "! no mkdir) function" /* No mkdir() function available! */ dk3app_log_i1(app, DK3_LL_ERROR, 107); } #endif } } *ptr = DK3_C8_SEP; ptr++; } } if(cc) { $? ". all parents ok path now \"%s\"", buffer if(dk3sf_c8_stat_app(&stb, buffer, NULL)) { $? ". path exists" if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { back = 1; $? ". path is a directory" } else { $? "! path is not a directory" if(app) { /* Not a directory! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 81, 82, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 83); #endif } } } else { $? ". must create \"%s\"", buffer #if DK3_HAVE_MKDIR #if DK3_HAVE_MKDIR2 if(mkdir(buffer, m) == 0) #else if(mkdir(buffer) == 0) #endif { back = 1; $? ". \"%s\" created successfully", buffer #if DK3_HAVE_CHMOD (void)chmod(buffer, m); $? ". mode %o", m #endif } else { $? "! failed to create \"%s\"", buffer #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 84, 85, buffer); #else dk3app_log_i1(app, DK3_LL_ERROR, 86); #endif dk3sf_report_errno(app, errno, dk3sf_function_names[12]); } #else if(app) { $? "! no mkdir() function" /* No mkdir() function available! */ dk3app_log_i1(app, DK3_LL_ERROR, 107); } #endif } } } else { $? "! directory name too long" if(app) { /* Path too long! */ #if DK3_CHAR_SIZE == 1 dk3app_log_i3(app, DK3_LL_ERROR, 59, 60, p); #else dk3app_log_i1(app, DK3_LL_ERROR, 87); #endif } } } $? "- dk3sf_c8_mkdir_app %d", back return back; } int dk3sf_c8_get_hostname_app(char *db, size_t sz, dk3_app_t *app) { int back = 0; char *ptr = NULL; /* Begin of DNS domain name. */ if((db) && (sz)) { if(gethostname(db, sz) == 0) { back = 1; ptr = dk3str_c8_chr(db, '.'); if(ptr) { *ptr = '\0'; } } else { if(app) { /* ERROR: Failed to find host name! */ dk3app_log_i1(app, DK3_LL_ERROR, 131); dk3sf_report_errno(app, errno, dk3sf_function_names[13]); } } } return back; } #if DK3_CHAR_SIZE > 1 #error "dkChar must be 8 bit on non-Windows systems!" #else /* +++ non-Windows, dkChar 8 bit +++ */ int dk3sf_fgets_fn_app( dkChar *db, size_t sz, FILE *fi, dkChar const *fn, dk3_app_t *app ) { int back = 0; if((db) && (sz) && (fi)) { if(fgets(db, sz, fi)) { back = 1; } else { if(!feof(fi)) { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 346, 347, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 345); } dk3sf_report_errno(app, errno, dk3sf_function_names[25]); } } } } return back; } int dk3sf_fputs_fn_app(dkChar const *st,FILE *fi,dkChar const *fn,dk3_app_t *app) { int back = 0; if((st) && (fi)) { if(fputs(st, fi) >= 0) { back = 1; } else { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 343, 344, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 120); } dk3sf_report_errno(app, errno, dk3sf_function_names[23]); } } } return back; } int dk3sf_fputc_fn_app(dkChar ch, FILE *fi, dkChar const *fn, dk3_app_t *app) { int back = 0; if(fi) { if(fputc(ch, fi) != EOF) { back = 1; } else { if(app) { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 343, 344, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 120); } dk3sf_report_errno(app, errno, dk3sf_function_names[24]); } } } return back; } void dk3sf_initialize_stdout(void) { } void dk3sf_initialize_stderr(void) { } void dk3sf_initialize_file(FILE *fipo) { } /* --- non-Windows, dkChar 8 bit --- */ #endif /* --- non-Windows --- */ #endif int dk3sf_must_expand(dkChar const *fn) { int back = 0; $? "+ dk3sf_must_expand" if(fn) { #if DK3_ON_WINDOWS dkChar const *ptr; ptr = fn; while((*ptr) && (back == 0)) { switch(*ptr) { case dkT('?'): case dkT('*'): { back = 1; } break; } ptr++; } #endif } $? "- dk3sf_must_expand %d", back return back; } int dk3sf_c8_fputc(char c, FILE *f) { int back = 0; if(f) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 if(fputwc((((wchar_t)c) & 0x000000FFUL), f) != WEOF) { back = 1; } #else if(fputwc((((wchar_t)c) & 0x00FFU), f) != WEOF) { back = 1; } #endif #else if(fputc(c, f) != EOF) { back = 1; } #endif } return back; } int dk3sf_c8_fputs(char const *s, FILE *f) { int back = 0; char const *ptr = NULL; if((s) && (f)) { back = 1; ptr = s; while(*ptr) { if(!dk3sf_c8_fputc(*(ptr++), f)) { back = 0; } } } return back; } size_t dk3sf_read_app(int fd, void *buf, size_t s, dk3_app_t *app) { size_t back = 0; $? "+ dk3sf_read_app buf=%s s=%u", TR_PTR(buf), (unsigned)s if((buf) && (s)) { #if DK3_ON_WINDOWS int rb; $? ". Windows +" rb = _read(fd, buf, (unsigned int)s); if(rb >= 0) { back = (size_t)rb; } else { /* ERROR: Read failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 124); } $? ". Windows -" #else $? ". non-Windows +" #if DK3_HAVE_READ ssize_t rb = 0; /* Number of bytes read. */ $? ". read() +" rb = read(fd, buf, s); if(rb >= (ssize_t)0) { back = (size_t)rb; } else { if(app) { /* ERROR: Read failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 124); dk3sf_report_errno(app, errno, dk3sf_function_names[14]); } } $? ". read() -" #else #if DK3_HAVE__READ ssize_t rb = 0; /* Number of bytes read. */ $? ". _read() +" rb = _read(fd, buf, s); if(rb >= (ssize_t)0) { back = (size_t)rb; } else { if(app) { /* ERROR: Read failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 124); dk3sf_report_errno(app, errno, dk3sf_function_names[15]); } } $? ". _read() -" #else #error "No read() function available!" #endif #endif $? ". non-Windows -" #endif } $? "- dk3sf_read_app %u", (unsigned)back return back; } int dk3sf_write_app(int fd, char const *buf, size_t s, dk3_app_t *app) { int back = 0; if((buf) && (s)) { #if DK3_ON_WINDOWS int wb; wb = _write(fd, buf, (unsigned int)s); if(wb >= 0) { if((size_t)wb == s) { back = 1; } else { if(app) { /* ERROR: Not all bytes written! */ dk3app_log_write_error(app, DK3_LL_ERROR, s, wb); } } } else { if(app) { /* ERROR: Write failed! */ dk3app_log_i1( app, DK3_LL_ERROR, 173); } } #else #if DK3_HAVE_WRITE ssize_t wb; wb = write(fd, buf, s); if(wb >= 0) { if((size_t)wb == s) { back = 1; } else { if(app) { /* ERROR: Not all bytes written! */ dk3app_log_write_error(app, DK3_LL_ERROR, s, wb); } } } else { if(app) { /* ERROR: Write failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 173); dk3sf_report_errno(app, errno, dk3sf_function_names[16]); } } #else #if DK3_HAVE__WRITE ssize_t wb; wb = _write(fd, buf, s); if(wb >= 0) { if((size_t)wb == s) { back = 1; } else { if(app) { /* ERROR: Not all bytes written! */ dk3app_log_write_error(app, DK3_LL_ERROR, s, wb); } } } else { if(app) { /* ERROR: Write failed! */ dk3app_log_i1(app, DK3_LL_ERROR, 173); dk3sf_report_errno(app, errno, dk3sf_function_names[17]); } } #else #error "No write() function available!" #endif #endif #endif } return back; } size_t dk3sf_fread_app(void *db, size_t sz, size_t ne, FILE *fi, dk3_app_t *app) { size_t back = 0; if((db) && (sz) && (ne) && (fi)) { #if DK3_ON_WINDOWS back = fread(db, sz, ne, fi); if(back < ne) { if(ferror(fi)) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 124); } } clearerr(fi); } #else #if DK3_HAVE_FREAD back = fread(db, sz, ne, fi); if(back < ne) { if(ferror(fi)) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 124); dk3sf_report_errno(app, errno, dk3sf_function_names[18]); } } clearerr(fi); } #else #if DK3_HAVE__FREAD back = _fread(db, sz, ne, fi); if(back < ne) { if(ferror(fi)) { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 124); dk3sf_report_errno(app, errno, dk3sf_function_names[19]); } } clearerr(fi); } #else #error "No fread() function available!" #endif #endif #endif } return back; } int dk3sf_fwrite_app(void const *sb, size_t sz, size_t ne, FILE *fi, dk3_app_t *app) { int back = 0; if((sb) && (sz) && (ne) && (fi)) { #if DK3_ON_WINDOWS size_t wb; wb = fwrite(sb, sz, ne, fi); if(wb == ne) { back = 1; } else { if(app) { dk3app_log_fwrite_error(app, DK3_LL_ERROR, ne, wb); } } #else #if DK3_HAVE_FWRITE size_t wb; wb = fwrite(sb, sz, ne, fi); if(wb == ne) { back = 1; } else { if(app) { dk3app_log_fwrite_error(app, DK3_LL_ERROR, ne, wb); dk3sf_report_errno(app, errno, dk3sf_function_names[20]); } } #else #if DK3_HAVE__FWRITE size_t wb; wb = _fwrite(sb, sz, ne, fi); if(wb == ne) { back = 1; } else { if(app) { dk3app_log_fwrite_error(app, DK3_LL_ERROR, ne, wb); dk3sf_report_errno(app, errno, dk3sf_function_names[21]); } } #else #error "No fwrite() function available!" #endif #endif #endif } return back; } int dk3sf_inspect_bom_skip_app( dkChar const *fn, int dv, size_t *skb, dk3_app_t *app ) { int back = -1; int found = 0; /* Flag: Any form of BOM found .*/ FILE *fipo = NULL; /* Input file. */ unsigned char bb[4]; /* Buffer for BOM. */ size_t rb = 0; /* Number of bytes read. */ $? "+ dk3sf_inspect_bom_app %d", dv if(skb) { *skb = 0; } back = dv; if(fn) { fipo = dk3sf_fopen_app(fn, dk3app_not_localized(36), app); if(fipo) { rb = dk3sf_fread_app(bb, 1, 4, fipo, app); /* Check UTF-8 */ if(rb >= 3) { if((bb[0] == 0xEF) && (bb[1] == 0xBB) && (bb[2] == 0xBF)) { found = 1; back = DK3_FILE_ENCODING_UTF8; $? ". UTF-8" if(skb) { *skb = 3; } } } if(!found) { if(rb >= 2) { if((bb[0] == 0xFE) && (bb[1] == 0xFF)) { found = 1; back = DK3_FILE_ENCODING_UTF16_MSB_FIRST; $? ". U16 M" if(skb) { *skb = 2; } } else { if((bb[0] == 0xFF) && (bb[1] == 0xFE)) { found = 1; back = DK3_FILE_ENCODING_UTF16_LSB_FIRST; $? ". U16 L" if(skb) { *skb = 2; } if(rb >= 4) { if((bb[2] == 0x00) && (bb[3] == 0x00)) { back = DK3_FILE_ENCODING_UNICODE_LSB_FIRST; $? ". U32 L" if(skb) { *skb = 4; } } } } } } } if(!found) { if(rb >= 4) { if((bb[0] == 0x00) && (bb[1] == 0x00) && (bb[2] == 0xFE) && (bb[3] == 0xFF) ) { found = 1; back = DK3_FILE_ENCODING_UNICODE_MSB_FIRST; $? ". U32 M" if(skb) { *skb = 4; } } } } if(!found) { /* No BOM found */ back = dv; } fclose(fipo); } } $? "- dk3sf_inspect_bom_app %d", back return back; } int dk3sf_inspect_bom_app(dkChar const *fn, int dv, dk3_app_t *app) { int back; back = dk3sf_inspect_bom_skip_app(fn, dv, NULL, app); return back; } int dk3sf_apply_bom_to_file_app(FILE *fipo, int enc, dk3_app_t *app) { int back = 0; $? "+ dk3sf_apply_bom_to_file_app" #if DK3_ON_WINDOWS if(fipo) { switch(enc) { case DK3_FILE_ENCODING_ASCII: { back = 1; $? ". keep default" } break; case DK3_FILE_ENCODING_UTF8: { back = 1; _setmode(_fileno(fipo), _O_U8TEXT); $? ". 8" } break; case DK3_FILE_ENCODING_UTF16_LSB_FIRST: { _setmode(_fileno(fipo), _O_U16TEXT); $? ". 16 L" } break; default: { /* ERROR: Encoding can not be handled directly by file! */ dk3app_log_i1(app, DK3_LL_ERROR, 204); } break; } } #else if(fipo) { switch(enc) { case DK3_FILE_ENCODING_ASCII: case DK3_FILE_ENCODING_UTF8: { back = 1; $? ". 8-bit, ok" } break; default: { /* ERROR: Encoding can not be handled direcly by file! */ dk3app_log_i1(app, DK3_LL_ERROR, 204); } break; } } #endif $? "- dk3sf_apply_bom_to_file_app %d", back return back; } int dk3sf_is_dir_app(dkChar const *n, dk3_app_t *app) { int back = 0; dk3_stat_t stb; if(dk3sf_stat_app(&stb, n, app)) { if(((stb.ft) & (~(DK3_FT_SYMLINK))) == DK3_FT_DIRECTORY) { back = 1; } else { if(app) { /* ERROR: n is not a directory! */ dk3app_log_i3(app, DK3_LL_ERROR, 202, 203, n); } } } return back; } int dk3sf_chdir_app(dkChar const *dn, dk3_app_t *app) { int back = 0; if(dn) { #if DK3_CHAR_SIZE > 1 #if DK3_ON_WINDOWS if(_wchdir(dn) == 0) { back = 1; } else { if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 242, 243, dn); } } #else #error "No chdir() function (16-bit) on non-Windows systems!" #endif #else #if DK3_ON_WINDOWS if(chdir(dn) == 0) { back = 1; } else { if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 242, 243, dn); } } #else #if DK3_HAVE_CHDIR if(chdir(dn) == 0) { back = 1; } else { if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 242, 243, dn); dk3sf_report_errno(app, errno, dk3sf_function_names[22]); } } #else #error "No chdir() function available!" #endif #endif #endif } return back; } int dk3sf_must_rebuild(dkChar const *dn, dkChar const *sn) { int back = 1; dk3_stat_t stbs; dk3_stat_t stbd; if((dn) && (sn)) { if(dk3sf_stat_app(&stbd, dn, NULL)) { if(dk3sf_stat_app(&stbs, sn, NULL)) { if(stbd.mod > stbs.mod) { back = 0; } } } } return back; } int dk3sf_filename_to_c8( char *fnb, size_t szfnb, dkChar const *src, dk3_app_t *app ) { int back = 0; if((fnb) && (szfnb) && (src)) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "Only 1- or 2-byte character support available!" #else #if DK3_ON_WINDOWS back = dk3str_cnv_c16_to_c8p_app(fnb, szfnb, src, app); #else #error "2-byte character support is available on Windows platforms only!" #endif #endif #else if(dk3str_len(src) < szfnb) { dk3str_cpy_not_overlapped(fnb, src); back = 1; } else { /* ERROR: File name too long! */ if(app) { dk3app_log_i3(app, DK3_LL_ERROR, 65, 66, src); } } #endif } return back; } int dk3sf_scan_double_app(dkChar const *txt, double *v, dk3_app_t *app) { int back = 0; $? "+ dk3sf_scan_double" if((txt) && (v)) { $? ". args ok" #if DK3_HAVE_SETLOCALE char oldlocale[64]; char *lcptr; lcptr = setlocale(LC_NUMERIC, NULL); $? ". have setlocale" if(lcptr) { $? ". setlocale (1) ok" if(dk3str_c8_len(lcptr) < sizeof(oldlocale)) { $? ". length ok" dk3str_c8_cpy_not_overlapped(oldlocale, lcptr); setlocale(LC_NUMERIC, "C"); #if VERSION_BEFORE_20140716 back = dk3sf_sscanf3(txt,dkT("%lf"),v); #else back = dk3ma_d_from_string(v, txt, NULL); #endif setlocale(LC_NUMERIC, oldlocale); } else { $? "! too long" #if VERSION_BEFORE_20140716 dk3sf_sscanf3(txt,dkT("%lf"),v); #else back = dk3ma_d_from_string(v, txt, NULL); #endif if(app) { /* ERROR: Failed to save current locale! */ dk3app_log_i1(app, DK3_LL_ERROR, 254); } } } else { $? "! setlocale (1)" #if VERSION_BEFORE_20140716 dk3sf_sscanf3(txt,dkT("%lf"),v); #else back = dk3ma_d_from_string(v, txt, NULL); #endif if(app) { /* ERROR: Failed to obtain current locale! */ dk3app_log_i1(app, DK3_LL_ERROR, 253); } } #else #if VERSION_BEFORE_20140716 back = dk3sf_sscanf3(txt,dkT("%lf"),v); $? ". no setlocale" #else back = dk3ma_d_from_string(v, txt, NULL); #endif #endif } $? "- dk3sf_scan_double %d", back return back; } int dk3sf_get_max_files(void) { int back = 1024; #if DK3_HAVE_SYS_RESOURCE_H #if DK3_HAVE_GETRLIMIT struct rlimit rl; if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) { if(rl.rlim_max != RLIM_INFINITY) { back = rl.rlim_max; } } #endif #endif return back; } int dk3sf_fclose_fn_app(FILE *fipo, dkChar const *fn, dk3_app_t *app) { int back = 0; int res; if(fipo) { res = fclose(fipo); if(0 == res) { back = 1; } else { if(fn) { dk3app_log_i3(app, DK3_LL_ERROR, 341, 342, fn); } else { dk3app_log_i1(app, DK3_LL_ERROR, 340); } dk3sf_report_errno(app, errno, dk3sf_function_names[1]); } } return back; } int dk3sf_fclose_app(FILE *fipo, dk3_app_t *app) { int back = 0; back = dk3sf_fclose_fn_app(fipo, NULL, app); return back; } int dk3sf_fgets(dkChar *db, size_t sz, FILE *fi) { int back; back = dk3sf_fgets_fn_app(db, sz, fi, NULL, NULL); return back; } int dk3sf_fputs(dkChar const *st, FILE *fi) { int back; back = dk3sf_fputs_fn_app(st, fi, NULL, NULL); return back; } int dk3sf_fputt(dkChar const * const *txt, FILE *fi) { dkChar const * const *ptr; int back = 0; if((txt) && (fi)) { back = 1; ptr = txt; while(*ptr) { if(!(dk3sf_fputs(*(ptr++), fi))) { back = 0; } dk3sf_fputc(dkT('\n'), fi); } } return back; } int dk3sf_fputc(dkChar c, FILE *fi) { int back; back = dk3sf_fputc_fn_app(c, fi, NULL, NULL); return back; } int dk3sf_stat_app(dk3_stat_t *st, dkChar const *fn, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_stat_app(st, fn, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_stat_app(st, fn, app)); #endif } FILE * dk3sf_fopen_app(dkChar const *fn, dkChar const *mo, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_fopen_app(fn, mo, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_fopen_app(fn, mo, app)); #endif } int dk3sf_time_convert_app( dkChar *dest, size_t sz, dk3_time_t const *timer, dk3_app_t *app ) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_time_convert_app(dest, sz, timer, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_time_convert_app(dest, sz, timer, app)); #endif } int dk3sf_getcwd_app(dkChar *dest, size_t sz, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_getcwd_app(dest, sz, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_getcwd_app(dest, sz, app)); #endif } int dk3sf_find_exec_app( dkChar *d, size_t s, dkChar const *w, dkChar const *c, dk3_app_t *app ) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_find_exec_app(d, s, w, c, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_find_exec_app(d, s, w, c, app)); #endif } int dk3sf_get_logname_app(dkChar *d, size_t s, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_get_logname_app(d, s, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_get_logname_app(d, s, app)); #endif } int dk3sf_get_home_app(dkChar *d, size_t s, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_get_home_app(d, s, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_get_home_app(d, s, app)); #endif } int dk3sf_mkdir_app(dkChar const *p, int mo, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_mkdir_app(p, mo, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_mkdir_app(p, mo, app)); #endif } int dk3sf_remove_file_app(dkChar const *n, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_remove_file_app(n, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_remove_file_app(n, app)); #endif } int dk3sf_remove_dir_app(dkChar const *n, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_remove_dir_app(n, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_remove_dir_app(n, app)); #endif } int dk3sf_get_hostname_app(dkChar *db, size_t sz, dk3_app_t *app) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_get_hostname_app(db, sz, app)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_get_hostname_app(db, sz, app)); #endif } dkChar * dk3sf_getenv(dkChar const *name) { #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 #error "System function for b-byte character strings not available!" #else #if DK3_ON_WINDOWS return(dk3sf_c16_getenv(name)); #else #error "Wide character functions not defined on non-Windows systems!" #endif #endif #else return(dk3sf_c8_getenv(name)); #endif } /* vim: set ai sw=2 : */