#ifndef posixprp_c
#define posixprp_c

#include "../config.h"

#if HAVE_UNISTD_H
# include <sys/types.h>
# include <unistd.h>
#else
#error Need POSIX
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#error Need stat
#endif

#include <assert.h>
#include <errno.h>

#define ensure( X ) assert((X))
#define require( X ) assert((X))

void* 
posix_make_stat()
{
  void* l_returnval = (void*)malloc(sizeof(struct stat));
  if (NULL != l_returnval) 
    {
      memset(l_returnval, 0, sizeof(struct stat));
    }
  return l_returnval;
}

void 
posix_free_stat(void* a_stat)
{
  require (a_stat);
  if (a_stat) 
    {
      free(a_stat);
    }
};

int 
posix_set_stat(const char* a_path, void* a_stat)
{
  require (a_stat);
  require (a_path);
#ifdef HAVE_LSTAT_EMPTY_STRING_BUG
  if ('\0' == *a_path)
    {
      memset(a_stat, 0, sizeof(struct stat));
      errno = ENOENT;
      return -1;
    }
#endif /* HAVE_LSTAT_EMPTY_STRING_BUG */
  return lstat(a_path, a_stat);
};

int 
posix_block_device(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a block device. */
{
  require (a_stat);
  return S_ISBLK(a_stat->st_mode);
}

int 
posix_character_device(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a character device. */
{
  require (a_stat);
  return S_ISCHR(a_stat->st_mode);
}

int 
posix_directory(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a directory. */
{
  require (a_stat);
  return S_ISDIR(a_stat->st_mode);
}

int 
posix_file(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a regular file. */
{
  require (a_stat);
  return S_ISREG(a_stat->st_mode);
}

int 
posix_pipe(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a pipe/fifo. */
{
  require (a_stat);
  return S_ISFIFO(a_stat->st_mode);
}

int 
posix_socket(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a socket. */
{
  require (a_stat);
  return S_ISSOCK(a_stat->st_mode);
}

int 
posix_symlink(struct stat* a_stat)
/**  indicate whether the file system object related to this  */
/**  object files is a symlink. */
{
  require (a_stat);
  return S_ISLNK(a_stat->st_mode);
}
			
int 
posix_size(struct stat* a_stat)
/**  Get the size of a file or symlink. */
{
  require (a_stat);
  return (int)a_stat->st_size;
}
			
int 
posix_access(struct stat* a_stat)
/**  Get the file system object related to this object's access */
/**  time (st_atime), e.g. time of call by execve(2), mknod(2), */
{
  require (a_stat);
  return (int)a_stat->st_atime;
}

int 
posix_change(struct stat* a_stat)
/**  Get the file system object related to this object's change */
/**  time (st_ctime). The field st_ctime is changed by writing */
{
  require (a_stat);
  return (int)a_stat->st_ctime;
}

int 
posix_mod(struct stat* a_stat)
/**  Get the file system object related to this object's */
/**  modification time (st_mtime). The field st_mtime is */
{
  require (a_stat);
  return (int)a_stat->st_mtime;
}

#endif /** !posixprp_c */

