module gcc.configunix;
private import gcc.config;

alias gcc.config.Coff_t off_t;
extern(C) {

enum {
  O_RDONLY = 0,
  O_WRONLY = 1,
  O_RDWR = 2,
  O_NONBLOCK = 4,
  O_CREAT = 512,
  O_EXCL = 2048,
  O_TRUNC = 1024,
  O_APPEND = 8,
  O_NOFOLLOW = 256,
}

enum {
  F_DUPFD = 0,
  F_GETFD = 1,
  F_SETFD = 2,
  F_GETFL = 3,
  F_SETFL = 4,
}

alias int time_t;
struct timespec {
    int tv_sec;
    int tv_nsec;
}

static assert(timespec.tv_sec.offsetof == 0);
static assert(timespec.tv_nsec.offsetof == 4);


struct timeval {
    int tv_sec;
    int tv_usec;
}

static assert(timeval.tv_sec.offsetof == 0);
static assert(timeval.tv_usec.offsetof == 4);


struct timezone {
    int tz_minuteswest;
    int tz_dsttime;
}

static assert(timezone.tz_minuteswest.offsetof == 0);
static assert(timezone.tz_dsttime.offsetof == 4);


struct tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
    int tm_gmtoff;
    char * tm_zone;
}

static assert(tm.tm_sec.offsetof == 0);
static assert(tm.tm_min.offsetof == 4);
static assert(tm.tm_hour.offsetof == 8);
static assert(tm.tm_mday.offsetof == 12);
static assert(tm.tm_mon.offsetof == 16);
static assert(tm.tm_year.offsetof == 20);
static assert(tm.tm_wday.offsetof == 24);
static assert(tm.tm_yday.offsetof == 28);
static assert(tm.tm_isdst.offsetof == 32);
static assert(tm.tm_gmtoff.offsetof == 36);


enum {
  S_IFIFO = 4096,
  S_IFCHR = 8192,
  S_IFDIR = 16384,
  S_IFBLK = 24576,
  S_IFREG = 32768,
  S_IFLNK = 40960,
  S_IFSOCK = 49152,
  S_IFMT = 61440,
  S_IRUSR = 256,
  S_IWUSR = 128,
  S_IXUSR = 64,
  S_IRGRP = 32,
  S_IWGRP = 16,
  S_IXGRP = 8,
  S_IROTH = 4,
  S_IWOTH = 2,
  S_IXOTH = 1,
  S_IRWXG = 56,
  S_IRWXO = 7,
}

struct struct_stat {
    uint st_dev;
    uint st_ino;
    ushort st_mode;
    ushort st_nlink;
    uint st_uid;
    uint st_gid;
    uint st_rdev;
    int st_atime;
   ubyte[4] ___pad1;
    int st_mtime;
   ubyte[4] ___pad2;
    int st_ctime;
   ubyte[4] ___pad3;
    long st_size;
    long st_blocks;
    uint st_blksize;
}

static assert(struct_stat.st_dev.offsetof == 0);
static assert(struct_stat.st_ino.offsetof == 4);
static assert(struct_stat.st_mode.offsetof == 8);
static assert(struct_stat.st_nlink.offsetof == 10);
static assert(struct_stat.st_uid.offsetof == 12);
static assert(struct_stat.st_gid.offsetof == 16);
static assert(struct_stat.st_rdev.offsetof == 20);
static assert(struct_stat.st_atime.offsetof == 24);
static assert(struct_stat.st_mtime.offsetof == 32);
static assert(struct_stat.st_ctime.offsetof == 40);
static assert(struct_stat.st_size.offsetof == 48);
static assert(struct_stat.st_blocks.offsetof == 56);
static assert(struct_stat.st_blksize.offsetof == 64);


// from <sys/signal.h>
enum {
  SIGHUP = 1,
  SIGINT = 2,
  SIGQUIT = 3,
  SIGILL = 4,
  SIGABRT = 6,
  SIGIOT = 6,
  SIGBUS = 10,
  SIGFPE = 8,
  SIGKILL = 9,
  SIGUSR1 = 30,
  SIGUSR2 = 31,
  SIGPIPE = 13,
  SIGALRM = 14,
  SIGTERM = 15,
  SIGSTKFLT = 0,
  SIGCHLD = 20,
  SIGCONT = 19,
  SIGSTOP = 17,
  SIGTSTP = 18,
  SIGTTIN = 21,
  SIGTTOU = 22,
  SIGIO = 23,
  SIGPOLL = 0,
  SIGWINCH = 28,
  SIGURG = 16,
  SIGTRAP = 5,
}
enum {
  SA_NOCLDSTOP = 8,
  SA_NOCLDWAIT = 32,
  SA_SIGINFO = 64,
  SA_ONSTACK = 1,
  SA_RESTART = 2,
  SA_NODEFER = 16,
  SA_RESETHAND = 4,
}

struct sigset_t { ubyte[16] opaque; }
alias  void function(int) __sighandler_t;
const __sighandler_t SIG_DFL = cast(__sighandler_t) 0;
const __sighandler_t SIG_IGN = cast(__sighandler_t) 1;
const __sighandler_t SIG_ERR = cast(__sighandler_t) -1;

/* siginfo_t is not finished... see gen_unix.c */
struct siginfo_t {
    int si_signo;
    int si_errno;
    int si_code;
}

static assert(siginfo_t.si_signo.offsetof == 0);
static assert(siginfo_t.si_errno.offsetof == 4);
static assert(siginfo_t.si_code.offsetof == 8);


struct sigaction_t {
    union {
        void function(int) sa_handler;
        void function(int, siginfo_t *, void *) sa_sigaction;
    }
    int sa_flags;
    sigset_t sa_mask;
}

static assert(sigaction_t.sa_flags.offsetof == 4);


// from <sys/mman.h>
extern(D) const void * MAP_FAILED = cast(void *) -1;
enum { PROT_NONE = 0, PROT_READ = 1, PROT_WRITE = 2, PROT_EXEC = 4 }
enum { MAP_SHARED = 0x1, MAP_PRIVATE = 0x2, MAP_ANON = 0x1000,       MAP_ANONYMOUS = 0x1000 }
enum { MS_ASYNC = 0x1, MS_SYNC = 0x0, MS_INVALIDATE = 0x2 }

enum {
  EPERM = 1,
  ENOENT = 2,
  ESRCH = 3,
  EINTR = 4,
  ENXIO = 6,
  E2BIG = 7,
  ENOEXEC = 8,
  EBADF = 9,
  ECHILD = 10,
  EINPROGRESS = 36,
  EWOULDBLOCK = 35,
  EAGAIN = 35,
}

struct sem_t { ubyte[4] opaque; }
alias uint pthread_t;
// from <sys/socket.h>
const int SOL_SOCKET = 65535

;enum {
  SO_DEBUG = 1,
  SO_ACCEPTCONN = 2,
  SO_REUSEADDR = 4,
  SO_KEEPALIVE = 8,
  SO_DONTROUTE = 16,
  SO_BROADCAST = 32,
  SO_USELOOPBACK = 64,
  SO_LINGER = 128,
  SO_OOBINLINE = 256,
  SO_REUSEPORT = 512,
  SO_TIMESTAMP = 1024,
  SO_SNDBUF = 4097,
  SO_RCVBUF = 4098,
  SO_SNDLOWAT = 4099,
  SO_RCVLOWAT = 4100,
  SO_SNDTIMEO = 4101,
  SO_RCVTIMEO = 4102,
  SO_ERROR = 4103,
  SO_TYPE = 4104,
}

struct linger {
    int l_onoff;
    int l_linger;
}

static assert(linger.l_onoff.offsetof == 0);
static assert(linger.l_linger.offsetof == 4);



const int __FD_SET_SIZEOF = 128;
const int FD_SETSIZE = 1024;

}

extern (C)
{
    int open(char*, int, ...);
    int read(int, void*, size_t);
    int write(int, void*, size_t);
    int close(int);
    off_t lseek(int, off_t, int);
    int fstat(int, struct_stat*);
    int stat(char*, struct_stat*);
    int chdir(char*);
    int mkdir(char*, int);
    int rmdir(char*);
    char* getcwd(char*, int);

    int gettimeofday(timeval*, void*);
    time_t time(time_t*);
    tm *localtime(time_t*);

    // version( Unix_Posix_Sempahore ) ?
    int sem_init (sem_t *, int, uint);
    int sem_destroy (sem_t *);
    sem_t * sem_open (char *, int, ...);
    int sem_close(sem_t *);
    int sem_wait(sem_t*);
    int sem_post(sem_t*);
    // there are a few more..

    int sigfillset(sigset_t*);
    int sigdelset(sigset_t*, int);
    int sigaction(int, sigaction_t*, sigaction_t*);
    int sigsuspend(sigset_t*);
    
    // version ( Unix_Pthread )...
    int pthread_create(pthread_t*, void*, void* (*)(void*), void*);
    int pthread_join(pthread_t, void**);
    int pthread_kill(pthread_t, int);
    pthread_t pthread_self();
    int pthread_equal(pthread_t, pthread_t);

    // version ( Unix_Sched )
    void sched_yield();

    // from <sys/mman.h>
    void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
    int munmap(void* addr, size_t len);
    int msync(void* start, size_t length, int flags);

    // from <fcntl.h>
    int fcntl(int fd, int cmd, int arg);

    // could probably rewrite fd_set stuff in D, but for now...
    struct fd_set {
	ubyte opaque[__FD_SET_SIZEOF];
    }
    private void _d_gnu_fd_set(int n, fd_set * p);
    private void _d_gnu_fd_clr(int n, fd_set * p);
    private int  _d_gnu_fd_isset(int n, fd_set * p);
    private void _d_gnu_fd_copy(fd_set * f, fd_set * t);
    private void _d_gnu_fd_zero(fd_set * p);
    // maybe these should go away in favor of fd_set methods
    void FD_SET(int n, inout fd_set p) { return _d_gnu_fd_set(n, & p); }
    void FD_CLR(int n, inout fd_set p) { return _d_gnu_fd_clr(n, & p); }
    int FD_ISSET(int n, inout fd_set p) { return _d_gnu_fd_isset(n, & p); }
    void FD_COPY(inout fd_set f, inout fd_set t) { return _d_gnu_fd_copy(& f, & t); }
    void FD_ZERO(inout fd_set p) { return _d_gnu_fd_zero(& p); }
}
