#include <sys/hostabi.h>
#include <stdbool.h>

#ifndef MEM
#define MEM const char *
#endif

#if defined(SYSCALL) && !defined(SYSCALL_DIOS)
#define SYSCALL_DIOS(...) SYSCALL(__VA_ARGS__)
#define SYSCALL_DIOS_UNDEF
#endif

#ifndef VOID
#define VOID void
#define VOID_UNDEF
#endif

#ifdef __cplusplus
    #define TOP ::
#else
    #define TOP
#endif

SYSCALL_DIOS( get_process_tasks, CONTINUE,   __dios_task*, ( __dios_task _1 ) )
SYSCALL_DIOS( start_task,        RESCHEDULE, __dios_task,  ( __dios_task_routine _1, void *_2, int _3 ) )
SYSCALL_DIOS( resize_tls,        CONTINUE,   void*, ( __dios_task _1, int _2 ) )
SYSCALL_DIOS( get_fault_config,  CONTINUE,   int, ( int _1 ) )
SYSCALL_DIOS( exit_process,      RESCHEDULE, VOID, ( int _1 ) )
SYSCALL_DIOS( configure_fault,   CONTINUE,   int, ( int _1, int _2 ) )
SYSCALL_DIOS( die,               RESCHEDULE, VOID, () )
SYSCALL_DIOS( kill_task,         RESCHEDULE, VOID, ( __dios_task _1 ) )
SYSCALL_DIOS( kill_process,      RESCHEDULE, VOID, ( int _1 ) )
SYSCALL_DIOS( yield,             RESCHEDULE, VOID, ( ) )
SYSCALL_DIOS( fault_handler,     CONTINUE,   VOID, ( int _1, struct _VM_Frame * _2, int _3 ) )
SYSCALL_DIOS( pipe,              CONTINUE,   int, ( OUT(int*) _1 ) )
SYSCALL_DIOS( open,              CONTINUE,   int, ( MEM _1, int _2, mode_t _3 ) )
SYSCALL_DIOS( fcntl,             CONTINUE,   int,     ( int _1, int _2, va_list *_3 ) )
SYSCALL_DIOS( sysfork,           CONTINUE,   VOID, ( pid_t *_1 ) )
SYSCALL_DIOS( hardware_concurrency, CONTINUE, int, () ) /* TODO: use sysctl for this */

SYSCALL_DIOS( nondet_i1,         CONTINUE, bool, ( int _1 ) )
SYSCALL_DIOS( nondet_i8,         CONTINUE, int8_t, ( int _1 ) )
SYSCALL_DIOS( nondet_i16,        CONTINUE, int16_t, ( int _1 ) )
SYSCALL_DIOS( nondet_i32,        CONTINUE, int32_t, ( int _1 ) )
SYSCALL_DIOS( nondet_i64,        CONTINUE, int64_t, ( int _1 ) )

#ifdef __cplusplus
SYSCALL_DIOS( register_monitor,  CONTINUE,   VOID, ( __dios::Monitor *_1 ) )
#else
SYSCALL_DIOS( register_monitor,  CONTINUE,   VOID, ( void *_1 ) )
#endif

SYSCALL( clock_gettime, CONTINUE, int, ( clockid_t _1, STRUCT(struct TOP timespec *) _2 ) )
SYSCALL( clock_settime, CONTINUE, int, ( clockid_t _1, STRUCT(const struct TOP timespec *) _2 ) )

SYSCALL( gettimeofday , CONTINUE, int, ( STRUCT(struct TOP timeval *) _1, STRUCT(struct TOP timezone *) _2 ) )
SYSCALL( settimeofday , CONTINUE, int, ( STRUCT(const struct TOP timeval *) _1,
                                         STRUCT(const struct TOP timezone *) _2 ) )

SYSCALL( rename,      CONTINUE, int,     ( MEM _1, MEM _2 ) )
SYSCALL( lseek,       CONTINUE, off_t,   ( int _1, off_t _2, int _3 ) )
SYSCALL( accept4,     CONTINUE, int,     ( int _1, STRUCT(struct TOP sockaddr *) _2,
                                           OUT(socklen_t *) _3, int _4 ) )
SYSCALL( linkat,      CONTINUE, int,     ( int _1, MEM _2, int _3, MEM _4, int _5 ) )
SYSCALL( mkdir,       CONTINUE, int,     ( MEM _1, mode_t _2 ) )
SYSCALL( sync,        CONTINUE, VOID,    () )

SYSCALL( chmod,       CONTINUE, int,     ( MEM _1, mode_t _2 ) )
SYSCALL( renameat,    CONTINUE, int,     ( int _1, MEM _2, int _3, MEM _4 ) )
SYSCALL( mknod,       CONTINUE, int,     ( MEM _1, mode_t _2, dev_t _3 ) )
SYSCALL( symlinkat,   CONTINUE, int,     ( MEM _1, int _2, MEM _3 ) )
SYSCALL( kill,      TRAMPOLINE, int,     ( pid_t _1, int _2 ) )
SYSCALL( connect,     CONTINUE, int,     ( int _1, COUNT(const struct TOP sockaddr *) _2, socklen_t _3 ) )
SYSCALL( getsockname, CONTINUE, int,     ( int _1, STRUCT(struct TOP sockaddr *) _2, OUT(socklen_t *) _3 ) )
SYSCALL( close,       CONTINUE, int,     ( int _1 ) )
SYSCALL( recvfrom,    CONTINUE, ssize_t, ( int _1, COUNT(void *) _2, size_t _3, int _4,
                                           STRUCT(struct TOP sockaddr *) _5, OUT(socklen_t *) _6 ) )
SYSCALL( write,       CONTINUE, ssize_t, ( int _1, COUNT(const void *) _2, size_t _3 ) )
SYSCALL( bind,        CONTINUE, int,     ( int _1, COUNT(const struct TOP sockaddr *) _2, socklen_t _3 ) )
SYSCALL( fchmodat,    CONTINUE, int,     ( int _1, MEM _2, mode_t _3, int _4 ) )
SYSCALL( lstat,       CONTINUE, int,     ( MEM _1, STRUCT(struct stat *) _2 ) )
SYSCALL( umask,       CONTINUE, mode_t,  ( mode_t _1 ) )
SYSCALL( access,      CONTINUE, int,     ( MEM _1, int _2 ) )
SYSCALL( faccessat,   CONTINUE, int,     ( int _1, MEM _2 , int _3, int _4 ) )
SYSCALL( fchmod,      CONTINUE, int,     ( int _1, mode_t _2 ) )
SYSCALL( rmdir,       CONTINUE, int,     ( MEM _1 ) )
SYSCALL( accept,      CONTINUE, int,     ( int _1, STRUCT(struct TOP sockaddr *) _2, OUT(socklen_t *) _3 ) )
SYSCALL( dup,         CONTINUE, int,     ( int _1 ) )
SYSCALL( fstat,       CONTINUE, int,     ( int _1, STRUCT(struct stat *) _2 ) )
SYSCALL( getpid,      CONTINUE, pid_t,   () )
SYSCALL( getppid,     CONTINUE, pid_t,   () )
SYSCALL( getsid,      CONTINUE, pid_t,   ( pid_t _1 ) )
SYSCALL( getpgid,     CONTINUE, pid_t,   ( pid_t _1 ) )
SYSCALL( getpgrp,     CONTINUE, pid_t,   () )
SYSCALL( setsid,      CONTINUE, pid_t,   () )
SYSCALL( setpgid,     CONTINUE, int,     ( pid_t _1, pid_t _2 ) )
SYSCALL( stat,        CONTINUE, int,     ( MEM _1, STRUCT(struct stat *) _2 ) )
SYSCALL( truncate,    CONTINUE, int,     ( MEM _1, off_t _2 ) )
SYSCALL( dup2,        CONTINUE, int,     ( int _1, int _2 ) )
SYSCALL( read,        CONTINUE, ssize_t, ( int _1, COUNT(void *) _2, size_t _3 ) )
SYSCALL( openat,      CONTINUE, int,     ( int _1, MEM _2, int _3, mode_t _4 ) )
SYSCALL( sendto,      CONTINUE, ssize_t, ( int _1, COUNT(const void *) _2, size_t _3, int _4,
                                           COUNT(const struct TOP sockaddr *) _5, socklen_t _6 ) )
SYSCALL( symlink,     CONTINUE, int,     ( MEM _1, MEM _2 ) )
SYSCALL( readlink,    CONTINUE, ssize_t, ( MEM _1, COUNT(char *) _2, size_t _3 ) )
SYSCALL( fchdir,      CONTINUE, int,     ( int _1 ) )
SYSCALL( ftruncate,   CONTINUE, int,     ( int _1, off_t _2 ) )
SYSCALL( getpeername, CONTINUE, int,     ( int _1, STRUCT(struct TOP sockaddr *) _2, OUT(socklen_t *) _3 ) )
SYSCALL( unlink,      CONTINUE, int,     ( MEM _1 ) )
SYSCALL( unlinkat,    CONTINUE, int,     ( int _1, MEM _2, int _3 ))
SYSCALL( mknodat,     CONTINUE, int,     ( int _1, MEM _2, mode_t _3, dev_t _4 ) )
SYSCALL( readlinkat,  CONTINUE, ssize_t, ( int _1, MEM _2, COUNT(char *) _3, size_t _4 ) )
SYSCALL( chdir,       CONTINUE, int,     ( MEM _1 ) )
SYSCALL( socket,      CONTINUE, int,     ( int _1, int _2, int _3 ) )
SYSCALL( fsync,       CONTINUE, int,     ( int _1 ) )
SYSCALL( socketpair,  CONTINUE, int,     ( int _1, int _2, int _3, OUT(int *) _4 ) )
SYSCALL( link,        CONTINUE, int,     ( MEM _1, MEM _2 ) )
SYSCALL( listen,      CONTINUE, int,     ( int _1, int _2 ) )
SYSCALL( mkdirat,     CONTINUE, int,     ( int _1, MEM _2, mode_t _3 ) )
SYSCALL( wait4,       CONTINUE, pid_t,   ( pid_t _1, int *_2, int _3, STRUCT(struct TOP rusage *) _4 ) )
SYSCALL( flock,       CONTINUE, int,     ( int _1, int _2 ) )

#if _HOST_is_linux /* linux-specific syscalls */
SYSCALL( creat,       CONTINUE, int,     ( MEM _1, mode_t _2 ) )
SYSCALL( fdatasync,   CONTINUE, int,     ( int _1 ) )
SYSCALL( syncfs,      CONTINUE, int,     ( int _1 ) )
SYSCALL( uname,       CONTINUE, int,     ( STRUCT(struct TOP utsname *) _1 ) )
SYSCALL( getcwd,      CONTINUE, char*,   ( COUNT(char*) _1, size_t _2 ) )
SYSCALL( rt_sigaction, CONTINUE, int,    ( int _1, const struct TOP sigaction * _2,
                                           struct TOP sigaction * _3, size_t _4 ) )
#endif

#if _HOST_is_openbsd
SYSCALL( sigaction,   CONTINUE, int,     ( int _1, const struct TOP sigaction * _2,
                                           struct TOP sigaction * _3 ) )
SYSCALL( __getcwd,    CONTINUE, int,     ( COUNT(char*) _1, size_t _2 ) )
#endif

SYSCALL( fstatfs,     CONTINUE, int,     ( int _1, STRUCT(struct TOP statfs *) _2 ) )
SYSCALL( statfs,      CONTINUE, int,     ( MEM _1, STRUCT(struct TOP statfs *) _2 ) )

#undef MEM
#undef TOP

#ifdef SYSCALL_DIOS_UNDEF
#undef SYSCALL_DIOS_UNDEF
#undef SYSCALL_DIOS
#endif

#ifdef VOID_UNDEF
#undef VOID_UNDEF
#undef VOID
#endif
