/*
Copyright (c) 2000-2010, Dirk Krause
All rights reserved.

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

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

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



/**	@file	dksf.c	System functions.
*/



#include "dk.h"
#include "dktypes.h"
#include "dksfc.h"
#include "dkmem.h"
#include "dkstr.h"
#include "dkerror.h"

#include <stdio.h>

#line 53 "dksf.ctr"


#if DK_HAVE_DOS_H
#include <dos.h>
#endif
#if DK_HAVE_IO_H
#include <io.h>
#endif
#if DK_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if DK_HAVE_STDDEF_H
#include <stddef.h>
#endif
#if DK_HAVE_STRING_H
#include <string.h>
#endif
#if DK_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if DK_HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#if DK_HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if DK_HAVE_SYS_SYSTEMINFO_H
#include <sys/systeminfo.h>
#endif
#if DK_HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#if DK_HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#if DK_HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if DK_HAVE_TERMIOS_H
#include <termios.h>
#endif
#if DK_HAVE_SYS_TERMIOS_H
#include <sys/termios.h>
#endif
#if DK_HAVE_SYS_TTOLD_H
#include <sys/ttold.h>
#endif
#if DK_HAVE_WINCON_H
#include <wincon.h>
#endif
#if DK_HAVE_UNISTD_H
#include <unistd.h>
#endif
#if DK_HAVE_DIRECT_H
#include <direct.h>
#endif
#if DK_HAVE_DIRENT_H
#include <dirent.h>
#endif
#if DK_HAVE_DIR_H
#include <dir.h>
#endif
#if DK_HAVE_PWD_H
#include <pwd.h>
#endif
#if DK_HAVE_PROCESS_H
#include <process.h>
#endif
#include "dkwin.h"
#if DK_HAVE_ERRNO_H
#include <errno.h>
#endif

#include "dkmem.h"

/**	Inside the dksf module.
*/
#define DK_SYSFCT_C 1
#include "dksf.h"


/**	Abbreviation for tm.
*/
typedef struct tm STRUCTTM;


#ifdef MY_MAXPATHLEN
#undef MY_MAXPATHLEN
#endif

#ifdef MAXPATHLEN
/**	Maximum path length.
*/
#define MY_MAXPATHLEN MAXPATHLEN
#else
#ifdef _MAX_PATH
/**	Maximum path length.
*/
#define MY_MAXPATHLEN _MAX_PATH
#else
/**	Maximum path length.
*/
#define MY_MAXPATHLEN 1024L
#endif
#endif



/**	Separator between path components.
*/
static char path_component_separator[] = {
#if DK_HAVE_FEATURE_BACKSLASH
"\\"
#else
"/"
#endif
};



/**	Other delimiter, not a separator between path components.
*/
static char no_component_separator[] = {
#if DK_HAVE_FEATURE_BACKSLASH
"/"
#else
"\\"
#endif
};



/**	The /var/run directory.
*/
static char var_run[] = { DK_LOCALSTATEDIR "/run" };



/**	Suffix to use for PID files.
*/
static char suffix_pid[] = { ".pid" };


#ifdef USE_FNE
#undef USE_FNE
#endif

#if defined(WIN32) || defined(_WIN32)
/* + Win32 */
#if DK_HAVE__FINDFIRST64
/* Win32, _findfirst64 */
/**	Flag: Use file name expander.
*/
#define USE_FNE	1
#else
#if DK_HAVE__FINDFIRST32
/* Win32, _findfirst32 */
/**	Flag: Use file name expander.
*/
#define USE_FNE 1
#else
#if DK_HAVE__FINDFIRST
/* Win32, _findfirst */
/**	Flag: Use file name expander.
*/
#define USE_FNE 1
#endif
#endif
#endif
/* - Win32 */
#else
#if DK_HAVE_FINDFIRST
/* DOS, findfirst */
/**	Flag: Use file name expander.
*/
#define USE_FNE 1
#else
#if DK_HAVE_DIRENT_H
/* UNIX/Linux, dirent */
/**	Flag: Do not use file name expander.
*/
#define USE_FNE 0
#else
/* any unknown directory listing mechanism */
/**	Flag: Do not use file name expander.
*/
#define USE_FNE 0
#endif
#endif
#endif



#if USE_FNE
/**	Pattern to match all files in the current directory.
*/
static char all_files[] = {
#if DK_HAVE_ALLDOTALL
  "*.*"
#else
  "*"
#endif
};
#endif



#if DK_HAVE_FEATURE_DOS_EXEC
/**	Default PATH extensions on DOS and followers.
*/
static char default_path_ext[] = { ".COM;.EXE;.BAT" };
#endif



#if DK_HAVE_FEATURE_BACKSLASH
/**	Default temporary directory on DOS and followers.
*/
static char temp_string[] = { "\\TEMP" };
#endif



/**	Time format to show file times.
*/
static char time_format[] = { "%04d/%02d/%02d %02d:%02d:%02d" };



/**	File name of current working directory.
*/
static char curdir[] = { "." };



#if DK_HAVE_DOS_DRIVE_LETTER
/**	Colon, used to construct path names.
*/
static char str_colon = ':';
#endif


#ifndef S_IFMT
/**	File mask.
*/
#ifdef _S_IFMT
#define S_IFMT (_S_IFMT)
#else
#define S_IFMT 0170000
#endif
#endif



#ifndef S_IFREG
/**	File type: Regular file.
*/
#ifdef _S_IFREG
#define S_IFREG (_S_IFREG)
#else
#define S_IFREG 0100000
#endif
#endif



#ifndef S_IFSOCK
/**	File type: Socket.
*/
#ifdef _S_IFSOCK
#define S_IFSOCK (_S_IFSOCK)
#else
#define S_IFSOCK 0140000
#endif
#endif



#ifndef S_IFLNK
/**	File type: Symbolic link.
*/
#ifdef _S_IFLNK
#define S_IFLNK (_S_IFLNK)
#else
#define S_IFLNK 0120000
#endif
#endif



#ifndef S_IFBLK
/**	File type: Block device.
*/
#ifdef _S_IFBLK
#define S_IFBLK (_S_IFBLK)
#else
#define S_IFBLK 0060000
#endif
#endif



#ifndef S_IFDIR
/**	File type: Directory.
*/
#ifdef _S_IFDIR
#define S_IFDIR (_S_IFDIR)
#else
#define S_IFDIR 0040000
#endif
#endif



#ifndef S_IFCHR
/**	File type: Character device.
*/
#ifdef _S_IFCHR
#define S_IFCHR (_S_IFCHR)
#else
#define S_IFCHR 0020000
#endif
#endif



#ifndef S_IFIFO
/**	File type: FIFO.
*/
#ifdef _S_IFIFO
#define S_IFIFO (_S_IFIFO)
#else
#define S_IFIFO 0010000
#endif
#endif



/**	Convert native file type to DK_FT_xxx file type.
	@param	m	Native file type.
	@return	DK_FT_xxx file type.
*/
static
int
dksf_filetype	DK_P1(mode_t,	m)
{
  int back, found;
  
  back = found = 0;
  switch(m & S_IFMT) {
    case S_IFSOCK : back = DK_FT_SOCKET ; break;
    case S_IFLNK  : back = DK_FT_SYMLINK ; break;
    case S_IFREG  : back = DK_FT_REG; break;
    case S_IFBLK  : back = DK_FT_BLK; break;
    case S_IFDIR  : back = DK_FT_DIR; break;
    case S_IFCHR  : back = DK_FT_CHR; break;
    default:        back = DK_FT_OTHER; break;
  }
  
  return back;
}



/**	Convert DK_PERM_xxx permissions to native permissions.
	@param	m	DK_PERM_xxx permissions.
	@return	Native permissions.
*/
mode_t
dksf_perm_dk2h	DK_P1(int, m)
{
  mode_t back = 0L;
  
if(m & DK_PERM_SUID) {
#ifdef S_ISUID
back |= S_ISUID;
#else
#ifdef _S_ISUID
back |= _S_ISUID;
#else
back |= DK_PERM_SUID;
#endif
#endif
}

if(m & DK_PERM_SGID) {
#ifdef S_ISGID
back |= S_ISGID;
#else
#ifdef _S_ISGID
back |= _S_ISGID;
#else
back |= DK_PERM_SGID;
#endif
#endif
}

if(m & DK_PERM_VTX) {
#ifdef S_ISVTX
back |= S_ISVTX;
#else
#ifdef _S_ISVTX
back |= _S_ISVTX;
#else
back |= DK_PERM_VTX;
#endif
#endif
}

if(m & DK_PERM_U_READ) {
#ifdef S_IRUSR
back |= S_IRUSR;
#else
#ifdef _S_IRUSR
back |= _S_IRUSR;
#else
back |= DK_PERM_U_READ;
#endif
#endif
}

if(m & DK_PERM_U_WRITE) {
#ifdef S_IWUSR
back |= S_IWUSR;
#else
#ifdef _S_IWUSR
back |= _S_IWUSR;
#else
back |= DK_PERM_U_WRITE;
#endif
#endif
}

if(m & DK_PERM_U_EXECUTE) {
#ifdef S_IXUSR
back |= S_IXUSR;
#else
#ifdef _S_IXUSR
back |= _S_IXUSR;
#else
back |= DK_PERM_U_EXECUTE;
#endif
#endif
}

if(m & DK_PERM_G_READ) {
#ifdef S_IRGRP
back |= S_IRGRP;
#else
#ifdef _S_IRGRP
back |= _S_IRGRP;
#else
back |= DK_PERM_G_READ;
#endif
#endif
}

if(m & DK_PERM_G_WRITE) {
#ifdef S_IWGRP
back |= S_IWGRP;
#else
#ifdef _S_IWGRP
back |= _S_IWGRP;
#else
back |= DK_PERM_G_WRITE;
#endif
#endif
}

if(m & DK_PERM_G_EXECUTE) {
#ifdef S_IXGRP
back |= S_IXGRP;
#else
#ifdef _S_IXGRP
back |= _S_IXGRP;
#else
back |= DK_PERM_G_EXECUTE;
#endif
#endif
}

if(m & DK_PERM_O_READ) {
#ifdef S_IROTH
back |= S_IROTH;
#else
#ifdef _S_IROTH
back |= _S_IROTH;
#else
back |= DK_PERM_O_READ;
#endif
#endif
}

if(m & DK_PERM_O_WRITE) {
#ifdef S_IWOTH
back |= S_IWOTH;
#else
#ifdef _S_IWOTH
back |= _S_IWOTH;
#else
back |= DK_PERM_O_WRITE;
#endif
#endif
}

if(m & DK_PERM_O_EXECUTE) {
#ifdef S_IXOTH
back |= S_IXOTH;
#else
#ifdef _S_IXOTH
back |= _S_IXOTH;
#else
back |= DK_PERM_O_EXECUTE;
#endif
#endif
}
  
  return back;
}



/**	Convert native permissions to DK_PERM_xxx permissions.
	@param	m	Native permissions.
	@return	DK_PERM_xxx permissions.
*/
int
dksf_perm_h2dk	DK_P1(mode_t, m)
{
  int back = 0;
  
#ifdef S_ISUID
  if(m & S_ISUID) back |= DK_PERM_SUID;
#else
#ifdef _S_ISUID
  if(m & _S_ISUID) back |= DK_PERM_SUID;
#else
  if(m & DK_PERM_SUID) back |= DK_PERM_SUID;
#endif
#endif
#ifdef S_ISGID
  if(m & S_ISGID) back |= DK_PERM_SGID;
#else
#ifdef _S_ISGID
  if(m & _S_ISGID) back |= DK_PERM_SGID;
#else
  if(m & DK_PERM_SGID) back |= DK_PERM_SGID;
#endif
#endif
#ifdef S_ISVTX
  if(m & S_ISVTX) back |= DK_PERM_VTX;
#else
#ifdef _S_ISVTX
  if(m & _S_ISVTX) back |= DK_PERM_VTX;
#else
  if(m & DK_PERM_VTX) back |= DK_PERM_VTX;
#endif
#endif

#ifdef S_IRUSR
if(m & S_IRUSR) back |= DK_PERM_U_READ;
#else
#ifdef _S_IRUSR
if(m & _S_IRUSR) back |= DK_PERM_U_READ;
#else
if(m & DK_PERM_U_READ) back |= DK_PERM_U_READ;
#endif
#endif

#ifdef S_IWUSR
if(m & S_IWUSR) back |= DK_PERM_U_WRITE;
#else
#ifdef _S_IWUSR
if(m & _S_IWUSR) back |= DK_PERM_U_WRITE;
#else
if(m & DK_PERM_U_WRITE) back |= DK_PERM_U_WRITE;
#endif
#endif

#ifdef S_IXUSR
if(m & S_IXUSR) back |= DK_PERM_U_EXECUTE;
#else
#ifdef _S_IXUSR
if(m & _S_IXUSR) back |= DK_PERM_U_EXECUTE;
#else
if(m & DK_PERM_U_EXECUTE) back |= DK_PERM_U_EXECUTE;
#endif
#endif


#ifdef S_IRGRP
if(m & S_IRGRP) back |= DK_PERM_G_READ;
#else
#ifdef _S_IRGRP
if(m & _S_IRGRP) back |= DK_PERM_G_READ;
#else
if(m & DK_PERM_G_READ) back |= DK_PERM_G_READ;
#endif
#endif

#ifdef S_IWGRP
if(m & S_IWGRP) back |= DK_PERM_G_WRITE;
#else
#ifdef _S_IWGRP
if(m & _S_IWGRP) back |= DK_PERM_G_WRITE;
#else
if(m & DK_PERM_G_WRITE) back |= DK_PERM_G_WRITE;
#endif
#endif

#ifdef S_IXGRP
if(m & S_IXGRP) back |= DK_PERM_G_EXECUTE;
#else
#ifdef _S_IXGRP
if(m & _S_IXGRP) back |= DK_PERM_G_EXECUTE;
#else
if(m & DK_PERM_G_EXECUTE) back |= DK_PERM_G_EXECUTE;
#endif
#endif

#ifdef S_IROTH
if(m & S_IROTH) back |= DK_PERM_O_READ;
#else
#ifdef _S_IROTH
if(m & _S_IROTH) back |= DK_PERM_O_READ;
#else
if(m & DK_PERM_O_READ) back |= DK_PERM_O_READ;
#endif
#endif

#ifdef S_IWOTH
if(m & S_IWOTH) back |= DK_PERM_O_WRITE;
#else
#ifdef _S_IWOTH
if(m & _S_IWOTH) back |= DK_PERM_O_WRITE;
#else
if(m & DK_PERM_O_WRITE) back |= DK_PERM_O_WRITE;
#endif
#endif

#ifdef S_IXOTH
if(m & S_IXOTH) back |= DK_PERM_O_EXECUTE;
#else
#ifdef _S_IXOTH
if(m & _S_IXOTH) back |= DK_PERM_O_EXECUTE;
#else
if(m & DK_PERM_O_EXECUTE) back |= DK_PERM_O_EXECUTE;
#endif
#endif
  
  return back;
}



/**	Convert timestamp to text.
	@param	s	String buffer for result.
	@param	t	Timestamp structure.
*/
static
void
internal_time_convert DK_P2(char *, s, struct tm *, t)
{
  struct tm *tm;
  
  tm = t;
  s[0] = '\0';
  sprintf(s, time_format,
      (tm->tm_year + 1900),
      (tm->tm_mon + 1),
      tm->tm_mday,
      tm->tm_hour,
      tm->tm_min,
      tm->tm_sec
  );
  
}




void
dksf_time_convert DK_P2(char *, s, time_t, t)
{
  struct tm *tm;
  
  tm = localtime(&t);
  s[0] = '\0';
  if(tm) {
    internal_time_convert(s, tm);
  }
  
}



/**	Initialize a struct tm.
	@param	tm	Struct to initialize.
*/	
static
void
init_struct_tm DK_P1(struct tm *,tm) {
  tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0;
  tm->tm_mday = 1; tm->tm_mon = 0; tm->tm_year = 0;
  tm->tm_wday = 0; tm->tm_yday = 0; tm->tm_isdst = 0;
}



/**	Initialize a dk_stat_t structure.
	@param	ptr	Structure to inspect.
*/
static
void
dkstat_init	DK_P1(dk_stat_t, *ptr)
{
    
    ptr->permissions = 0;
    ptr->filetype = 0;
#if DK_HAVE_LONG_LONG_INT
    ptr->size = 0ULL;
    
#else
    ptr->size = 0UL;
    
#endif
    ptr->size_math_error = 0;
    ptr->inode_number = 0UL;
    ptr->device_number = 0UL;
    ptr->rdevice_number = 0UL;
    ptr->number_of_links = 0UL;
    ptr->uid = 0L; ptr->gid = 0L;
    ptr->ctime[0] = ptr->atime[0] = ptr->mtime[0] = '\0';
    ptr->is_far_link = 0;
    /* ptr->ori_ctime = ptr->ori_atime = ptr->ori_mtime = (time_t)0L; */
    init_struct_tm(&(ptr->ori_ctime));
    init_struct_tm(&(ptr->ori_atime));
    init_struct_tm(&(ptr->ori_mtime));
    ptr->ud = 0x00;
    ptr->gd = 0x00;
}



int
dkstat_get	DK_P2(dk_stat_t *, ptr, char *, filename)
{
  int back = 0;
  struct tm *tm;
  
  if((ptr) && (filename)) {
#if defined(WIN32) || defined(_WIN32)
#if DK_HAVE__STAT64
      /* + _stat64 */
      struct __stat64 st;
#if DK_HAVE__LSTAT64
      struct __stat64 lst;
#endif
      if(_stat64(filename, &st) == 0) {
        back = 1;
        ptr->filetype = dksf_filetype(st.st_mode);
        ptr->permissions = dksf_perm_h2dk(st.st_mode);
        ptr->inode_number = (unsigned long)(st.st_ino);
        ptr->device_number = (unsigned long)(st.st_dev);
        ptr->rdevice_number = (unsigned long)(st.st_rdev);
        ptr->size = (dk_long_long_unsigned_t)(st.st_size);
        
        if(sizeof(off_t)>sizeof(dk_long_long_unsigned_t)) {
	  ptr->size_math_error = (((off_t)(ptr->size) != st.st_size) ? 1 : 0);
	} else {
          ptr->size_math_error = 0;
          
        }
        ptr->number_of_links = (unsigned long)(st.st_nlink);
        ptr->uid = (long)(st.st_uid);
        ptr->gid = (long)(st.st_gid);
        ptr->ctime[0] = '\0'; ptr->atime[0] = '\0'; ptr->mtime[0]  = '\0';
	/*
        ptr->ori_ctime = st.st_ctime;
        ptr->ori_atime = st.st_atime;
        ptr->ori_mtime = st.st_mtime;
	*/
	tm = _localtime64(&(st.st_ctime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_ctime), tm, sizeof(STRUCTTM));
	}
	tm = _localtime64(&(st.st_atime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_atime), tm, sizeof(STRUCTTM));
	}
	tm = _localtime64(&(st.st_mtime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_mtime), tm, sizeof(STRUCTTM));
	}
#if DK_HAVE__LSTAT64
        if(_lstat64(filename, &lst) == 0) { 
	  if(dksf_filetype(lst.st_mode) == DK_FT_SYMLINK) {
	    
	    ptr->filetype |= DK_FT_SYMLINK;
	    if(lst.st_dev != st.st_dev) {
	      ptr->is_far_link = 1;
	    }
	  }
	  if(st.st_uid != lst.st_uid) { ptr->ud = 0x01; }
	  if(st.st_gid != lst.st_gid) { ptr->gd = 0x01; }
        } else {	
	  back = 0;
	}
#endif
      }
      /* - _stat64 */
#else
/* if DK_HAVE__STAT64 */
#if DK_HAVE__STAT32
      /* + _stat32 */
      struct __stat32 st;
#if DK_HAVE__LSTAT32
      struct __stat32 lst;
#endif
      if(_stat32(filename, &st) == 0) {
        back = 1;
        ptr->filetype = dksf_filetype(st.st_mode);
        ptr->permissions = dksf_perm_h2dk(st.st_mode);
        ptr->inode_number = (unsigned long)(st.st_ino);
        ptr->device_number = (unsigned long)(st.st_dev);
        ptr->rdevice_number = (unsigned long)(st.st_rdev);
        ptr->size = (dk_long_long_unsigned_t)(st.st_size);
        
        if(sizeof(off_t)>sizeof(dk_long_long_unsigned_t)) {
          ptr->size_math_error =
          (((st.st_size) > ((off_t)DK_MAX_LONG_LONG_UNSIGNED)) ? 1 : 0);
          
        } else {
          ptr->size_math_error = 0;
          
        }
        ptr->number_of_links = (unsigned long)(st.st_nlink);
        ptr->uid = (long)(st.st_uid);
        ptr->gid = (long)(st.st_gid);
        ptr->ctime[0] = '\0'; ptr->atime[0] = '\0'; ptr->mtime[0]  = '\0';
	/*
        ptr->ori_ctime = st.st_ctime;
        ptr->ori_atime = st.st_atime;
        ptr->ori_mtime = st.st_mtime;
	*/
	tm = localtime(&(st.st_ctime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_ctime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_atime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_atime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_mtime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_mtime), tm, sizeof(STRUCTTM));
	}
#if DK_HAVE__LSTAT32
        if(_lstat32(filename, &lst) == 0) { 
	  if(dksf_filetype(lst.st_mode) == DK_FT_SYMLINK) {
	    
	    ptr->filetype |= DK_FT_SYMLINK;
	    if(lst.st_dev != st.st_dev) {
	      ptr->is_far_link = 1;
	    }
	  }
	  if(st.st_uid != lst.st_uid) { ptr->ud = 0x01; }
	  if(st.st_gid != lst.st_gid) { ptr->gd = 0x01; }
        } else {			
	  back = 0;
	}
#endif
      }
      /* - _stat32 */
#else
/* if DK_HAVE__STAT32 */
#if DK_HAVE__STAT
      /* + _stat */
      struct _stat st;
#if DK_HAVE__LSTAT
      struct _stat lst;
#endif
      if(_stat(filename, &st) == 0) {
        back = 1;
        ptr->filetype = dksf_filetype(st.st_mode);
        ptr->permissions = dksf_perm_h2dk(st.st_mode);
        ptr->inode_number = (unsigned long)(st.st_ino);
        ptr->device_number = (unsigned long)(st.st_dev);
        ptr->rdevice_number = (unsigned long)(st.st_rdev);
        ptr->size = (dk_long_long_unsigned_t)(st.st_size);
        
        if(sizeof(off_t)>sizeof(dk_long_long_unsigned_t)) {
          ptr->size_math_error =
          (((st.st_size) > ((off_t)DK_MAX_LONG_LONG_UNSIGNED)) ? 1 : 0);
          
        } else {
          ptr->size_math_error = 0;
          
        }
        ptr->number_of_links = (unsigned long)(st.st_nlink);
        ptr->uid = (long)(st.st_uid);
        ptr->gid = (long)(st.st_gid);
        ptr->ctime[0] = '\0'; ptr->atime[0] = '\0'; ptr->mtime[0]  = '\0';
	/*
        ptr->ori_ctime = st.st_ctime;
        ptr->ori_atime = st.st_atime;
        ptr->ori_mtime = st.st_mtime;
	*/
	tm = localtime(&(st.st_ctime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_ctime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_atime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_atime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_mtime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_mtime), tm, sizeof(STRUCTTM));
	}
#if DK_HAVE__LSTAT
        if(_lstat(filename, &lst) == 0) { 
	  if(dksf_filetype(lst.st_mode) == DK_FT_SYMLINK) {
	    
	    ptr->filetype |= DK_FT_SYMLINK;
	    if(lst.st_dev != st.st_dev) {
	      ptr->is_far_link = 1;
	    }
	  }
	  if(st.st_uid != lst.st_uid) { ptr->ud = 0x01; }
	  if(st.st_gid != lst.st_gid) { ptr->gd = 0x01; }
        } else {			
	  back = 0;
	}
#endif
      }
      /* - _stat */
#else
/* if DK_HAVE__STAT*/
/* Problem */
#endif
/* if DK_HAVE__STAT*/
#endif
/* if DK_HAVE__STAT32 */
#endif
/* if DK_HAVE__STAT64 */
#else
/* if defined(WIN32) || defined(_WIN32) */
#if DK_HAVE_STAT64 && DK_HAVE_LARGEFILE64_SOURCE
      /* + stat64 */
      struct stat64 st;
#if DK_HAVE_LSTAT64
      struct stat64 lst;
#endif
      if(stat64(filename, &st) == 0) {
        back = 1;
	ptr->filetype = dksf_filetype(st.st_mode);
	ptr->permissions = dksf_perm_h2dk(st.st_mode);
	ptr->inode_number = (unsigned long)(st.st_ino);
	ptr->device_number = (unsigned long)(st.st_dev);
	ptr->rdevice_number = (unsigned long)(st.st_rdev);
	ptr->size = (dk_long_long_unsigned_t)(st.st_size);
	if(sizeof(off_t)>sizeof(dk_long_long_unsigned_t)) {
	  ptr->size_math_error =
	  (((st.st_size) > ((off_t)DK_MAX_LONG_LONG_UNSIGNED)) ? 1 : 0);
	  
	} else {
	  ptr->size_math_error = 0;
	  
	}
	ptr->number_of_links = (unsigned long)(st.st_nlink);
	ptr->uid = (long)(st.st_uid);
	ptr->gid = (long)(st.st_gid);
	ptr->ctime[0] = '\0'; ptr->atime[0] = '\0'; ptr->mtime[0]  = '\0';
	tm = localtime(&(st.st_ctime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_ctime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_atime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_atime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_mtime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_mtime), tm, sizeof(STRUCTTM));
	}
#if DK_HAVE_LSTAT64
	if(lstat64(filename, &lst) == 0) {
	  if(dksf_filetype(lst.st_mode) == DK_FT_SYMLINK) {
	    
	    ptr->filetype |= DK_FT_SYMLINK;
	    if(lst.st_dev != st.st_dev) {
	      ptr->is_far_link = 1;
	    }
	  }
	  if(st.st_uid != lst.st_uid) { ptr->ud = 0x01; }
	  if(st.st_gid != lst.st_gid) { ptr->gd = 0x01; }
	} else {
	  back = 0;
	}
#endif
      }
      /* - stat64 */
#else
/* if DK_HAVE_STAT64 */
#if DK_HAVE_STAT
      /* + stat */
      struct stat st;
#if DK_HAVE_LSTAT
      struct stat lst;
#endif
      if(stat(filename, &st) == 0) {
        back = 1;
        ptr->filetype = dksf_filetype(st.st_mode);
        ptr->permissions = dksf_perm_h2dk(st.st_mode);
        ptr->inode_number = (unsigned long)(st.st_ino);
        ptr->device_number = (unsigned long)(st.st_dev);
        ptr->rdevice_number = (unsigned long)(st.st_rdev);
        ptr->size = (dk_long_long_unsigned_t)(st.st_size);
        
        if(sizeof(off_t)>sizeof(dk_long_long_unsigned_t)) {
          ptr->size_math_error =
          (((st.st_size) > ((off_t)DK_MAX_LONG_LONG_UNSIGNED)) ? 1 : 0);
          
        } else {
          ptr->size_math_error = 0;
          
        }
        ptr->number_of_links = (unsigned long)(st.st_nlink);
        ptr->uid = (long)(st.st_uid);
        ptr->gid = (long)(st.st_gid);
        ptr->ctime[0] = '\0'; ptr->atime[0] = '\0'; ptr->mtime[0]  = '\0';
	/*
        ptr->ori_ctime = st.st_ctime;
        ptr->ori_atime = st.st_atime;
        ptr->ori_mtime = st.st_mtime;
	*/
	tm = localtime(&(st.st_ctime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_ctime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_atime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_atime), tm, sizeof(STRUCTTM));
	}
	tm = localtime(&(st.st_mtime));
	if(tm) {
	  DK_MEMCPY(&(ptr->ori_mtime), tm, sizeof(STRUCTTM));
	}
#if DK_HAVE_LSTAT
        if(lstat(filename, &lst) == 0) { 
	  if(dksf_filetype(lst.st_mode) == DK_FT_SYMLINK) {
	    
	    ptr->filetype |= DK_FT_SYMLINK;
	    if(lst.st_dev != st.st_dev) {
	      ptr->is_far_link = 1;
	    }
	  }
	  if(st.st_uid != lst.st_uid) { ptr->ud = 0x01; }
	  if(st.st_gid != lst.st_gid) { ptr->gd = 0x01; }
        } else {			
	  back = 0;
	}
#endif
      }
      /* - stat */
#else
/* if DK_HAVE_STAT */
/* Problem */
#endif
/* if DK_HAVE_STAT */
#endif
/* if DK_HAVE_STAT64 */
#endif
/* if defined(WIN32) || defined(_WIN32) */
  } 
  return back;
}



int
dksf_must_rebuild DK_P2(char *,d, char *,s) {
  int back = 0;
  if((d) && (s)) {
#if defined(WIN32) || defined(_WIN32)
#if DK_HAVE__STAT64
    struct __stat64 sst, dst;
    if(_stat64(s, &sst) == 0) {
      back = 1;
      if(_stat64(d, &dst) == 0) {
        if(dst.st_mtime > sst.st_mtime) {
	  back = 0;
	}
      }
    }
#else
#if DK_HAVE__STAT32
    struct __stat32 sst, dst;
    if(_stat32(s, &sst) == 0) {
      back = 1;
      if(_stat32(d, &dst) == 0) {
        if(dst.st_mtime > sst.st_mtime) {
	  back = 0;
	}
      }
    }
#else
    struct _stat sst, dst;
    if(_stat(s, &sst) == 0) {
      back = 1;
      if(_stat(d, &dst) == 0) {
        if(dst.st_mtime > sst.st_mtime) {
	  back = 0;
	}
      }
    }
#endif
#endif
#else
#if DK_HAVE_STAT64 && DK_HAVE_LARGEFILE64_SOURCE
    struct stat64 sst, dst;
    if(stat64(s, &sst) == 0) {
      back = 1;
      if(stat64(d, &dst) == 0) {
        if(dst.st_mtime > sst.st_mtime) {
	  back = 0;
	}
      }
    }
#else
#if DK_HAVE_STAT
    struct stat sst, dst;
    if(stat(s, &sst) == 0) {
      back = 1; /* have source */
      if(stat(d, &dst) == 0) {
        if(dst.st_mtime > sst.st_mtime) {
	  back = 0; /* up to date */
	}
      }
    }
#endif
#endif
#endif
  }
  return back;
}



int
dkstat_far_link DK_P1(dk_stat_t *, ptr)
{
  int back = 0;
  if(ptr) {
    back = ptr->is_far_link;
  }
  return back;
}



dk_stat_t *
dkstat_open	DK_P1(char *, filename)
{
  dk_stat_t *back = NULL;
  
  if(filename) {
    back = dk_new(dk_stat_t,1);
    if(back) {
      dkstat_init(back);
      if(!dkstat_get(back,filename)) {
	dk_delete(back);
	back = NULL;
      }
    }
  } 
  return back;
}



void
dkstat_close	DK_P1(dk_stat_t *, ptr)
{
  
  if(ptr) {
    dk_delete(ptr);
  }
}



int
dkstat_filetype	DK_P1(dk_stat_t *, ptr)
{
  int back = 0;
  
  if(ptr) back = ptr->filetype;
  
  return back;
}



int
dkstat_permissions	DK_P1(dk_stat_t *, ptr)
{
  int back = 0;
  
  if(ptr) back = ptr->permissions;
  
  return back;
}



unsigned long
dkstat_inode	DK_P1(dk_stat_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) back = ptr->inode_number;
  
  return back;
}



unsigned long
dkstat_device	DK_P1(dk_stat_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) back = ptr->device_number;
  
  return back;
}



unsigned long
dkstat_rdevice	DK_P1(dk_stat_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) back = ptr->rdevice_number;
  
  return back;
}



unsigned long
dkstat_nlinks	DK_P1(dk_stat_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) back = ptr->number_of_links;
  
  return back;
}



dk_long_long_unsigned_t
dkstat_size	DK_P1(dk_stat_t *, ptr)
{
#if DK_HAVE_LONG_LONG_INT
  dk_long_long_unsigned_t back = 0ULL;
#else
  dk_long_long_unsigned_t back = 0UL;
#endif
  if(ptr) back = ptr->size;
#if DK_HAVE_LONG_LONG_INT
  
#else
  
#endif
  return back;
}



dk_long_long_unsigned_t
dkstat_size_ok	DK_P2(dk_stat_t *, ptr, int *,ok)
{
#if DK_HAVE_LONG_LONG_INT
  dk_long_long_unsigned_t back = 0ULL;
#else
  dk_long_long_unsigned_t back = 0UL;
#endif
  if(ptr) {
    back = ptr->size;
    if(ptr->size_math_error) {
      if(ok) {
        *ok = DK_ERR_MATH_OOR;
      }
    }
  }
#if DK_HAVE_LONG_LONG_INT
  
#else
  
#endif
  return back;
}



long
dkstat_uid	DK_P1(dk_stat_t *, ptr)
{
  long back = -1;
  if(ptr) back = ptr->uid;
  
  return back;
}



long
dkstat_gid	DK_P1(dk_stat_t *, ptr)
{
  long back = -1;
  if(ptr) back = ptr->gid;
  
  return back;
}



char *
dkstat_ctime	DK_P1(dk_stat_t *, ptr)
{
  char *back = NULL;
  if(ptr) {
    back = &(ptr->ctime[0]);
    if(!(*back)) {
      internal_time_convert(back, &(ptr->ori_ctime));
    }
  }
  
  return back;
}



char *
dkstat_atime	DK_P1(dk_stat_t *, ptr)
{
  char *back = NULL;
  if(ptr) {
    back = &(ptr->atime[0]);
    if(!(*back)) {
      internal_time_convert(back, &(ptr->ori_atime));
    }
  }
  
  return back;
}



char *
dkstat_mtime	DK_P1(dk_stat_t *, ptr)
{
  char *back = NULL;
  if(ptr) {
    back = &(ptr->mtime[0]);
    if(!(*back)) {
      internal_time_convert(back, &(ptr->ori_mtime));
    }
  }
  
  return back;
}



int
dksf_mkdir	DK_P2(char *, path, int, mode)
{
  int back = 0;
  mode_t mode_translated;
  
  if(path) {
  mode_translated = dksf_perm_dk2h(mode);
#if	DK_HAVE_MKDIR2
  if(mkdir(path, mode_translated) == 0) {
    back = 1;
  }
#else
#if	DK_HAVE_MKDIR || DK_HAVE__MKDIR
#if DK_HAVE_MKDIR
  if(mkdir(path) == 0) {
#else
  if(_mkdir(path) == 0) {
#endif
    back = 1;
  }
#endif
#endif
  }
  
  return back;
}



int
dksf_chmod	DK_P2(char *, path, int, mode)
{
  int back = 0;
  
  if(path) {
#if DK_HAVE_CHMOD
    mode_t mode_translated;
    mode_translated = dksf_perm_dk2h(mode);
    if(chmod(path, mode_translated) == 0) {
      back = 1;
    }
#endif
  } 
  
  return back;
}



int
dksf_fchmod	DK_P2(int,fd, int,mode)
{
  int back = 0;
#if DK_HAVE_FCHMOD
  mode_t mode_translated;
  mode_translated = dksf_perm_dk2h(mode);
  if(fchmod(fd, mode_translated) == 0) {
    back = 1;
  }
#endif
  return back;
}



dk_stat_t *
dkstat_new	DK_P0()
{
  dk_stat_t *back = NULL;
  
  back = dk_new(dk_stat_t,1);
  if(back) {
    dkstat_init(back);
  }
  
  return back;
}



void
dkstat_delete	DK_P1(dk_stat_t *, ptr)
{
  
  if(ptr) {
    dk_delete(ptr);
  }
}



long
dksf_getpid	DK_P0()
{
  long back = -1L;
#if DK_HAVE_GETCURRENTPROCESSID
  back = GetCurrentProcessId();
#else
#if DK_HAVE_GETPID
  back = (long)getpid();
#endif
#endif
  
  return back;
}



int
dksf_have_getpid	DK_P0()
{
int back = 0;
#if DK_HAVE_GETPID
back = 1;
#endif

return back;
}



long
dksf_getppid	DK_P0()
{
  long back = -1L;
#if DK_HAVE_GETPPID
  back = (long)getppid();
#else
  back = dksf_getpid();
#endif
  
  return back;
}



int
dksf_have_getppid	DK_P0()
{
int back = 0;
#if DK_HAVE_GETPPID
back = 1;
#endif

return back;
}



long
dksf_getuid	DK_P0()
{
long back = -1L;
#if DK_HAVE_GETUID
back = (long)getuid();
#endif

return back;
}



int
dksf_have_getuid	DK_P0()
{
int back = 0;
#if DK_HAVE_GETUID
back = 1;
#endif

return back;
}



long
dksf_getgid	DK_P0()
{
long back = -1L;
#if DK_HAVE_GETGID
back = (long)getgid();
#endif

return back;
}



int
dksf_have_getgid	DK_P0()
{
int back = 0;
#if DK_HAVE_GETGID
back = 1;
#endif

return back;
}



long
dksf_geteuid DK_P0()
{
  long back = -1L;
#if DK_HAVE_GETEUID
  back = (long)geteuid();
#endif

  return back;
}



int
dksf_have_geteuid DK_P0()
{
int back = 0;
#if DK_HAVE_GETEUID
back = 1;
#endif

return back;
}



long
dksf_getegid DK_P0()
{
  long back = -1L;
#if DK_HAVE_GETEGID
  back = (long)getegid();
#endif

  return back;
}



int
dksf_have_getegid DK_P0()
{
int back = 0;
#if DK_HAVE_GETEGID
back = 1;
#endif

return back;
}



long
dksf_getpgrp DK_P0()
{
long back = -1L;
#if DK_HAVE_GETPGRP
back = (long)getpgrp();
#endif

return back;
}



int
dksf_have_getpgrp DK_P0()
{
int back = 0;
#if DK_HAVE_GETPGRP
back = 1;
#endif

return back;
}



long
dksf_getpgid	DK_P1(long, x)
{
long back = -1L;
#if DK_HAVE_GETPGID
back = (long)getpgid((pid_t)x);
#endif

return back;
}



int
dksf_have_getpgid DK_P0()
{
int back = 0;
#if DK_HAVE_GETPGID
back = 1;
#endif

return back;
}

#if DK_HAVE_WINREG_H



/**	List of registry key and entry names to inspect.
*/
static char *subkeys_to_inspect[] = {
  "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  "System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
  "System\\CurrentControlSet\\Control\\ComputerName\\ComputerName",
  "System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName",
  "DefaultUserName",
  "Hostname",
  "Domain",
  "ComputerName",
  "System\\CurrentControlSet\\control",
  "Current User",
  "Network\\Logon",
  "username",
  "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
  "System\\CurrentControlSet\\Services\\VxD\\VNETSUP",
  "HostName",

  NULL
};



/**	Read a string from the registry.
	@param	dest	Result buffer.
	@param	dsz	Size of \a dest.
	@param	what	Indicator for registry hive and key and entry name.
*/
static
int
read_registry_string DK_P3(char *, dest, size_t, dsz, int, what)
{
  int back = 0;
  char *subkey, *entry_key;

  
  subkey = entry_key = NULL;
  switch(what) {
    case 0: {
      subkey = subkeys_to_inspect[0]; entry_key = subkeys_to_inspect[4];
    } break;
    case 1: {
      subkey = subkeys_to_inspect[1]; entry_key = subkeys_to_inspect[5];
    } break;
    case 2: {
      subkey = subkeys_to_inspect[1]; entry_key = subkeys_to_inspect[6];
    } break;
    case 3: {
      subkey = subkeys_to_inspect[3]; entry_key = subkeys_to_inspect[7];
    } break;
    case 4: {
      subkey = subkeys_to_inspect[2]; entry_key = subkeys_to_inspect[7];
    } break;
    case 5: { /* HKLM/System/CurrentControlSet/control:Current User */
      subkey = subkeys_to_inspect[8]; entry_key = subkeys_to_inspect[9];
    } break;
    case 6: { /* HKLM/Network/Logon:username */
      subkey = subkeys_to_inspect[10]; entry_key = subkeys_to_inspect[11];
    } break;
    case 7: { /* HKLM/System/CurrentControlSet/Services/VxD/MSTCP:HostName */
      subkey = subkeys_to_inspect[12]; entry_key = subkeys_to_inspect[14];
    } break;
    case 8: {
      /* HKLM/System/CurrentControlSet/Services/VxD/VNETSUP:ComputerName */
      subkey = subkeys_to_inspect[13]; entry_key = subkeys_to_inspect[7];
    } break;
    case 9: {
     subkey = subkeys_to_inspect[12]; entry_key = subkeys_to_inspect[6];
    } break;
  } 
  if(subkey && entry_key) {
    HKEY hklmsl; PHKEY phkSubkey;
    DWORD disp, dwType, sz; LONG retval;
    phkSubkey = &hklmsl;
    retval = RegCreateKeyExA(
      HKEY_LOCAL_MACHINE, subkey,
      0, NULL, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE,
      NULL, phkSubkey, &disp
    );
    if(retval == ERROR_SUCCESS) { 
      sz = dsz;
      retval = RegQueryValueExA(
	hklmsl, entry_key, NULL, &dwType, dest, &sz
      );
      if(retval == ERROR_SUCCESS) { 
	if(sz < dsz) { 
	  dest[sz] = '\0'; back = 1;
	}
      } else { 
      }
    } else { 
    }
  } 
  return back;
}



#endif

#if DK_HAVE_GETPWUID || DK_HAVE_GETPWENT
/**	Save information to buffer.
	@param	buffer	Result buffer.
	@param	sz	Size of \a buffer.
	@param	who	0=UID, 1=effective UID.
	@param	how	0=LOGNAME, 1=HOME.
	@return	1 on success, 0 on error.
*/
static
int
fill_buffer	DK_P4(char *, buffer, size_t, sz, int, who, int, how)
{
  int back = 0;
#if DK_HAVE_GETUID
  uid_t uid;
  struct passwd *pw;
#if !DK_HAVE_SETPWENT
  struct passwd *xpw;
#endif
#if DK_HAVE_GETEUID
  uid = (who ? getuid() : geteuid());
#else
  uid = getuid();
#endif
#if DK_HAVE_GETPWUID
  pw = getpwuid(uid);
#else
  pw = NULL;
#if DK_HAVE_SETPWENT
  setpwent();
#endif
  xpw = getpwent();
  while((!pw) & (xpw)) {
    if(xpw->pw->uid == uid) {
      pw = xpw;
    }
    if(!pw) {
      xpw = getpwent();
    }
  }
#endif
  switch(how) {
    case 1: {	/* HOME */
      if(pw->pw_dir) {
	if(strlen(pw->pw_dir) < sz) {
	  back = 1;
	  strcpy(buffer, pw->pw_dir);
	}
      }
    } break;
    case 0: {	/* LOGNAME */
      if(pw->pw_name) {
	if(strlen(pw->pw_name) < sz) {
	  back = 1;
	  strcpy(buffer, pw->pw_name);
	}
      }
    } break;
  }
#if (!DK_HAVE_GETPWUID) && DK_HAVE_GETENDPWENT
  endpwent();
#endif
#else
  /* So what */
#endif
  
  return back;
}

#endif



int
dksf_get_uname	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  
  if(buffer) {
  if(sz) {
#if DK_HAVE_GETPWUID || DK_HAVE_GETPWENT
    back = fill_buffer(buffer, sz, 1, 0);
#else
    char *x;
#if DK_HAVE_GETUSERNAME
    DWORD xs;
    xs = sz;
    if(GetUserNameA(buffer,&xs)) {
      back = 1;
      if(xs >= sz) {
	xs--;
      }
      buffer[(size_t)xs] = '\0';
    }
#endif
#if DK_HAVE_WINREG_H
    /* Windows NT 4.0 Workstation */
    if(!back) {
      back = read_registry_string(buffer,sz,0);
    }
    if(!back) {
      back = read_registry_string(buffer,sz,6);
    }
    if(!back) {
      back = read_registry_string(buffer,sz,5);
    }
#endif
    if(!back) {
    x = getenv("LOGNAME");
    if(x) {
      if(strlen(x) < sz) {
	back = 1;
	strcpy(buffer, x);
      }
    }
    }
    if(!back) {
    x = getenv("USERNAME");
    if(x) {
      if(strlen(x) < sz) {
	back = 1;
	strcpy(buffer, x);
      }
    }
    }
#endif
  }
  } 
  return back;
}



int
dksf_get_euname	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  
  if(buffer) {
  if(sz) {
#if DK_HAVE_GETPWUID || DK_HAVE_GETPWENT
    back = fill_buffer(buffer, sz, 0, 0);
#else
    char *x;
#if DK_HAVE_GETUSERNAME
    DWORD xs;
    xs = sz;
    if(GetUserNameA(buffer,&xs)) {
      back = 1;
      if(xs >= sz) {
	xs--;
      }
      buffer[(size_t)xs] = '\0';
    }
#endif
#if DK_HAVE_WINREG_H
    back = read_registry_string(buffer,sz,0);
#endif
    if(!back) {
    x = getenv("LOGNAME");
    if(x) {
      if(strlen(x) < sz) {
	back = 1;
	strcpy(buffer, x);
      }
    }
    }
    if(!back) {
    x = getenv("USERNAME");
    if(x) {
      if(strlen(x) < sz) {
	back = 1;
	strcpy(buffer, x);
      }
    }
    }
#endif
  }
  } 
  return back;
}



#if !(DK_HAVE_GETPWUID || DK_HAVE_GETPWENT)
/**	Attempt to construct home directory name from environment variables.
	@param	buffer	Result buffer.
	@param	sz	Size of \a buffer.
	@return	1 on success, 0 on error.
*/
static
int
try_home_from_env	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  char *x;
#if DK_HAVE_FEATURE_BACKSLASH
  char *y;
#endif
  x = getenv("HOME");
  if(x) {
    if(strlen(x) < sz) {
      back = 1; strcpy(buffer,x);
    }
  }
  if(!back) {
#if DK_HAVE_FEATURE_BACKSLASH
    x = getenv("USERPROFILE");
    if(x) {
      if(strlen(x) < sz) {
	back = 1; strcpy(buffer,x);
      }
    }
#endif
  }
  if(!back) {
#if DK_HAVE_FEATURE_BACKSLASH
    x = getenv("HOMEDRIVE"); y = getenv("HOMEPATH");
    if(x && y) {
      if((strlen(x) + strlen(y) + strlen(path_component_separator)) < sz) {
	back = 1;
	strcpy(buffer,x);
	if(y[0] != path_component_separator[0]) {
	  strcat(buffer, path_component_separator);
	}
	strcat(buffer,y);
      }
    }
#endif
  }
  return back;
}
#endif



/**	Get home directory.
	@param	buffer	Result buffer.
	@param	sz	Size of \a buffer.
	@return	1 on success, 0 on error.
*/
static
int
internal_get_home	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  
  if(buffer) {
  if(sz) {
#if DK_HAVE_GETPWUID || DK_HAVE_GETPWENT
    back = fill_buffer(buffer, sz, 1, 1);
#else
    back = try_home_from_env(buffer,sz);
#endif
  }
  } 
  return back;
}



/**	Check permissions to temporary directory.
	@param	buffer	Result buffer.
	@param	sz	Size of \a buffer.
	@param	x	Candidate for temprary directory.
	@return	1 on success, 0 on error.
*/
static
int
check_temp_dir	DK_P3(char *, buffer, size_t, sz, char *, x)
{
  int back = 0;
  dk_stat_t st;
  
  if(dkstat_get(&st,x)) {
    int ft; 
    ft = dkstat_filetype(&st);
    ft &= (~DK_FT_SYMLINK);
    if(ft == DK_FT_DIR) {
      if(strlen(x) < sz) {
	back = 1;
	/* strcpy(buffer,x); */
      }
    }
  }
  if(!back) {
    (void)dksf_mkdir(x, DK_PERM_CREATE_DIR);
  }
  if(dkstat_get(&st,x)) {
    int ft;
    ft = dkstat_filetype(&st);
    ft &= (~DK_FT_SYMLINK);
    if(ft == DK_FT_DIR) {
      if(strlen(x) < sz) {
      back = 1;
      /* strcpy(buffer,x); */
      }
    }
  } 
  return back;
}



/**	Environment variables to inspect for temporary files directory.
*/
static char *variables_to_check[] = {
  "TMPDIR", "TEMP", "TMP",
  NULL
};



/**	Find temporary directory.
	@param	buffer	Buffer for result.
	@param	sz	Size of \a buffer.
	@return	1 on success, 0 on error.
*/
static
int
internal_get_tempdir	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  
  if(buffer) {
  if(sz) {
    char c, *p1, *p2, *p3, *vptr, **kptr;
    kptr = variables_to_check;
    while((*kptr) && (!back)) {
      vptr = getenv(*kptr);
      if(vptr) {
        if(strlen(vptr) < sz) {
	  strcpy(buffer, vptr);
	  if(dkstr_chr(buffer, ';')) {
	    p1 = buffer;
	    while((p1) && (!back)) {
	      p2 = dkstr_chr(p1, ';');
	      if(p2) { *(p2++) = '\0'; }
	      back = check_temp_dir(buffer, sz, p1);
	      if(back) {
	        p3 = buffer;
		while(*p1) {
		  c = *(p1++);
		  *(p3++) = c;
		}
		*p3 = '\0';
	      }
	      p1 = p2;
	    }
	  } else {
	    back = check_temp_dir(buffer, sz, vptr);
	    if(back) {
	      strcpy(buffer, vptr);
	    }
	  }
	}
      }
      kptr++;
    }
#if DK_HAVE_FEATURE_BACKSLASH
    if(!back) {
      char *x;
      x = getenv("SystemDrive");
      if(x) {
	if((strlen(x) + strlen(temp_string)) < sz) {
	  strcpy(buffer,x);
	  strcat(buffer,temp_string);
	  back = check_temp_dir(buffer,sz,buffer);
	}
      }
      if(!back) {
      x = getenv("SystemRoot");
      if(x) {
	if((strlen(x) + strlen(temp_string)) < sz) {
	  strcpy(buffer,x);
	  strcat(buffer,temp_string);
	  back = check_temp_dir(buffer,sz,buffer);
	}
      }
      }
      if(!back) {
      x = getenv("windir");
      if(x) {
	if((strlen(x) + strlen(temp_string)) < sz) {
	  strcpy(buffer,x);
	  strcat(buffer,temp_string);
	  back = check_temp_dir(buffer,sz,buffer);
	}
      }
      }
    }
#endif
  }
  } 
  return back;
}



int
dksf_get_ehome	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  
  if(buffer) {
  if(sz) {
#if DK_HAVE_GETPWUID || DK_HAVE_GETPWENT
    back = fill_buffer(buffer, sz, 0, 1);
#else
    back = try_home_from_env(buffer,sz);
#endif
    if(!back) { back = internal_get_tempdir(buffer,sz); }
  }
  } 
  return back;
}



int
dksf_get_hostname	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
#if DK_HAVE_GETCOMPUTERNAME
  size_t xs;
#endif
  
  if(buffer) {
  if(sz) {
#if DK_HAVE_SYS_SYSTEMINFO
#if DK_HAVE_SYSINFO
#ifdef SI_HOSTNAME
    long l;
    l = sysinfo(SI_HOSTNAME, buffer, sz);
    if((l > 0L) && (l <= sz)) {
      back = 1;
    }
#endif
#endif
#endif
#if DK_HAVE_GETCOMPUTERNAME
    xs = sz;
    if(!back) {
      if(GetComputerNameA(buffer,&xs)) {
	if(xs >= sz) {
	  xs--;
	}
	buffer[(size_t)xs] = '\0';
	back = 1;
      }
    }
#endif
#if DK_HAVE_GETHOSTNAME
    if(!back) {
    if(gethostname(buffer, (int)sz) == 0) {
      back = 1;
      buffer[(sz-1UL)] = '\0';
    }
    }
#endif
    if(!back) {
#if DK_HAVE_WINREG_H
    /* Windows NT 4.0 Workstation */
    back = read_registry_string(buffer,sz,1);
    if(!back) {
      back = read_registry_string(buffer,sz,3);
    }
    if(!back) {
      back = read_registry_string(buffer,sz,4);
    }
    /* Windows 95 */
    if(!back) {
      back = read_registry_string(buffer,sz,7);
    }
    if(!back) {
      back = read_registry_string(buffer,sz,8);
    }
#endif
    }
    if(!back) {
      char *x;
      x = getenv("COMPUTERNAME");
      if(x) {
	if(strlen(x) < sz) {
	  back = 1;
	  strcpy(buffer,x);
	}
      }
    }
  }
  } 
  return back;
}



int
dksf_get_home	DK_P2(char *, buffer, size_t, sz)
{
  int back;
  back = internal_get_home(buffer,sz);
  if(!back) { back = internal_get_tempdir(buffer,sz); }
  return back;
}



int
dksf_get_tempdir	DK_P2(char *, buffer, size_t, sz)
{
  int back;
  back = internal_get_tempdir(buffer,sz);
  if(!back) { back = internal_get_home(buffer,sz); }
  return back;
}



int
dksf_get_domainname	DK_P2(char *, buffer, size_t, sz)
{
  int back = 0;
  
  if(buffer) {
  if(sz) {
#if DK_HAVE_SYS_SYSTEMINFO_H
    long l;
    
#if DK_HAVE_SYSINFO
    
#ifdef SI_SYSNAME
    
    l = sysinfo(SI_SRPC_DOMAIN, buffer, sz);
    if((l > 0L) && (l <= sz)) {
      back = 1;
    }
#else
#endif
#else
#endif
#else
#endif
    if(!back) {
#if DK_HAVE_WINREG_H
      /* Windows NT 4.0 Workstation */
      back = read_registry_string(buffer,sz,2);
      /* Windows 95 */
      if(!back) {
	back = read_registry_string(buffer,sz,9);
      }
#endif
    }
  }
  } 
  return back;
}



long
dksf_get_maxpathlen	DK_P0()
{
  long back = MY_MAXPATHLEN;
  return back;
}



long
dksf_get_maxfiles	DK_P0()
{
  long back = 1024L;
#if DK_HAVE_SYS_RESOURCE_H
#if DK_HAVE_GETRLIMIT
  struct rlimit rl;
  if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
    if(rl.rlim_max != RLIM_INFINITY) {
      back = (long)(rl.rlim_max);
    }
  }
#endif
#endif
  return back;
}



/**	Directory state: Not yet initialized.
*/
#define DIR_STATE_UNUSED	0

/**	Directory state: Initialized.
*/
#define DIR_STATE_INITIALIZED	1

/**	Directory state: Opened.
*/
#define DIR_STATE_OPENED	2

/**	Directory state: End of directory reached.
*/
#define DIR_STATE_WRAPPED	3

/**	Directory state: Closed.
*/
#define DIR_STATE_CLOSED	4



/**	Get file properties.
	@param	ptr	Directory.
	@param	shortname	File name.
	@return	1 on success, 0 on error.
*/
static
int
get_file_properties DK_P2(dk_dir_t *, ptr, char *, shortname) {
  int back = 0;
  size_t lgt, lgtx;
  if((long)strlen(shortname) < ptr->maxpathlen) {
    strcpy(ptr->shortname, shortname);
    strcpy(ptr->fullname, ptr->dirname);
    lgt = lgtx = strlen(ptr->dirname);
    lgt += strlen(path_component_separator);
    lgt += strlen(shortname);
    if((long)lgt < ptr->maxpathlen) {
      if(((ptr->dirname)[lgtx - 1]) != path_component_separator[0]) {
        strcat(ptr->fullname, path_component_separator);
      }
      strcat(ptr->fullname, shortname);
      if(dkstat_get(&(ptr->stbuf), ptr->fullname)) {
	back = 1;
      }
    } else {					
    }
  } else {					
  }
  return back;
}



int
dkdir_start_search DK_P2(dk_dir_t *, ptr, char *, name) {
  int back = 0;
  
  if((ptr) && (name)) {		
    switch(ptr->state) {
      case DIR_STATE_UNUSED: case DIR_STATE_CLOSED: {
        if((long)strlen(name) < ptr->maxpathlen) {
	  strcpy(ptr->dirname, name);
	  ptr->state = DIR_STATE_INITIALIZED;
	  back = 1;
	} else {		
	}
      } break;
      default: {		
      } break;
    }
  } else {			
  } 
  return back;
}




#if defined(WIN32) || defined(_WIN32)
/* + Win32 */
#if DK_HAVE__FINDFIRST64
/* Win32, _findfirst64 */



void
dkdir_end_search DK_P1(dk_dir_t *,ptr) {
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_OPENED: case DIR_STATE_WRAPPED: {
        _findclose(ptr->hFile64);
	ptr->hFile64 = -1L;
      } break;
      default: {	
      } break;
    }
  } 
}



int
dkdir_next DK_P1(dk_dir_t *, ptr) {
  int back = 0;
  size_t	lgt;
  size_t	lgtx;
  size_t	lgty;
  int		i;
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_INITIALIZED: {	
        lgt = strlen(ptr->dirname); lgtx = lgty = lgt;
	if(lgt > 0) {
	  lgt += strlen(path_component_separator);
	  lgt += strlen(all_files);
	  if((long)lgt < ptr->maxpathlen) {
	    if(((ptr->dirname)[lgtx - 1]) != path_component_separator[0]) {
	      strcat(ptr->dirname, path_component_separator);
	    }
	    strcat(ptr->dirname, all_files);
	    ptr->hFile64 = _findfirst64(ptr->dirname, &(ptr->fdt64));
	    (ptr->dirname)[lgtx] = '\0';
	    if(ptr->hFile64 != -1L) {
	      /* back = get_file_properties(ptr, (ptr->fdt64).name); */
	      back = 1;
	      if(!get_file_properties(ptr, (ptr->fdt64).name)) {
	        back = -1;
	      }
	      ptr->state = DIR_STATE_OPENED;
	    } else {			
	    }
	  } else {			
	  }
	} else {			
	}
      } break;
      case DIR_STATE_OPENED: {		
        i = _findnext64(ptr->hFile64, &(ptr->fdt64));
	if(i == 0) {
	  /* back = get_file_properties(ptr, (ptr->fdt64).name); */
	  back = 1;
	  if(!get_file_properties(ptr, (ptr->fdt64).name)) {
	    back = -1;
	  }
	} else {
	  _findclose(ptr->hFile64); ptr->hFile64 = -1L;
	  ptr->state = DIR_STATE_CLOSED;
	}
      } break;
      default: {			
      } break;
    }
  } 
  return back;
}



/**	Initialize new directory.
	@param	ptr	Directory to initialize.
*/
static
void
init_new_directory DK_P1(dk_dir_t *,ptr) {
  ptr->hFile64 = -1L;
}

#else
#if DK_HAVE__FINDFIRST32
/* Win32, _findfirst32 */



void
dkdir_end_search DK_P1(dk_dir_t *,ptr) {
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_OPENED: case DIR_STATE_WRAPPED: {
        _findclose(ptr->hFile32);
	ptr->hFile = -1L;
      } break;
      default: {	
      } break;
    }
  } 
}



int
dkdir_next DK_P1(dk_dir_t *, ptr) {
  int back = 0;
  size_t	lgt;
  size_t	lgtx;
  size_t	lgty;
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_INITIALIZED: {	
        lgt = strlen(ptr->dirname); lgtx = lgty = lgt;
	if(lgt > 0) {
	  lgt += strlen(path_component_separator);
	  lgt += strlen(all_files);
	  if((long)lgt < ptr->maxpathlen) {
	    if(((ptr->dirname)[lgtx - 1]) != path_component_separator[0]) {
	      strcat(ptr->dirname, path_component_separator);
	    }
	    strcat(ptr->dirname, all_files);
	    ptr->hFile32 = _findfirst32(ptr->dirname, &(ptr->fdt32));
	    (ptr->dirname)[lgtx] = '\0';
	    if(ptr->hFile32 != -1L) {
	      /* back = get_file_properties(ptr, (ptr->fdt32).name); */
	      back = 1;
	      if(!get_file_properties(ptr, (ptr->fdt32).name)) {
	        back = -1;
	      }
	      ptr->state = DIR_STATE_OPENED;
	    } else {			
	    }
	  } else {			
	  }
	} else {			
	}
      } break;
      case DIR_STATE_OPENED: {		
        i = _findnext32(ptr->hFile32, &(ptr->fdt32));
	if(i == 0) {
	  /* back = get_file_properties(ptr, (ptr->fdt32).name); */
	  back = 1;
	  if(!get_file_properties(ptr, (ptr->fdt32).name)) {
	    back = -1;
	  }
	} else {
	  _findclose(ptr->hFile32); ptr->hFile32 = -1L;
	  ptr->state = DIR_STATE_CLOSED;
	}
      } break;
      default: {			
      } break;
    }
  } 
  return back;
}



/**	Initialize new directory.
	@param	ptr	Directory to initialize.
*/
static
void
init_new_directory DK_P1(dk_dir_t *,ptr) {
  ptr->hFile32 = -1L;
}


#else
#if DK_HAVE__FINDFIRST
/* Win32, _findfirst */



void
dkdir_end_search DK_P1(dk_dir_t *,ptr) {
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_OPENED: case DIR_STATE_WRAPPED: {
        _findclose(ptr->hFile);
	ptr->hFile = -1L;
      } break;
      default: {	
      } break;
    }
  } 
}



int
dkdir_next DK_P1(dk_dir_t *, ptr) {
  int back = 0;
  size_t	lgt;
  size_t	lgtx;
  size_t	lgty;
  int		i;
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_INITIALIZED: {	
        lgt = strlen(ptr->dirname); lgtx = lgty = lgt;
	if(lgt > 0) {
	  lgt += strlen(path_component_separator);
	  lgt += strlen(all_files);
	  if((long)lgt < ptr->maxpathlen) {
	    if(((ptr->dirname)[lgtx - 1]) != path_component_separator[0]) {
	      strcat(ptr->dirname, path_component_separator);
	    }
	    strcat(ptr->dirname, all_files);
	    ptr->hFile = _findfirst(ptr->dirname, &(ptr->fdt));
	    (ptr->dirname)[lgtx] = '\0';
	    if(ptr->hFile != -1L) {
	      /* back = get_file_properties(ptr, (ptr->fdt).name); */
	      back = 1;
	      if(!get_file_properties(ptr, (ptr->fdt).name)) {
	        back = -1;
	      }
	      ptr->state = DIR_STATE_OPENED;
	    } else {			
	    }
	  } else {			
	  }
	} else {			
	}
      } break;
      case DIR_STATE_OPENED: {		
        i = _findnext(ptr->hFile, &(ptr->fdt));
	if(i == 0) {
	  /* back = get_file_properties(ptr, (ptr->fdt).name); */
	  back = 1;
	  if(!get_file_properties(ptr, (ptr->fdt).name)) {
	    back = -1;
	  }
	} else {
	  _findclose(ptr->hFile); ptr->hFile = -1L;
	  ptr->state = DIR_STATE_CLOSED;
	}
      } break;
      default: {			
      } break;
    }
  } 
  return back;
}



/**	Initialize new directory.
	@param	ptr	Directory to initialize.
*/
static
void
init_new_directory DK_P1(dk_dir_t *,ptr) {
  ptr->hFile = -1L;
}

#endif
#endif
#endif
/* - Win32 */
#else
#if DK_HAVE_FINDFIRST
/* DOS, findfirst */



void
dkdir_end_search DK_P1(dk_dir_t *,ptr) {
  int i;
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_OPENED: case DIR_STATE_WRAPPED: {
        i = 0;
	while(!i) { i = findnext(&(ptr->dir)); }
      } break;
      default: {	
      } break;
    }
  } 
}



int
dkdir_next DK_P1(dk_dir_t *, ptr) {
  int back = 0;
  size_t	lgt;
  size_t	lgtx;
  size_t	lgty;
  int		i;
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_INITIALIZED: {	
        lgt = strlen(ptr->dirname);
	if(lgt > 0) {
	  lgtx = lgty = lgt;
	  lgt += strlen(all_files);
	  lgt += strlen(path_component_separator);
	  if(lgt < ptr->maxpathlen) {
	    if((ptr->dirname)[lgtx - 1] != path_component_separator[0]) {
	      strcat(ptr->dirname, path_component_separator);
	    }
	    strcat(ptr->dirname, all_files);
	    i = findfirst(ptr->dirname, &(ptr->dir), FA_DIREC);
	    (ptr->dirname)[lgty] = '\0';
	    if(i == 0) {
	      /* back = get_file_properties(ptr, (ptr->dir).ff_name); */
	      back = 1;
	      if(!get_file_properties(ptr, (ptr->dir).ff_name)) {
	        back = -1;
	      }
	      ptr->state = DIR_STATE_OPENED;
	    } else {			
	    }
	  } else {			
	  }
	} else {			
	}
      } break;
      case DIR_STATE_OPENED: {		
        i = findnext(&(ptr->dir));
	if(i == 0) {
	  /* back = get_file_properties(ptr, (ptr->dir).ff_name); */
	  back = 1;
	  if(!get_file_properties(ptr, (ptr->dir).ff_name)) {
	    back = -1;
	  }
	} else {
	  ptr->state = DIR_STATE_CLOSED;
	}
      } break;
      default: {			
      } break;
    }
  } 
  return back;
}



/**	Initialize new directory.
	@param	ptr	Directory to initialize.
*/
static
void
init_new_directory DK_P1(dk_dir_t *,ptr) {
}

#else
#if DK_HAVE_DIRENT_H
/* UNIX/Linux, dirent */



void
dkdir_end_search DK_P1(dk_dir_t *,ptr) {
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_OPENED: case DIR_STATE_WRAPPED: {
        closedir(ptr->dir); ptr->dir = NULL; 
	ptr->state = DIR_STATE_CLOSED;
      } break;
      default: {	
      } break;
    }
  } 
}

int
dkdir_next DK_P1(dk_dir_t *, ptr) {
  int back = 0;
  struct dirent *de;
  
  if(ptr) {
    switch(ptr->state) {
      case DIR_STATE_INITIALIZED: {	
        if(strlen(ptr->dirname)) {
	  ptr->dir = opendir(ptr->dirname);
	  if(ptr->dir) {
	    de = readdir(ptr->dir);
	    if(de) {
	      ptr->state = DIR_STATE_OPENED;
	      back = 1;
	      /* back = get_file_properties(ptr, de->d_name); */
	      if(!get_file_properties(ptr, de->d_name)) {
	        back = -1;
	      }
	    } else {			
	      closedir(ptr->dir); ptr->dir = NULL;
	      ptr->state = DIR_STATE_CLOSED;
	    }
	  } else {			
	  }
	} else {			
	}
      } break;
      case DIR_STATE_OPENED: {		
        de = readdir(ptr->dir);
	if(de) {
	  /* back = get_file_properties(ptr, de->d_name); */
	  back = 1;
	  if(!get_file_properties(ptr, de->d_name)) {
	    back = -1;
	  }
	} else {
	  closedir(ptr->dir); ptr->dir = NULL;
	  ptr->state = DIR_STATE_CLOSED;
	}
      } break;
      default: {			
      } break;
    }
  } 
  return back;
}



/**	Initialize a new directory.
	@param	ptr	Directory to initialize.
*/
static
void
init_new_directory DK_P1(dk_dir_t *,ptr) {
  ptr->dir = NULL;
}

#else
/* any unknown directory listing mechanism */
#endif
#endif
#endif



void
dkdir_delete	DK_P1(dk_dir_t *, ptr)
{
  if(ptr) {
    char *p;
    p = ptr->dirname; if(p) { dk_delete(p); }
    p = ptr->fullname; if(p) { dk_delete(p); }
    p = ptr->shortname; if(p) { dk_delete(p); }
    ptr->dirname = ptr->fullname = ptr->shortname = NULL;
    dk_delete(ptr);
  }
}



dk_dir_t *
dkdir_new DK_P0() {
  dk_dir_t *back = NULL;
  long ml;
  back = dk_new(dk_dir_t,1);
  if(back) {
    char *ptr;
    back->error_code = DK_ERR_NONE;
    back->dirname = back->fullname = back->shortname = NULL;
    ml = back->maxpathlen = dksf_get_maxpathlen();
    back->state = DIR_STATE_UNUSED;
    ptr = dk_new(char,ml); if(ptr) { back->dirname = ptr; }
    ptr = dk_new(char,ml); if(ptr) { back->fullname = ptr; }
    ptr = dk_new(char,ml); if(ptr) { back->shortname = ptr; }
    if(!((back->dirname) && (back->fullname) && (back->shortname))) {
      dkdir_delete(back);
      back = NULL;
    } else {
      *(back->dirname) = '\0';
      *(back->fullname) = '\0';
      *(back->shortname) = '\0';
      init_new_directory(back);
    }
  }
  return back;
}



void
dkdir_close	DK_P1(dk_dir_t *, ptr)
{
  if(ptr) {
    dkdir_end_search(ptr);
    dkdir_delete(ptr);
  }
}



dk_dir_t *
dkdir_open	DK_P1(char *, name)
{
  dk_dir_t *back = NULL;
  if(name) {
    back = dkdir_new();
    if(back) {
      if(!dkdir_start_search(back,name)) {
				
        dkdir_close(back);
        back = NULL;
      }
    } else {			
    }
  } else {			
  }
  return back;
}



char *
dkdir_get_fullname(dk_dir_t *ptr)
{
  char *back = NULL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = ptr->fullname;
    }
  }
  return back;
}



char *
dkdir_get_shortname(dk_dir_t *ptr)
{
  char *back = NULL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = ptr->shortname;
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



long
dkdir_uid DK_P1(dk_dir_t *, ptr)
{
  long back = 0L;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_uid(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



long
dkdir_gid DK_P1(dk_dir_t *, ptr)
{
  long back = 0L;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_gid(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



char	 *
dkdir_ctime DK_P1(dk_dir_t *, ptr)
{
  char *back = NULL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_ctime(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



char	 *
dkdir_atime DK_P1(dk_dir_t *, ptr)
{
  char *back = NULL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_atime(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



char	 *
dkdir_mtime DK_P1(dk_dir_t *, ptr)
{
  char *back = NULL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_mtime(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



int
dkdir_filetype DK_P1(dk_dir_t *, ptr)
{
  int back = 0;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_filetype(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



int
dkdir_permissions DK_P1(dk_dir_t *, ptr)
{
  int back = 0;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_permissions(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



unsigned long
dkdir_inode DK_P1(dk_dir_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_inode(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



unsigned long
dkdir_device DK_P1(dk_dir_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_device(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



unsigned long
dkdir_rdevice DK_P1(dk_dir_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_rdevice(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



unsigned long
dkdir_nlinks DK_P1(dk_dir_t *, ptr)
{
  unsigned long back = 0UL;
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_nlinks(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



dk_long_long_unsigned_t
dkdir_size DK_P1(dk_dir_t *, ptr)
{
#if DK_HAVE_LONG_LONG_INT
  dk_long_long_unsigned_t back = 0ULL;
#else
  dk_long_long_unsigned_t back = 0UL;
#endif
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_size(&(ptr->stbuf));
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}



dk_long_long_unsigned_t
dkdir_size_ok DK_P2(dk_dir_t *, ptr, int *, ok)
{
#if DK_HAVE_LONG_LONG_INT
  dk_long_long_unsigned_t back = 0ULL;
#else
  dk_long_long_unsigned_t back = 0UL;
#endif
  if(ptr) {
    if(ptr->state == DIR_STATE_OPENED) {
      back = dkstat_size_ok(&(ptr->stbuf), ok);
    } else {
      ptr->error_code = DK_ERR_NOT_NOW;
    }
  }
  return back;
}


/**     File name expander state: Not yet initialized.
*/
#define FNE_STATE_UNUSED 0

/**     File name expander state: Initialized.
*/
#define FNE_STATE_INITIALIZED 1

/**     File name expander state: Opened.
*/
#define FNE_STATE_OPENED      2

/**     File name expander state: Closed.
*/
#define FNE_STATE_CLOSED      3

/**     File name expander state: Search for directories.
*/
#define FNE_DIRS        8

/**     File name expander state: Search for files.
*/
#define FNE_FILES       16

/**	File name expander state: Must run.
*/
#define FNE_MUST_RUN	32



/**	File name expander state: Not yet initialized.
*/
#define FNE_NOT_STATE (FNE_DIRS | FNE_FILES | FNE_MUST_RUN)



/**	Correct a directory name.
	@param	name	Buffer containing the file name.
*/
static
void
correct_dir_name DK_P1(char *, name)
{
  char *ptr;
  ptr = name;
  while(*ptr) {
#if DK_HAVE_FEATURE_BACKSLASH
    if(*ptr == '/') { *ptr = '\\'; }
#else
    if(*ptr == '\\') { *ptr = '/'; }
#endif
    ptr++;
  }
}



dk_fne_t *
dkfne_open	DK_P3(char *, name, int, files, int, dirs)
{
  dk_fne_t *back = NULL;
  
  if(name && (files || dirs)) {
    if(strlen(name) > 0) {
    back = dkdir_new();
    if(back) {
      if((long)strlen(name) < back->maxpathlen) {
	strcpy(back->dirname, name);
	correct_dir_name(back->dirname);
	back->state = FNE_STATE_INITIALIZED;
	if(files) { back->state |= FNE_FILES; }
	if(dirs)  { back->state |= FNE_DIRS; }
#if USE_FNE
	if(dkstr_chr(name, '*')) {
	  back->state |= FNE_MUST_RUN;
	} else {
	  if(dkstr_chr(name, '?')) {
	    back->state |= FNE_MUST_RUN;
	  }
	}
#endif
      } else {					
	dkdir_delete(back);
	back = NULL;
      }
    } else {					
    }
    } else {					
    }
  } else {					
  } 
  return back;
}



/**	Find one file name matching a pattern.
	@param	f	File name expander.
	@return	1 on success, 0 on error.
*/
static
int
dkfne_find_one	DK_P1(dk_fne_t *, f)
{
  int back = 0;
  char *ptr;
  
  if(f) {
    (f->fullname)[0] = '\0';
    (f->shortname)[0] = '\0';
    if(f->state & FNE_MUST_RUN) {		
#if USE_FNE
      switch(f->state & (~(FNE_NOT_STATE))) {
	case FNE_STATE_INITIALIZED: {
#if defined(WIN32) || defined(_WIN32)
/* + Win32 */
#if DK_HAVE__FINDFIRST64
/* Win32, _findfirst64 */
          f->hFile64 = _findfirst64(f->dirname, &(f->fdt64));
	  if(f->hFile64 != -1L) {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_OPENED);
	    if((long)strlen((f->fdt64).name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->fdt64).name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_NO_SUCH_FILE;
	  }
#else
#if DK_HAVE__FINDFIRST32
/* Win32, _findfirst32 */
          f->hFile32 = _findfirst32(f->dirname, &(f->fdt32));
	  if(f->hFile32 != -1L) {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_OPENED);
	    if((long)strlen((f->fdt32).name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->fdt).name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_NO_SUCH_FILE;
	  }
#else
#if DK_HAVE__FINDFIRST
/* Win32, _findfirst */
          f->hFile = _findfirst(f->dirname, &(f->fdt));
	  if(f->hFile != -1L) {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_OPENED);
	    if((long)strlen((f->fdt).name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->fdt).name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_NO_SUCH_FILE;
	  }
#endif
#endif
#endif
/* - Win32 */
#else
#if DK_HAVE_FINDFIRST
/* DOS, findfirst */
          int i;
	  i = findfirst(f->dirname, &(f->dir), ((f->state & FNE_FILES) ? FA_DIREC : 0));
	  if(i == 0) {
	    if(strlen((f->dir).ff_name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->dir).ff_name);
	      
	      back = 1;
	      f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_OPENED);
	    } else {
	      f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_NO_SUCH_FILE;
	  }
#else
#if DK_HAVE_DIRENT_H
/* UNIX/Linux, dirent */
#else
/* any unknown directory listing mechanism */
#endif
#endif
#endif
	} break;
	case FNE_STATE_OPENED: {
	  int i;
#if defined(WIN32) || defined(_WIN32)
/* + Win32 */
#if DK_HAVE__FINDFIRST64
/* Win32, _findfirst64 */
	  i = _findnext64(f->hFile64, &(f->fdt64));
	  if(i == 0) {
	    if((long)strlen((f->fdt64).name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->fdt64).name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    _findclose(f->hFile64); f->hFile64 = -1L;
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_FINISHED;
	  }
#else
#if DK_HAVE__FINDFIRST32
/* Win32, _findfirst32 */
	  i = _findnext32(f->hFile32, &(f->fdt32));
	  if(i == 0) {
	    if((long)strlen((f->fdt32).name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->fdt32).name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    _findclose(f->hFile32); f->hFile32 = -1L;
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_FINISHED;
	  }
#else
#if DK_HAVE__FINDFIRST
/* Win32, _findfirst */
	  i = _findnext(f->hFile, &(f->fdt));
	  if(i == 0) {
	    if((long)strlen((f->fdt).name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->fdt).name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    _findclose(f->hFile); f->hFile = -1L;
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	    f->error_code = DK_ERR_FINISHED;
	  }
#endif
#endif
#endif
/* - Win32 */
#else
#if DK_HAVE_FINDFIRST
/* DOS, findfirst */
	  i = findnext(&(f->dir));
	  if(i == 0) {
	    if(strlen((f->dir).ff_name) < f->maxpathlen) {
	      strcpy(f->shortname, (f->dir).ff_name);
	      
	      back = 1;
	    } else {
	      f->error_code = DK_ERR_STRING_TOO_LONG;
	    }
	  } else {
	    f->state = ((f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED);
	  }
#else
#if DK_HAVE_DIRENT_H
/* UNIX/Linux, dirent */
#else
/* any unknown directory listing mechanism */
#endif
#endif
#endif
	} break;
	default: {				
	  f->error_code = DK_ERR_NOT_NOW;
	} break;
      }
#endif
    } else {					
      switch(f->state & (~(FNE_NOT_STATE))) {
	case FNE_STATE_INITIALIZED: {
	  strcpy(f->fullname, f->dirname);
	  ptr = dkstr_rchr(f->fullname, path_component_separator[0]);
	  if(ptr) {
	    ptr++;
	  } else {
	    ptr = f->fullname;
	  }
	  strcpy(f->shortname, ptr);
	  f->state = (FNE_STATE_CLOSED | ((f->state) & FNE_NOT_STATE));
	  back = 1;
	} break;
	default: {				
	  f->error_code = DK_ERR_NOT_NOW;
	} break;
      }
    }
  }
  if(back) {
#if USE_FNE
    if((f->state) & FNE_MUST_RUN) {
      
      strcpy(f->fullname, f->dirname);
      ptr = dkstr_rchr(f->fullname, path_component_separator[0]);
      if(ptr) {
        ptr++;
      } else {
        ptr = f->fullname;
      }
      strcpy(ptr, f->shortname);
      
    }
#endif
  } 
  return back;
}



int
dkfne_next	DK_P1(dk_fne_t *, f)
{
  int back = 0;
  int can_continue, must_continue, ft;
  char *fullname;
  dk_stat_t stb;
  
  if(f) {
    can_continue = must_continue = 1;
    while(can_continue && must_continue) {
      can_continue = dkfne_find_one(f);
      if(can_continue) {
	fullname = dkfne_get_fullname(f);
	if(fullname) {
	  if(dkstat_get(&stb, fullname)) {
	    ft = dkstat_filetype(&stb);
	    ft = ft & (~(DK_FT_SYMLINK));
	    switch(ft) {
	      case DK_FT_REG : {
		if((f->state) & FNE_FILES) {
		  back = 1; must_continue = 0;
		}
	      } break;
	      case DK_FT_DIR : {
		if((f->state) & FNE_DIRS) {
		  back = 1; must_continue = 0;
		}
	      } break;
	    }
	  }
	}
      }
    }
  } 
  return back;
}



char
*dkfne_get_one	DK_P1(dk_fne_t *, f)
{
  char *back = NULL; char *ptr;
  if(f) {
    if(dkfne_next(f)) {
      ptr = dkfne_get_fullname(f);
      if(ptr) {
        back = dkstr_dup(ptr);
	if(back) {
	  if(dkfne_next(f)) {
	    dk_delete(back);
	    back = NULL;
	    f->error_code = DK_ERR_NOT_UNIQUE;
	  }
	} else {
	  f->error_code = DK_ERR_NOMEM;
	}
      } else {
        f->error_code = DK_ERR_NO_SUCH_FILE;
      }
    } else {
      f->error_code = DK_ERR_NO_SUCH_FILE;
    }
  }
  return back;
}



char *
dkfne_get_fullname	DK_P1(dk_fne_t *, f)
{
  char *back = NULL;
  
  if(f) {
    back = f->fullname;
  } 
  return back;
}



char *
dkfne_get_shortname	DK_P1(dk_fne_t *, f)
{
  char *back = NULL;
  
  if(f) {
    back = f->shortname;
  } 
  return back;
}



void
dkfne_close	DK_P1(dk_fne_t *, f)
{
  
  if(f) {
#if USE_FNE
    switch(f->state & (~(FNE_NOT_STATE))) {
      case FNE_STATE_OPENED: {
#if defined(WIN32) || defined(_WIN32)
/* + Win32 */
#if DK_HAVE__FINDFIRST64
/* Win32, _findfirst64 */
      _findclose(f->hFile64); f->hFile64 = -1L;
      f->state = (f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED;
#else
#if DK_HAVE__FINDFIRST32
/* Win32, _findfirst32 */
      _findclose(f->hFile32); f->hFile32 = -1L;
      f->state = (f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED;
#else
#if DK_HAVE__FINDFIRST
/* Win32, _findfirst */
      _findclose(f->hFile); f->hFile = -1L;
      f->state = (f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED;
#endif
#endif
#endif
/* - Win32 */
#else
#if DK_HAVE_FINDFIRST
/* DOS, findfirst */
      int i;
      i = 0;
      while(!i) {
	i = findnext(&(f->dir));
      }
      f->state = (f->state & FNE_NOT_STATE) | FNE_STATE_CLOSED;
#else
#if DK_HAVE_DIRENT_H
/* UNIX/Linux, dirent */
#else
/* any unknown directory listing mechanism */
#endif
#endif
#endif
      } break;
      default: {				
      } break;
    }
#endif
  } 
}



char *
dksf_get_last_filename	DK_P1(char *, name)
{
  char *back = NULL;
  if(name) {
    back = dkstr_rchr(name, path_component_separator[0]);
    if(back) {
      back++;
    } else {
      back = name;
    }
  }
  return back;
}



char *
dksf_get_file_type_dot	DK_P1(char *, name)
{
  char *back = NULL;
  char *x;
  
  if(name) {
    x = dkstr_rchr(name, path_component_separator[0]);
    x = (x ? x : name);
    back = dkstr_rchr(x, '.');
  }
  
  return back;
}



int
dksf_is_abs_path	DK_P1(char *, name)
{
  int back = 0;
  
  if(name) {
    if(*name == path_component_separator[0]) {
      back = 1;
    } else {
#if DK_HAVE_FEATURE_DRIVECHAR
      if(((*name >= 'a') && (*name <= 'z')) || ((*name >= 'A') && (*name <= 'Z'))) {
	if(name[1] == ':') {
	  if(name[2] == path_component_separator[0]) {
	    if(name[3]) {
	      back = 1;
	    }
	  }
	}
      }
#endif
    }
  } 
  return back;
}



/**	Find place where tu cut a file name.
	@param	dirname	Directory name.
	@return	Pointer to cut position.
*/
static
char *
find_place_to_cut	DK_P1(char *, dirname)
{
  char *back = NULL;
  char *ptr;
  int seps_found;
  int last_was_sep;
  
  last_was_sep = 0;
  seps_found = 0;
  ptr = dirname;
  while(*ptr) {
    if(*ptr == path_component_separator[0]) {
      seps_found++;
      last_was_sep = 1;
      if(seps_found > 1) {
	back = ptr;
      }
    } else {
      if(last_was_sep) {
	if(seps_found == 1) {
	  back = ptr;
	}
      }
      last_was_sep = 0;
    }
    ptr++;
  }
  
  return back;
}



int
dksf_path_combine DK_P4(char *, buf, size_t, len, char *, cd, char *, pr)
{
  int back = 0;
  size_t used;
  char *xptr, *yptr, *zptr;
  if(buf) {
  if(len > 3) {
  if(cd) {
  if(pr) {
    used = strlen(cd);
    if(used < len) {
      back = 1;
      strcpy(buf, cd);
      xptr = pr;
      if(dksf_is_abs_path(pr)) {
	xptr++;
	*buf = pr[0];
        if(*buf != path_component_separator[0]) {
	  buf[1] = pr[1];
	  buf[2] = pr[2];
	  buf[3] = '\0';
	  xptr++; xptr++;
	} else {
	  buf[1] = '\0';
	}
	used = strlen(buf);
      }
      while(xptr && back) {
	used = strlen(buf);
        yptr = dkstr_chr(xptr, path_component_separator[0]);
        if(yptr) { *yptr = '\0'; }
        if(strcmp(xptr, ".")) {
	  if(strcmp(xptr, "..")) {	
	    if((used + strlen(xptr) + 1) < len) {
	      if(buf[(used > 0) ? (used - 1) : used] != path_component_separator[0]) {
		strcat(buf, path_component_separator);
	      }
	      strcat(buf, xptr);
	    } else {
	      back = 0;
	    }
	  } else {			
	    /* zptr = dkstr_rchr(buf, path_component_separator[0]); */
	    zptr = find_place_to_cut(buf);
	    if(zptr) {
	      *zptr = '\0';
	    } else {
	      back = 0;
	    }
	  }
	}
	if(yptr) { *yptr = path_component_separator[0]; }
	xptr = yptr;
	if(xptr) xptr++;
      }
    }
  }
  }
  }
  }
  return back;
}



#if DK_HAVE_FEATURE_DOS_EXEC
/**	Check whether a file name exists with one of the specified suffixes.
	@param	buf	Buffer containing the base file name.
	@param	len	Length of \a buf.
	@param	pe	List of suffixes for executable files,
			semicolon separated.
	@return	1 on success, 0 on error.
*/
static
int
check_executable_file(char *buf, size_t len, char *pe)
{
  int back = 0;
  size_t lgt;
  dk_stat_t st;
  char *xptr, *yptr;
  if(dksf_get_file_type_dot(buf)) {		
    if(dkstat_get(&st, buf)) {
      if((dkstat_filetype(&st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) {
	back = 1;
      }
    }
  } else {				
    lgt = strlen(buf);
    xptr = pe;
    while(xptr && (!back)) {
      yptr = dkstr_chr(xptr, ';');
      if(yptr) { *(yptr++) = '\0'; }
      if((lgt + strlen(xptr)) < len) {
	strcat(buf, xptr);
	if(dkstat_get(&st, buf)) {
	  if((dkstat_filetype(&st) & (~(DK_FT_SYMLINK))) == DK_FT_REG) {
	    back = 1;
	  }
	}
      }
      if(!back) { buf[lgt] = '\0'; }
      xptr = yptr;
    }
  }
  return back;
}
#endif



int
dksf_get_executable DK_P5(char *, buf, size_t, len, char *, cd, char *, pr, int, cu)
{
  int back = 0;
  char psep;
  int action;
  char *pathori;
  char *pathcp;
#if DK_HAVE_FEATURE_DOS_EXEC
  char *pe;
  char *pc;
#endif
  char *xptr;
  char *yptr;
  size_t used;
  
  if(buf) {
  if(len) {
  if(cd) {
  if(pr) {	
    psep = path_component_separator[0];
    if(dkstr_chr(pr,psep)) {
      action = 2;
    } else {
      action = 0;
    }
    if(dksf_get_file_type_dot(pr)) { action += 1; }
#if DK_HAVE_FEATURE_DOS_EXEC
#if DK_HAVE_GETMODULEFILENAME && DK_HAVE_GETMODULEHANDLE
    if(cu) {
    if(GetModuleFileNameA(GetModuleHandle(NULL),buf,len)) {
      back = 1;
    }
    }
#endif
    /* DOS exec search, current directory first */
    if(!back) {
      pe = getenv("PATHEXT");
      if(!pe) pe = default_path_ext;
      pc = dkstr_dup(pe);
      if(pc) {
        if(action & 2) {    
	  if(len > strlen(pr)) {
	    strcpy(buf, pr);
	    back = check_executable_file(buf, len, pc);
	  }
        } else {		  
	  if(len > (strlen(cd) + strlen(pr) + 1)) {
	    strcpy(buf, cd);
	    used = strlen(cd);
	    if(used > 0) used--;
	    if(buf[used] != path_component_separator[0]) {
	      strcat(buf, path_component_separator);
	    }
	    strcat(buf, pr);
	    back = check_executable_file(buf, len, pc);
	  }
          if(!back) {
	    pathori = getenv("PATH");
	    if(pathori) {
	      pathcp = dkstr_dup(pathori);
	      if(pathcp) {
	        xptr = pathcp;
	        while(xptr && (!back)) {
		  strcpy(pc, pe);
		  yptr = dkstr_chr(xptr, ';');
		  if(yptr) { *(yptr++) = '\0'; }
                  if(len > (strlen(xptr) + 1 + strlen(pr))) {
		    strcpy(buf, xptr);
		    used = strlen(buf);
		    if(used > 0) used--;
		    if(buf[used] != path_component_separator[0]) {
		      strcat(buf, path_component_separator);
		    }
		    strcat(buf, pr);
		    back = check_executable_file(buf, len, pc);
		  }
		  xptr = yptr;
	        }
	        dkmem_free(pathcp);
	      }
	    }
	  }
        }
        dkmem_free(pc);
      }
    }
#else
    /* UNIX exec search, consult PATH/path */
    if(action & 2) {    
      if(dksf_is_abs_path(pr)) {
	if(strlen(pr) < len) {
	  strcpy(buf,pr);
	  back = 1;
	}
      } else {
	back = dksf_path_combine(buf, len, cd, pr);
      }
    } else {            
      pathori = getenv("PATH");
      if(pathori) {
	dk_stat_t st;
	pathcp = dkstr_dup(pathori);
	if(pathcp) {
          xptr = pathcp;
	  while(xptr && (!back)) {
	    
	    yptr = dkstr_chr(xptr, ':');
	    if(yptr) { *(yptr++) = '\0'; }
	    
            if(strlen(xptr) == 0) {		
	      if(len > (strlen(cd) + strlen(pr) + 1)) { 
		strcpy(buf, cd);
		used = strlen(cd);
		if(used > 0) used--;
		if(buf[used] != path_component_separator[0]) {
		  strcat(buf, path_component_separator);
		}
		strcat(buf, pr);
		if(dkstat_get(&st, buf)) {
		  if((dkstat_filetype(&st) & (~DK_FT_SYMLINK)) == DK_FT_REG) {
		  if(dkstat_permissions(&st) & DK_PERM_U_EXECUTE) {
		    back = 1;
		  }
		  }
		}
	      }
	    } else {				
	      if(len > (strlen(xptr) + strlen(pr) + 1)) {
		strcpy(buf, xptr);
		used = strlen(xptr);
		if(used > 0) used--;
		if(buf[used] != path_component_separator[0]) {
		  strcat(buf, path_component_separator);
		}
		strcat(buf, pr);
		if(dkstat_get(&st, buf)) {
		  if((dkstat_filetype(&st) & (~DK_FT_SYMLINK)) == DK_FT_REG) {
		  if(dkstat_permissions(&st) & DK_PERM_U_EXECUTE) {
		    back = 1;
		  }
		  }
		}
	      }
	    }
	    xptr = yptr;
	  }
	  dkmem_free(pathcp);
	}
      }
    }
#endif
  }
  }
  }
  }
  
  return back;
}



int
dksf_getcwd DK_P2(char *, buffer, size_t, lgt)
{
  int back = 0;
  if(buffer && lgt) {
#if DK_HAVE_GETCURRENTDIRECTORY
  if(GetCurrentDirectoryA(lgt,buffer)) {
    back = 1;
  }
#else
#if DK_HAVE_GETCWD
  if(getcwd(buffer, lgt)) {
    back = 1;
  }
#else
#if DK_HAVE_GETWD
  char *buf;
  buf = dk_new(char,DK_MAX_PATH);
  if(buf) {
    if(getwd(buf)) {
      if(strlen(buf) < lgt) {
	strcpy(buffer, buf); back = 1;
      }
    }
    dk_delete(buf);
    buf = NULL;
  }
#else
#if DK_HAVE__GETCWD
  if(_getcwd(buffer, lgt)) {
    back = 1;
  }
#else
#if DK_HAVE__GETWD
  char *buf;
  buf = dk_new(char,DK_MAX_PATH);
  if(buf) {
    if(_getwd(buf)) {
      if(strlen(buf) < lgt) {
	strcpy(buffer, buf); back = 1;
      }
    }
    dk_delete(buf); buf = NULL;
  }
#else
#error "No getcwd/getwd/_getcwd/_getwd function"
#endif
#endif
#endif
#endif
#endif
  }
  return back;
}



void
dksf_correct_fnsep DK_P1(char *,str)
{
  char *ptr;
  if(str) {
    ptr = str;
    while(*ptr) {
      if(*ptr == no_component_separator[0]) {
	*ptr = path_component_separator[0];
      }
      ptr++;
    }
  }
}



int
dksf_remove_file DK_P1(char *, filename)
{
  int back = 0;
  
  if(filename) {
#if DK_HAVE_UNLINK || DK_HAVE__UNLINK
    
#if DK_HAVE_UNLINK
    if(unlink(filename) == 0) {
#else
    if(_unlink(filename) == 0) {
#endif
      back = 1;
    }
#else
#if DK_HAVE_REMOVE
    
    if(remove(filename) == 0) {
      back = 1;
    }
#endif
#endif
  }
    
  return back;
}



/**	Attempt to remove a directory with all contents.
	@param	filename	File name of directory.
	@param	bck		Set to 0 on error.
*/
static
void
remove_dir_rec DK_P2(char *, filename, int *, bck)
{
  dk_stat_t st;
  dk_dir_t  *dir;
  char      *sn, *fn;
  int	     dnt;
  
  if(dkstat_get(&st, filename)) {
    if((st.filetype) & DK_FT_SYMLINK) {
      
      if(!dksf_remove_file(filename)) {
	
	*bck = 0;
      }
    } else {
      
      switch(st.filetype) {
	case DK_FT_DIR : {
	  
	  dir = dkdir_open(filename);
	  if(dir) {
	    while((dnt = dkdir_next(dir))) {
	      if(dnt == 1) {
	        sn = dir->shortname;
	        fn = dir->fullname;
	        if(sn && fn) {
		  if(strcmp(sn, ".")) {
		    if(strcmp(sn, "..")) {
		      remove_dir_rec(fn, bck);
		    }
		  }
	        } else {
		  
		  *bck = 0;
	        }
	      }
	    }
	    dkdir_close(dir);
	    dir = NULL;
#if DK_HAVE_RMDIR || DK_HAVE__RMDIR
	      
#if DK_HAVE_RMDIR
	      if(rmdir(filename) != 0)
#else
	      if(_rmdir(filename) != 0)
#endif
	      {
		
		*bck = 0;
	      }
#else
#if DK_HAVE_UNLINK || DK_HAVE__UNLINK
	      
#if DK_HAVE_UNLINK
	      if(unlink(filename) != 0)
#else
	      if(_unlink(filename) != 0)
#endif
	      {
	        
		*bck = 0;
	      }
#else
#if DK_HAVE_REMOVE
	      
	      if(remove(filename) != 0) {
		
		*bck = 0;
	      }
#else
	      
#endif
#endif
#endif
	  } else {
	    
	    *bck = 0;
	  }
	} break;
	default : {
	  
	  if(!dksf_remove_file(filename)) {
	    
	    *bck = 0;
	  }
	} break;
      }
    }
  } else {
    
    *bck = 0;
  } 
}



int
dksf_remove_directory
DK_P1(char *, filename)
{
  int back = 0;
  if(filename) {
    back = 1;
    remove_dir_rec(filename, &back);
  }
  return back;
}



dk_stat_t *
dkdir_stat DK_P1(dk_dir_t *,d)
{
  dk_stat_t *back = NULL;
  if(d) {
    back = &(d->stbuf);
  }
  return back;
}



int
dksf_fdesk_binary DK_P2(int,fn, int,fl)
{
  int back = 0;
#if DK_HAVE_DOSWIN_SETMODE
  int res = 0;
#endif
#if DK_HAVE_DOSWIN_SETMODE
  if(fl) {
#if DK_HAVE_DOSWIN_SETMODE
#if DK_HAVE_SETMODE
#ifdef O_BINARY
    res = setmode(fn, O_BINARY);
    if(res == O_BINARY) back = 1;
#else
#ifdef _O_BINARY
    res = setmode(fn, _O_BINARY);
    if(res == _O_BINARY) back = 1;
#endif
#endif
#else
#if DK_HAVE__SETMODE
#ifdef O_BINARY
    res = _setmode(fn, O_BINARY);
    if(res == O_BINARY) back = 1;
#else
#ifdef _O_BINARY
    res = _setmode(fn, _O_BINARY);
    if(res == _O_BINARY) back = 1;
#endif
#endif
#endif
#endif
#endif
  } else {
#if DK_HAVE_DOSWIN_SETMODE
#if DK_HAVE_SETMODE
#ifdef O_TEXT
  res = setmode(fn, O_TEXT);
  if(res == O_BINARY) back = 1;
#else
#ifdef _O_TEXT
  res = setmode(fn, _O_TEXT);
  if(res == _O_BINARY) back = 1;
#endif
#endif
#else
#if DK_HAVE__SETMODE
#ifdef O_TEXT
  res = _setmode(fn, O_TEXT);
  if(res == O_BINARY) back = 1;
#else
#ifdef _O_TEXT
  res = _setmode(fn, _O_TEXT);
  if(res == _O_BINARY) back = 1;
#endif
#endif
#endif
#endif
#endif
  }
#endif
  return back;
}



/**	Check whether a file name is a symbolic link.
	@param	name	File name.
	@return	1 for symbolic link, 0 for other file types.
*/
static
int
is_symbolic_link DK_P1(char *,name)
{
  int back = 0;
  dk_stat_t st;
  if(name) {
  dkstat_init(&st);
  if(dkstat_get(&st, name)) {
    if((st.filetype) & DK_FT_SYMLINK) {
      back = 1;
    }
  }
  }
  
  return back;
}



/**	Check whether a file name is a directory.
	@param	name	File name to check.
	@return	1 for directory, 0 for not a directory.
*/
static int
is_directory DK_P1(char *,name)
{
  int back = 0;
  dk_stat_t st;
  if(name) {
    dkstat_init(&st);
    if(dkstat_get(&st, name)) {
      if(((st.filetype) & (~(DK_FT_SYMLINK))) == DK_FT_DIR) {
        back = 1;
      }
    }
  }
  
  return back;
}



/**	When opening a file to write check that it is not a directory.
	@param	name	File name to open.
	@param	ign	Security checks to ignore.
	@param	reason	Pointer to buffer for reason.
	@return	1 on success (we can write the file), 0 on error.
*/
static
int
directory_write_check DK_P3(char *,name,int,ign,int *,reason)
{
  int back = 1;
  dk_stat_t st;
  if(name) {
    if(dkstat_get(&st, name)) {
      if((st.permissions) & DK_PERM_O_WRITE) {
        if(!(ign & DK_SF_SEC_WO)) {
	  back = 0;
	  if(reason) *reason = DK_SF_SEC_WO;
	}
      }
      if((st.permissions) & DK_PERM_G_WRITE) {
        if(!(ign & DK_SF_SEC_WG)) {
	  back = 0;
	  if(reason) *reason = DK_SF_SEC_WG;
	}
      }

    }
  }
  
  return back;
}



/**	Check whether the link target is owned by the same user as the link
	itself.
	@param	name	File name.
	@return	1 for check ok, 0 for check failed.
*/
static int
check_ownership_for_symlink DK_P1(char *,name)
{
  int back = 0;
  dk_stat_t st;
  if(name) {
    if(dkstat_get(&st, name)) {
      if(st.ud) {
        back = 1;
      }
    }
  }
  
  return back;
}



int
dksf_allowed_to_write DK_P3(char *,name,int,ign,int *,reason)
{
  int back = 0;
  char *dirname; char *cptr; size_t lgt;
  
  if(name) {
    if(is_symbolic_link(name)) {
      dirname = dkstr_dup(name);
      if(dirname) {
        cptr = dkstr_rchr(dirname, path_component_separator[0]);
	if(cptr) {
	  *cptr = (char)0;
	  if((lgt = strlen(dirname)) > 0) {
#if DK_HAVE_DOS_DRIVE_LETTER
	    if(lgt == 2) {
	    if(dirname[1] == str_colon) {
	      dirname[2] = path_component_separator[0];
	      dirname[3] = (char)0;
	    }
	    }
#endif
/* DK_HAVE_DOS_DRIVE_LETTER */
            back = directory_write_check(dirname,ign,reason);
	  } else {
	    dirname[0] = path_component_separator[0];
	    dirname[1] = (char)0;
	    back = directory_write_check(dirname,ign,reason);
	  }
	} else {
	  back = directory_write_check(curdir,ign,reason);
	}
        dk_delete(dirname);
      }
      if(back) {
        if(!(ign & DK_SF_SEC_OWNER)) {
	  if(!check_ownership_for_symlink(name)) {
	    back = 0;
	    if(reason) { *reason = DK_SF_SEC_OWNER; }
	  }
	}
      }
    } else {
      back = 1;
    }
  } 
  return back;
}



FILE *
dksf_msfo DK_P4(char *,name,char *,mode,int,ign,int *,reason)
{
  FILE *back = NULL;
  int want_to_write;
  char *cptr;
  
  if(name && mode) {
    want_to_write = 0; cptr = mode;
    while(*cptr) {
      switch(*(cptr++)) {
        case 'w':
	case 'a':
	case '+': {
	  want_to_write = 1;
	} break;
      }
    }
    if(want_to_write) { 
      if(dksf_allowed_to_write(name,ign,reason)) {
        if(is_directory(name)) {
	  if(reason) {
	    *reason = DK_SF_SEC_DIR;
	  }
	} else {
          
#if DK_HAVE_LARGEFILE64_SOURCE && DK_HAVE_FOPEN64
	  back = fopen64(name,mode);
#else
          back = fopen(name,mode);
#endif
	}
      }
    } else { 
      if(is_directory(name)) {
        if(reason) {
	  *reason = DK_SF_SEC_DIR;
	}
      } else {
#if DK_HAVE_LARGEFILE64_SOURCE && DK_HAVE_FOPEN64
	back = fopen64(name, mode);
#else
        back = fopen(name,mode);
#endif
      }
    }
  } 
  return back;
}



FILE *
dksf_fopen DK_P2(char *,p,char *,m)
{
  FILE *back = NULL;
  int dummy = 0;
  back = dksf_msfo(p,m,0,&dummy);
  return back;
}



int
dksf_must_expand_filename DK_P1(char *,name)
{
  int back = 0;
#if DK_HAVE_FEATURE_BACKSLASH && USE_FNE
  char *ptr;
  ptr = name;
  while((!back) && (*ptr)) {
    if((*ptr == '?') || (*ptr == '*')) { back = 1; }
    ptr++;
  }
#endif
  return back;
}



int
dkfne_get_error_code DK_P2(dk_fne_t *,f, int, res)
{
  int back = DK_ERR_NONE;
  if(f) {
    back = f->error_code;
    if(res) {
      f->error_code = DK_ERR_NONE;
    }
  }
  return back;
}



int
dksf_get_filetype DK_P1(char *,pathname)
{
  int back = 0;
  dk_stat_t st;
  
  if(pathname) {
    dkstat_init(&st);
    if(dkstat_get(&st, pathname)) {
      back = st.filetype;
    }
  }
  
  return back;
}



int
dksf_is_directory DK_P1(char *,pathname)
{
  int back = 0; int ft = 0;
  
  if(pathname) {
    ft = dksf_get_filetype(pathname);
    ft &= (~DK_FT_SYMLINK);
    if(ft == DK_FT_DIR) {
      back = 1;
    }
  }
  
  return back;
}



int
dksf_no_core DK_P0()
{
  int back = 0;
#if DK_HAVE_SYS_RESOURCE_H
#if DK_HAVE_GETRLIMIT
#ifdef RLIMIT_CORE
  struct rlimit rl;
  rl.rlim_cur = rl.rlim_max = 0;
  if(setrlimit(RLIMIT_CORE, &rl) == 0) {
    back = 1;
  }
#endif
#endif
#endif
  return back;
}



/*
  Usage:

  dk_echo_t	echodata;

  if(dksf_echo_save(&echodata)) {
    dksf_echo_off(&echodata);
    ...
    dksf_echo_restore(&echodata);
  }

*/

int
dksf_echo_save DK_P1(dk_echo_t *,ep)
{
  int back = 0;
  
  if(ep) {
  ep->is_tty = 0;
#if DK_HAVE_TCGETATTR
  
  if(tcgetattr(0, &(ep->ori)) == 0) {
    back = 1;
  }
#if DK_HAVE_ISATTY
  
  ep->is_tty = isatty(0);
#endif
#else
#ifdef TCGETS
  
  if(ioctl(0, TCGETS, &(ep->ori)) == 0) {
    back = 1;
  }
#if DK_HAVE_ISATTY
  
  ep->is_tty = isatty(0);
#endif
#else
#if DK_HAVE_GETSTDHANDLE
  
  ep->consoleHandle = GetStdHandle(STD_INPUT_HANDLE);
  if(ep->consoleHandle != INVALID_HANDLE_VALUE) {
    ep->is_tty = 1;
    if(GetConsoleMode(ep->consoleHandle, &(ep->ori))) {
      back = 1;
    }
  }
#else
#if DK_HAVE_ISATTY
  
  ep->is_tty = isatty(0);
#endif
#endif
#endif
#endif
  } 
  return back;
}



int
dksf_echo_restore DK_P1(dk_echo_t *,ep)
{
  int back = 0;
  
  if(ep) {
#if DK_HAVE_TCGETATTR
  
  if(tcsetattr(0, TCSANOW, &(ep->ori)) == 0) {
    back = 1;
  }
#else
#ifdef TCGETS
  
  if(ioctl(0, TCSETS, &(ep->ori)) == 0) {
    back = 1;
  }
#else
#if DK_HAVE_GETSTDHANDLE
  
  if(ep->consoleHandle != INVALID_HANDLE_VALUE) {
    if(SetConsoleMode(ep->consoleHandle, ep->ori)) {
      back = 1;
    }
  }
#endif
#endif
#endif
  } 
  return back;
}



/**	Abbreviation for use with sizeof operator.
*/
typedef struct termios TIO;



int
dksf_echo_off DK_P1(dk_echo_t *,ep)
{
  int back = 0;
  
  if(ep) {
#if DK_HAVE_TCGETATTR
  struct termios nti;
  
  DK_MEMCPY(&nti, &(ep->ori), sizeof(TIO));
#ifdef ECHO
  
  nti.c_lflag &= (~(ECHO));
#endif
#ifdef ECHONL
  
  nti.c_lflag |= (ECHONL);
#endif
  if(tcsetattr(0, TCSANOW, &nti) == 0) {
    back = 1;
  }
  tcflush(0, TCIFLUSH);
#else
#ifdef TCGETS
  struct termios nti;
  
  DK_MEMCPY(&nti, &(ep->ori), sizeof(TIO));
#ifdef ECHO
  
  nti.c_lflag &= (~(ECHO));
#endif
#ifdef ECHONL
  
  nti.c_lflag |= (ECHONL);
#endif
  if(ioctl(0, TCSETS, &nti) == 0) {
    back = 1;
  }
  (void)ioctl(0, TCFLSH, 0);
#else
#if DK_HAVE_GETSTDHANDLE
  DWORD nti;
  
  nti = ep->ori;
  if(ep->consoleHandle != INVALID_HANDLE_VALUE) {
    nti &= (~(ENABLE_ECHO_INPUT));
    if(SetConsoleMode(ep->consoleHandle, nti)) {
      back = 1;
    }
  }
#endif
#endif
#endif
  } 
  return back;
}



int
dksf_echo_is_tty DK_P1(dk_echo_t *,ep)
{
  int back = 0;
  if(ep) { back = ep->is_tty; }
  
  return back;
}



int
dksf_echo_test_tty DK_P0()
{
  int back = 0;
  
#if DK_HAVE_TCGETATTR
#if DK_HAVE_ISATTY
  
  back = isatty(0);
#endif
#else
#ifdef TCGETS
#if DK_HAVE_ISATTY
  
  back = isatty(0);
#endif
#else
#if DK_HAVE_GETSTDHANDLE
  
  if(GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE) {
    back = 1;
  }
#else
#if DK_HAVE_ISATTY
  
  back = isatty(0);
#endif
#endif
#endif
#endif
  
  return back;
}



unsigned long
dksf_filesize_bytes DK_P0() {
  unsigned long back = 0UL;
#if defined(WIN32) || defined(_WIN32)
#if DK_HAVE__STAT64
  back = 8UL;
#else
#if DK_HAVE__STAT32
  back = 4UL;
#else
  back = (unsigned long)sizeof(off_t);
#endif
#endif
#else
#if DK_HAVE_STAT64 && DK_HAVE_LARGEFILE64_SOURCE
  back = 8UL;
#else
  back = (unsigned long)sizeof(off_t);
#endif
#endif
  return back;
}



unsigned long
dksf_long_long_bytes DK_P0() {
  return (unsigned long)sizeof(dk_long_long_unsigned_t);
}



/**	Write PID file.
	@param	appname	Application name.
	@param	cr	1=create, 0=delete
	@return	1 on success, 0 on error.
*/
int
dksf_write_pid_file DK_P2(char *,appname, int,cr)
{
  int back = 0;
  size_t sz = 0;
  FILE *fipo = NULL;
  char buffer[MY_MAXPATHLEN];
  if(appname) {
    sz = strlen(var_run);
    sz += strlen(path_component_separator);
    sz += strlen(appname);
    sz += strlen(suffix_pid);
    if(sz < sizeof(buffer)) {
      strcpy(buffer, var_run);
      strcat(buffer, path_component_separator);
      strcat(buffer, appname);
      strcat(buffer, suffix_pid);
      switch(cr) {
        case 1: {
	  fipo = dksf_fopen(buffer, "w");
	  if(fipo) {
	    fprintf(fipo, "%ld\n", dksf_getpid());
	    fclose(fipo); fipo = NULL;
	  }
	} break;
	default: {
	  back = dksf_remove_file(buffer);
	} break;
      }
    }
  }
  return back;
}


