/* Copyright 2017-present Renesas Electronics Corporation and other contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef POSIX4_INCL
#define POSIX4_INCL

#include "./posix4_aux.h"

#ifdef __cplusplus
extern "C" {
#endif

#define P4_API(type,func)	type P4(func)
#define POSIX_API	P4_API
#define LINUX_API	P4_API
#define OVRDN_API	P4_API
#define NIC_API		P4_API

POSIX_API(char*, getcwd(char* buf, P4(size_t) size));
POSIX_API(int, chdir(const char* path));
POSIX_API(int, fdatasync(int fd));
POSIX_API(int, fsync(int fd));
POSIX_API(int, ftruncate(int fd, P4(off_t) length));
POSIX_API(int, scandir(const char* dirp, struct P4(dirent)*** namelist, int (*filter)(const struct P4(dirent)*), int (*compar)(const struct P4(dirent)**, const struct P4(dirent)**)));
POSIX_API(int, utime(const char* filename, const struct utimbuf* times));
POSIX_API(int, utimes(const char* filename, const struct timeval times[2]));
POSIX_API(P4(ssize_t), pread(int fd, void* buf, P4(size_t) count, P4(off_t) offset));
POSIX_API(P4(ssize_t), pwrite(int fd, const void* buf, P4(size_t) count, P4(off_t) offset));
POSIX_API(P4(ssize_t), readv(int fd, const struct P4(iovec)* iov, int iovcnt));
POSIX_API(P4(ssize_t), writev(int fd, const struct P4(iovec)* iov, int iovcnt));
POSIX_API(int, utimensat(int dirfd, const char* pathname, const struct P4(timespec) times[2], int flags));

POSIX_API(int, clock_getres(P4(clockid_t) clk_id, struct P4(timespec)* res));
POSIX_API(int, clock_gettime(P4(clockid_t) clk_id, struct P4(timespec)* tp));

POSIX_API(int, pthread_create(P4(pthread_t)* thread, P4(pthread_attr_t)* attr, void* (*start_routine)(void*), void* arg));
POSIX_API(int, pthread_join(P4(pthread_t) thread, void** retval));
POSIX_API(int, pthread_once(P4(pthread_once_t)* once_control, void (*init_routine)(void)));
POSIX_API(int, pthread_sigmask(int how, const P4(sigset_t)* set, P4(sigset_t)* oldset));
POSIX_API(int, pthread_attr_destroy(P4(pthread_attr_t)* attr));
POSIX_API(int, pthread_cond_destroy(P4(pthread_cond_t)* cond));
POSIX_API(int, pthread_cond_init(P4(pthread_cond_t)* cond, P4(pthread_condattr_t)* cond_attr));
POSIX_API(int, pthread_cond_signal(P4(pthread_cond_t)* cond));
POSIX_API(int, pthread_cond_wait(P4(pthread_cond_t)* cond, P4(pthread_mutex_t)* mutex));
POSIX_API(int, pthread_condattr_destroy(P4(pthread_condattr_t)* attr));
POSIX_API(int, pthread_condattr_init(P4(pthread_condattr_t)* attr));
POSIX_API(int, pthread_condattr_setclock(P4(pthread_condattr_t)* attr, clockid_t clock_id));
POSIX_API(int, pthread_mutex_destroy(P4(pthread_mutex_t)* mutex));
POSIX_API(int, pthread_mutex_init(P4(pthread_mutex_t)* mutex, const P4(pthread_mutexattr_t)* mutexattr));
POSIX_API(int, pthread_mutex_lock(P4(pthread_mutex_t)* mutex));
POSIX_API(int, pthread_mutex_unlock(P4(pthread_mutex_t)* mutex));
POSIX_API(int, pthread_rwlock_destroy(P4(pthread_rwlock_t)* rwlock));
POSIX_API(int, pthread_rwlock_init(P4(pthread_rwlock_t)* rwlock, const P4(pthread_rwlockattr_t)* attr));
POSIX_API(int, pthread_rwlock_rdlock(P4(pthread_rwlock_t)* rwlock));
POSIX_API(int, pthread_rwlock_unlock(P4(pthread_rwlock_t)* rwlock));
	POSIX_API(int, pthread_cond_broadcast(P4(pthread_cond_t)* cond));
	POSIX_API(int, pthread_cond_timedwait(P4(pthread_cond_t)* cond, P4(pthread_mutex_t)* mutex, const struct P4(timespec)* abstime));
	POSIX_API(P4(pthread_t), pthread_self(void));
	POSIX_API(int, pthread_equal(P4(pthread_t) t1, P4(pthread_t) t2));
	POSIX_API(int, pthread_mutex_trylock(P4(pthread_mutex_t)* mutex));
	POSIX_API(int, pthread_rwlock_tryrdlock(P4(pthread_rwlock_t)* rwlock));
	POSIX_API(int, pthread_rwlock_trywrlock(P4(pthread_rwlock_t)* rwlock));
	POSIX_API(int, pthread_rwlock_wrlock(P4(pthread_rwlock_t)* rwlock));
	POSIX_API(int, sem_init(P4(sem_t)* sem, int pshared, unsigned int value));
	POSIX_API(int, sem_destroy(P4(sem_t)* sem));
	POSIX_API(int, sem_wait(P4(sem_t)* sem));
	POSIX_API(int, sem_trywait(P4(sem_t)* sem));
	POSIX_API(int, sem_post(P4(sem_t)* sem));

#define CMSG_ALIGN(len)	(((len) + sizeof(P4(size_t)) - 1) & (P4(size_t))~(sizeof(P4(size_t)) - 1))
#define CMSG_SPACE(len)	(CMSG_ALIGN(len) + CMSG_ALIGN(sizeof(struct P4(cmsghdr))))
#define CMSG_LEN(len)	(CMSG_ALIGN(sizeof(struct P4(cmsghdr))) + (len))
#define CMSG_FIRSTHDR(mhdr)	(											\
	(P4(size_t))(mhdr)->msg_controllen >= sizeof(struct P4(cmsghdr))	\
	? (struct P4(cmsghdr)*)(mhdr)->msg_control : (struct P4(cmsghdr)*)0	\
)
P4_API(struct P4(cmsghdr)*, cmsg_nxthdr(struct P4(msghdr)* mhdr, struct P4(cmsghdr)* cmsg));
#define CMSG_NXTHDR(mhdr, cmsg)	P4(cmsg_nxthdr)(mhdr, cmsg)
#define CMSG_DATA(cmsg)	((unsigned char*)((struct P4(cmsghdr)*)(cmsg) + 1))

POSIX_API(int, accept(int sockfd, struct P4(sockaddr)* addr, P4(socklen_t)* addrlen));
POSIX_API(int, bind(int sockfd, const struct P4(sockaddr)* addr, P4(socklen_t) addrlen));
POSIX_API(int, connect(int sockfd, const struct P4(sockaddr)* addr, P4(socklen_t) addrlen));
POSIX_API(void, freeaddrinfo(struct P4(addrinfo)* res));
POSIX_API(int, getaddrinfo(const char* node, const char* service, const struct P4(addrinfo)* hints, struct P4(addrinfo)** res));
	POSIX_API(int, getpeername(int sockfd, struct P4(sockaddr)* addr, P4(socklen_t)* addrlen));
POSIX_API(int, getsockname(int sockfd, struct P4(sockaddr)* addr, P4(socklen_t)* addrlen));
POSIX_API(int, getsockopt(int sockfd, int level, int optname, void* optval, P4(socklen_t)* optlen));
POSIX_API(uint32_t, htonl(uint32_t hostlong));
POSIX_API(uint16_t, htons(uint16_t hostshort));
POSIX_API(unsigned int, if_nametoindex(const char* ifname));
POSIX_API(int, listen(int sockfd, int backlog));
POSIX_API(uint16_t, ntohs(uint16_t netshort));
POSIX_API(P4(ssize_t), recvmsg(int sockfd, struct P4(msghdr)* msg, int flags));
POSIX_API(P4(ssize_t), sendmsg(int sockfd, const struct P4(msghdr)* msg, int flags));
POSIX_API(int, setsockopt(int sockfd, int level, int optname, const void* optval, P4(socklen_t) optlen));
POSIX_API(int, shutdown(int sockfd, int how));
POSIX_API(int, socket(int domain, int type, int protocol));

POSIX_API(int, nanosleep(const struct P4(timespec)* req, struct P4(timespec)* rem));
POSIX_API(int, pipe(int pipefd[2]));
POSIX_API(long, sysconf(int name));

LINUX_API(P4(ssize_t), preadv(int fd, const struct P4(iovec)* iov, int iovcnt, P4(off_t) offset));
LINUX_API(P4(ssize_t), pwritev(int fd, const struct P4(iovec)* iov, int iovcnt, P4(off_t) offset));

LINUX_API(int, epoll_create(int size));
LINUX_API(int, epoll_create1(int flags));
LINUX_API(int, epoll_ctl(int epfd, int op, int fd, struct P4(poll_event)* event));
LINUX_API(int, epoll_pwait(int epfd, struct P4(poll_event)* events, int maxevents, int timeout, const P4(sigset_t)* sigmask));
LINUX_API(int, epoll_wait(int epfd, struct P4(poll_event)* events, int maxevents, int timeout));
LINUX_API(int, eventfd(unsigned int initval, int flags));
LINUX_API(int, eventfd2(unsigned int initval, int flags));

LINUX_API(int, accept4(int fd, struct P4(sockaddr)* addr, P4(socklen_t)* addr_len, int flags));
LINUX_API(int, socketcall(int call, unsigned long* args));

LINUX_API(int, ioctl(int fd, unsigned long request, ...));
LINUX_API(long, syscall(long number, ...));
LINUX_API(int, pipe2(int pipefd[2], int flags));

LINUX_API(void*, dlopen(const char* filename, int flag));
LINUX_API(void*, dlsym(void* handle, char* symbol));
LINUX_API(int, dlclose(void* handle));

LINUX_API(char**, backtrace_symbols(void*const* buffer, int size));
LINUX_API(int, backtrace(void** buffer, int size));

OVRDN_API(void, abort(void));
OVRDN_API(int, gettimeofday(struct timeval* tv, void* tz));
OVRDN_API(P4(ssize_t), read(int fd, void* buf, P4(size_t) count));
OVRDN_API(P4(ssize_t), write(int fd, const void* buf, P4(size_t) count));
OVRDN_API(int, open(const char* pathname, ...));
OVRDN_API(int, close(int fd));
OVRDN_API(int, unlink(const char* pathname));
OVRDN_API(int, mkdir(const char* pathname, P4(mode_t) mode));
OVRDN_API(int, rmdir(const char* pathname));
OVRDN_API(int, stat(const char* pathname, P4(stat_t)* buf));
OVRDN_API(int, fstat(int fd, P4(stat_t)* buf));

NIC_API(char*, nic_enumerate(void));
NIC_API(int, nic_ifup(const char* nic, const char* params));
NIC_API(int, nic_ifdown(const char* nic));
NIC_API(char*, nic_ifconfig(const char* nic));
NIC_API(int, nic_ntpdate(const char* nic, const char* server, int port, int timeout));

#undef NIC_API
#undef OVRDN_API
#undef LINUX_API
#undef POSIX_API

#if !defined( POSIX4_ITSELF )

	// functions
	#define getcwd						P4(getcwd)
	#define chdir						P4(chdir)
	#define fdatasync					P4(fdatasync)
	#define fsync						P4(fsync)
	#define ftruncate					P4(ftruncate)
	#define scandir						P4(scandir)
	#define utime						P4(utime)
	#define utimes						P4(utimes)
	#define pread						P4(pread)
	#define pwrite						P4(pwrite)
	#define readv						P4(readv)
	#define writev						P4(writev)
	#define utimensat					P4(utimensat)

	#define clock_getres				P4(clock_getres)
	#define clock_gettime				P4(clock_gettime)

	#define pthread_create				P4(pthread_create)
	#define pthread_join				P4(pthread_join)
	#define pthread_once				P4(pthread_once)
	#define pthread_sigmask				P4(pthread_sigmask)
	#define pthread_attr_destroy		P4(pthread_attr_destroy)
	#define pthread_cond_destroy		P4(pthread_cond_destroy)
	#define pthread_cond_init			P4(pthread_cond_init)
	#define pthread_cond_signal			P4(pthread_cond_signal)
	#define pthread_cond_wait			P4(pthread_cond_wait)
	#define pthread_condattr_destroy	P4(pthread_condattr_destroy)
	#define pthread_condattr_init		P4(pthread_condattr_init)
	#define pthread_condattr_setclock	P4(pthread_condattr_setclock)
	#define pthread_mutex_destroy		P4(pthread_mutex_destroy)
	#define pthread_mutex_init			P4(pthread_mutex_init)
	#define pthread_mutex_lock			P4(pthread_mutex_lock)
	#define pthread_mutex_unlock		P4(pthread_mutex_unlock)
	#define pthread_rwlock_destroy		P4(pthread_rwlock_destroy)
	#define pthread_rwlock_init			P4(pthread_rwlock_init)
	#define pthread_rwlock_rdlock		P4(pthread_rwlock_rdlock)
	#define pthread_rwlock_unlock		P4(pthread_rwlock_unlock)
		#define pthread_cond_broadcast		P4(pthread_cond_broadcast)
		#define pthread_cond_timedwait		P4(pthread_cond_timedwait)
		#define pthread_self				P4(pthread_self)
		#define pthread_equal				P4(pthread_equal)
		#define pthread_mutex_trylock		P4(pthread_mutex_trylock)
		#define pthread_rwlock_tryrdlock	P4(pthread_rwlock_tryrdlock)
		#define pthread_rwlock_trywrlock	P4(pthread_rwlock_trywrlock)
		#define pthread_rwlock_wrlock		P4(pthread_rwlock_wrlock)
		#define sem_init					P4(sem_init)
		#define sem_destroy					P4(sem_destroy)
		#define sem_wait					P4(sem_wait)
		#define sem_trywait					P4(sem_trywait)
		#define sem_post					P4(sem_post)

	#define accept						P4(accept)
	#define bind						P4(bind)
	#define connect						P4(connect)
	#define freeaddrinfo				P4(freeaddrinfo)
	#define getaddrinfo					P4(getaddrinfo)
		#define getpeername					P4(getpeername)
	#define getsockname					P4(getsockname)
	#define getsockopt					P4(getsockopt)
	#define htonl						P4(htonl)
	#define htons						P4(htons)
	#define if_nametoindex				P4(if_nametoindex)
	#define listen						P4(listen)
	#define ntohs						P4(ntohs)
	#define recvmsg						P4(recvmsg)
	#define sendmsg						P4(sendmsg)
	#define setsockopt					P4(setsockopt)
	#define shutdown					P4(shutdown)
	#define socket(d,t,p)				P4(socket)(d, t, p)

	#define nanosleep					P4(nanosleep)
	#define pipe						P4(pipe)
	#define sysconf						P4(sysconf)

	#define preadv						P4(preadv)
	#define pwritev						P4(pwritev)

	#define epoll_create				P4(epoll_create)
	#define epoll_create1				P4(epoll_create1)
	#define epoll_ctl					P4(epoll_ctl)
	#define epoll_pwait					P4(epoll_pwait)
	#define epoll_wait					P4(epoll_wait)
	#define eventfd						P4(eventfd)
	#define eventfd2					P4(eventfd2)

	#define accept4						P4(accept4)
	#define socketcall					P4(socketcall)

	#define ioctl						P4(ioctl)
	#define syscall(n, ...)				P4(syscall)(n, __VA_ARGS__)
	#define pipe2						P4(pipe2)

	#define dlopen						P4(dlopen)
	#define dlsym						P4(dlsym)
	#define dlclose						P4(dlclose)

	#define backtrace_symbols			P4(backtrace_symbols)
	#define backtrace					P4(backtrace)

	#define abort						P4(abort)
	#define gettimeofday(tv,tz)			P4(gettimeofday)(tv, tz)
	#define read(fd,buf,count)			P4(read)(fd, buf, count)
	#define write(fd,buf,count)			P4(write)(fd, buf, count)
	#define open(pathname, ...)			P4(open)(pathname, __VA_ARGS__)
	#define close(fd)					P4(close)(fd)
	#define unlink(pathname)			P4(unlink)(pathname)
	#define mkdir(pathname,mode)		P4(mkdir)(pathname,mode)
	#define rmdir(pathname)				P4(rmdir)(pathname)
	#define stat(pathname,buf)			P4(stat)(pathname, buf)
	#define fstat(fd,buf)				P4(fstat)(fd, buf)

	#define nic_enumerate				P4(nic_enumerate)
	#define nic_ifup					P4(nic_ifup)
	#define nic_ifdown					P4(nic_ifdown)
	#define nic_ifconfig				P4(nic_ifconfig)
	#define nic_ntpdate					P4(nic_ntpdate)

	// structs
	#define addrinfo					P4(addrinfo)
	#define cmsghdr						P4(cmsghdr)
	#define dirent						P4(dirent)
	#define in_addr						P4(in_addr)
	#define in6_addr					P4(in6_addr)
	#define iovec						P4(iovec)
	#define msghdr						P4(msghdr)
	#define poll_event					P4(poll_event)
	#define sockaddr					P4(sockaddr)
	#define sockaddr_in					P4(sockaddr_in)
	#define sockaddr_in6				P4(sockaddr_in6)
	#define sockaddr_storage			P4(sockaddr_storage)
	#define termios						P4(termios)
	#define timespec					P4(timespec)
	#define timeval						P4(timeval)
	#define utimbuf						P4(utimbuf)

	// typedefs
	#define clockid_t					P4(clockid_t)
	#define ip_mreq						P4(ip_mreq)
	#define ipv6_mreq					P4(ipv6_mreq)
	#define in_addr_t					P4(in_addr_t)
	#define in_port_t					P4(in_port_t)
	#define off_t						P4(off_t)
	#define pthread_attr_t				P4(pthread_attr_t)
	#define pthread_cond_t				P4(pthread_cond_t)
	#define pthread_condattr_t			P4(pthread_condattr_t)
	#define pthread_key_t				P4(pthread_key_t)
	#define pthread_mutex_t				P4(pthread_mutex_t)
	#define pthread_mutexattr_t			P4(pthread_mutexattr_t)
	#define pthread_once_t				P4(pthread_once_t)
	#define pthread_rwlock_t			P4(pthread_rwlock_t)
	#define pthread_rwlockattr_t		P4(pthread_rwlockattr_t)
	#define pthread_t					P4(pthread_t)
	#define sa_family_t					P4(sa_family_t)
	#define sem_t						P4(sem_t)
	#define sigset_t					P4(sigset_t)
	#define size_t						P4(size_t)
	#define socklen_t					P4(socklen_t)
	#define ssize_t						P4(ssize_t)
	#define stat_t						P4(stat_t)

#endif	// #if !defined( POSIX4_ITSELF )

#ifdef __cplusplus
}
#endif

#endif	// #ifndef POSIX4_INCL
