/* 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 POSIX4MBED_INCL
#define POSIX4MBED_INCL

#include <stdarg.h>
#include <errno.h>

#if defined(MBED_DEBUG)
	#define DEBUG
	#define ENABLE_DEBUG_LOG
	#define DEBUG_POSIX_BRIDGE
#endif	// #if defined(MBED_DEBUG)

#define POSIX4_ITSELF
#include "../../posix4.h"

#if !defined(DEBUG_POSIX_BRIDGE)
	#define TRACE(fmt, ...) ((void)0)
#else	// #if !defined(DEBUG_POSIX_BRIDGE)
	#define INFO  "@- "
	#define ENTER "-->"
	#define LEAVE "<--"
	#define TRACE mbed::debug::trace
#endif	// #if !defined(DEBUG_POSIX_BRIDGE)

#define CALLED_FROM __builtin_return_address(0)

namespace mbed {

	namespace debug {
		void trace(const char* fmt, ...);
	}	// namespace debug

	namespace posix {
		namespace obsolete {
			int gettimeofday(P4(timeval)* tv, timezone* tz);
		}	// namespace obsolete
		char* getcwd(char* buf, P4(size_t) size);
		int chdir(const char* path);
		int fdatasync(int fd);
		int fsync(int fd);
		int ftruncate(int fd, P4(off_t) length);
		int scandir(const char* dirp, P4(dirent)*** namelist, int (*filter)(const P4(dirent)*), int (*compar)(const P4(dirent)**, const P4(dirent)**));
		int utime(const char* filename, const P4(utimbuf)* times);
		int utimes(const char* filename, const P4(timeval) times[2]);
		P4(ssize_t) pread(int fd, void* buf, P4(size_t) count, P4(off_t) offset);
		P4(ssize_t) pwrite(int fd, const void* buf, P4(size_t) count, P4(off_t) offset);
		P4(ssize_t) readv(int fd, const P4(iovec)* iov, int iovcnt);
		P4(ssize_t) writev(int fd, const P4(iovec)* iov, int iovcnt);
		int utimensat(int dirfd, const char* pathname, const P4(timespec) times[2], int flags);
		namespace clock {
			int getres(P4(clockid_t) clk_id, P4(timespec)* res);
			int gettime(P4(clockid_t) clk_id, P4(timespec)* tp);
		}	// namespace clock
		namespace pthread {
			int create(P4(pthread_t)* thread, P4(pthread_attr_t)* attr, void* (*start_routine)(void*), void* arg);
			int join(P4(pthread_t) thread, void** retval);
			int once(P4(pthread_once_t)* once_control, void (*init_routine)(void));
			int sigmask(int how, const P4(sigset_t)* set, P4(sigset_t)* oldset);
			namespace attr {
				int destroy(P4(pthread_attr_t)* attr);
			}	// namespace attr
			namespace cond {
				int destroy(P4(pthread_cond_t)* cond);
				int init(P4(pthread_cond_t)* cond, P4(pthread_condattr_t)* cond_attr);
				int signal(P4(pthread_cond_t)* cond);
				int wait(P4(pthread_cond_t)* cond, P4(pthread_mutex_t)* mutex);
			}	// namespace cond
			namespace condattr {
				int destroy(P4(pthread_condattr_t)* attr);
				int init(P4(pthread_condattr_t)* attr);
				int setclock(P4(pthread_condattr_t)* attr, P4(clockid_t) clock_id);
			}	// namespace condattr
			namespace mutex {
				int destroy(P4(pthread_mutex_t)* mutex);
				int init(P4(pthread_mutex_t)* mutex, const P4(pthread_mutexattr_t)* mutexattr);
				int lock(P4(pthread_mutex_t)* mutex);
				int unlock(P4(pthread_mutex_t)* mutex);
			}	// namespace mutex
			namespace rwlock {
				int destroy(P4(pthread_rwlock_t)* rwlock);
				int init(P4(pthread_rwlock_t)* rwlock, const P4(pthread_rwlockattr_t)* attr);
				int rdlock(P4(pthread_rwlock_t)* rwlock);
				int unlock(P4(pthread_rwlock_t)* rwlock);
			}	// namespace rwlock
		}	// namespace pthread
		namespace sock {
			int accept(int sockfd, P4(sockaddr)* addr, P4(socklen_t)* addrlen);
			int bind(int sockfd, const P4(sockaddr)* addr, P4(socklen_t) addrlen);
			int connect(int sockfd, const P4(sockaddr)* addr, P4(socklen_t) addrlen);
			void freeaddrinfo(P4(addrinfo)* res);
			int getaddrinfo(const char* node, const char* service, const P4(addrinfo)* hints, P4(addrinfo)** res);
			int getsockname(int sockfd, P4(sockaddr)* addr, P4(socklen_t)* addrlen);
			int getsockopt(int sockfd, int level, int optname, void* optval, P4(socklen_t)* optlen);
			uint32_t htonl(uint32_t hostlong);
			uint16_t htons(uint16_t hostshort);
			unsigned int if_nametoindex(const char* ifname);
			int listen(int sockfd, int backlog);
			uint16_t ntohs(uint16_t netshort);
			P4(ssize_t) recvmsg(int sockfd, P4(msghdr)* msg, int flags);
			P4(ssize_t) sendmsg(int sockfd, const P4(msghdr)* msg, int flags);
			int setsockopt(int sockfd, int level, int optname, const void* optval, P4(socklen_t) optlen);
			int shutdown(int sockfd, int how);
			int socket(int domain, int type, int protocol);
		}	// namespace sock
		namespace sys {
			int nanosleep(const P4(timespec)* req, P4(timespec)* rem);
			int pipe(int pipefd[2]);
			long sysconf(int name);
		}	// namespace sys
	}	// namespace posix

	namespace linux {
		P4(ssize_t) preadv(int fd, const P4(iovec)* iov, int iovcnt, P4(off_t) offset);
		P4(ssize_t) pwritev(int fd, const P4(iovec)* iov, int iovcnt, P4(off_t) offset);
		namespace epoll {
			int create(int size);
			int create1(int flags);
			int ctl(int epfd, int op, int fd, P4(poll_event)* event);
			int pwait(int epfd, P4(poll_event)* events, int maxevents, int timeout, const P4(sigset_t)* sigmask);
			int wait(int epfd, P4(poll_event)* events, int maxevents, int timeout);
			int eventfd(unsigned int initval, int flags);
			int eventfd2(unsigned int initval, int flags);
		}	// namespace epoll
		namespace sock {
			int accept4(int fd, P4(sockaddr)* addr, P4(socklen_t)* addr_len, int flags);
			int socketcall(int call, unsigned long* args);
		}	// namespace sock
		namespace sys {
			int ioctl(int fd, unsigned long request, va_list args);
			long syscall(long number, va_list args);
			int pipe2(int pipefd[2], int flags);
			void* dlopen(const char* filename, int flag);
			void* dlsym(void* handle, char* symbol);
			int dlclose(void* handle);
		}	// namespace sys
		namespace debug {
			char** backtrace_symbols(void*const* buffer, int size);
			int backtrace(void** buffer, int size);
		}	// namespace debug
	}	// namespace linux

	namespace overridden {
		void abort();
		int gettimeofday(P4(timeval)* tv, void* tz);
		P4(ssize_t) read(int fd, void* buf, P4(size_t) count);
		P4(ssize_t) write(int fd, const void* buf, P4(size_t) count);
		int open(const char* pathname, va_list args);
		int close(int fd);
		int unlink(const char* pathname);
		int mkdir(const char* pathname, P4(mode_t) mode);
		int rmdir(const char* pathname);
		int stat(const char* pathname, P4(stat_t)* buf);
		int fstat(int fd, P4(stat_t)* buf);
	}	// namespace overridden

	namespace nic {
		char* enumerate();
		int ifup(const char* nic, const char* params);
		int ifdown(const char* nic);
		char* ifconfig(const char* nic);
		int ntpdate(const char* nic, const char* server, int port, int timeout);
	}	// namespace nic

}	// namespace mbed

using namespace mbed;

#endif	// #ifndef POSIX4MBED_INCL
