#ifndef __INC_LIBTHECORE_STDAFX_H__
#define __INC_LIBTHECORE_STDAFX_H__

#if defined(__GNUC__)
#define INLINE __inline__
#elif defined(_MSC_VER)
#define INLINE inline
#endif

#ifdef __WIN32__
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <tchar.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <conio.h>
#include <process.h>
#include <limits.h>
#include <math.h>
#include <locale.h>
#include <io.h>
#include <direct.h>
#include <fcntl.h>

#include "xdirent.h"
#include "xgetopt.h"

#define S_ISDIR(m)	(m & _S_IFDIR)
#define snprintf _snprintf

struct timespec
{
    time_t  tv_sec;         /* seconds */
    long    tv_nsec;        /* and nanoseconds */
};

#define __USE_SELECT__

#define PATH_MAX _MAX_PATH

// C runtime library adjustments
#define strlcat(dst, src, size) strcat_s(dst, size, src)
#define strlcpy(dst, src, size) strncpy_s(dst, size, src, _TRUNCATE)
#define strtoull(str, endptr, base) _strtoui64(str, endptr, base)
#define strtof(str, endptr) (float)strtod(str, endptr)
#define strcasecmp(s1, s2) stricmp(s1, s2)
#define strncasecmp(s1, s2, n) strnicmp(s1, s2, n)
#define atoll(str) _atoi64(str)
#define localtime_r(timet, result) localtime_s(result, timet)
#define strtok_r(s, delim, ptrptr) strtok_s(s, delim, ptrptr)

#include <boost/__typeof/__typeof.hpp>
#define __typeof(t) BOOST_TYPEOF(t)

// dummy declaration of non-supported signals
#define SIGUSR1     30  /* user defined signal 1 */
#define SIGUSR2     31  /* user defined signal 2 */

inline void usleep(unsigned long usec) {
	::Sleep(usec / 1000);
}
inline unsigned sleep(unsigned sec) {
	::Sleep(sec * 1000);
	return 0;
}
inline double rint(double x)
{
	return ::floor(x+.5);
}


#else

/* ### LINUX-BLOCK-BEGIN (stdafx.h __USE_SELECT__) ####################### */
/* Linux gets the epoll backend in fdwatch.c, so it must NOT fall back to the
 * select() one.  That branch is not merely slow here, it is wrong:
 *   - it calls select(0, ...); nfds == 0 is fine on Windows where the
 *     argument is ignored, but on Linux it means "watch nothing";
 *   - game calls fdwatch_new(4096) while FD_SETSIZE is 1024, and
 *     socket_accept() (socket.c:232) accepts descriptors up to 65500;
 *   - it uses a compacted index model and swap-removes on delete, whereas
 *     db's RemovePeer() deletes mid-iteration, which would silently re-point
 *     later event indices at the wrong peer.
 * The original directive is the "#ifndef __FreeBSD__" preserved below. */
#if !defined(__FreeBSD__) && !defined(__linux__)
/* ### LINUX-BLOCK-END (stdafx.h __USE_SELECT__) ######################### */
#define __USE_SELECT__
#ifdef __CYGWIN__
#define _POSIX_SOURCE 1
#endif
#endif

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <dirent.h>

#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>

#include <sys/signal.h>
#include <sys/wait.h>

#include <pthread.h>
#include <semaphore.h>

#ifdef __FreeBSD__
#include <sys/event.h>
#endif

/* ### LINUX-BLOCK-BEGIN (stdafx.h linux headers) ######################## */
#if defined(__linux__)
/* ------------------------------------------------------------------------
 * Linux port.  kqueue(2) does not exist here; fdwatch.c implements the same
 * public API on top of epoll(7).  See the "#if defined(__linux__)" branch of
 * fdwatch.c.
 * ---------------------------------------------------------------------- */
#include <features.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>	/* SIOCOUTQ - used to emulate EVFILT_WRITE's
				   "free space in the socket send buffer" */
#include <sys/random.h>		/* getrandom() - stands in for srandomdev() */
#endif
/* ### LINUX-BLOCK-END (stdafx.h linux headers) ########################## */

#endif

/* ### LINUX-BLOCK-BEGIN (stdafx.h strlcpy) ############################## */
#if defined(__linux__)
/* ------------------------------------------------------------------------
 * strlcpy()/strlcat() are BSD extensions.  glibc only gained them in 2.38
 * (Ubuntu 24.04 / Debian 13 and newer); on anything older libthecore ships
 * the canonical OpenBSD implementation in strlcpy.c.  The prototypes below
 * are byte-compatible with both glibc's and OpenBSD's, so declaring them is
 * harmless when the C library already provides them - but we only do so when
 * it does not, to avoid clashing with glibc's __restrict qualified
 * declarations.
 *
 * Every other module (game, db, libgame, libsql, ...) includes this header
 * through its own stdafx.h, so this one place covers all 65 call sites.
 *
 * NOTE: the __WIN32__ branch above #defines strlcpy/strlcat as macros; this
 * branch is in the #else half of that same #ifdef chain, so the two can never
 * collide.
 * ---------------------------------------------------------------------- */
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2, 38)
#define THECORE_HAVE_STRLCPY 1
#endif
#endif

#ifndef THECORE_HAVE_STRLCPY
#ifdef __cplusplus
extern "C" {
#endif
extern size_t strlcpy(char * dst, const char * src, size_t siz);
extern size_t strlcat(char * dst, const char * src, size_t siz);
#ifdef __cplusplus
}
#endif
#endif
#endif
/* ### LINUX-BLOCK-END (stdafx.h strlcpy) ################################ */

/* ### LINUX-BLOCK-BEGIN (stdafx.h false/true) ########################### */
/* ---------------------------------------------------------------------------
 * "false" and "true" are keywords in C++, not macros, so "#ifndef false" is
 * always true and the two #defines below turn them into the *int* 0 and 1 for
 * every translation unit that includes this header.
 *
 * That is fatal on Linux under -std=c++23 (the standard game/src/Makefile and
 * db/src/Makefile both use).  libstdc++ 13 writes constraints such as
 *
 *     requires __is_signed_int128<_Tp> || false
 *
 * in <bits/iterator_concepts.h>, and with "false" rewritten to 0 the compiler
 * rejects them: "error: constraint '0' has type 'int', not 'bool'".  It fires
 * hundreds of times for any TU that includes <string>, <vector>, <algorithm>,
 * <map> ... after this header - which is exactly what game/src/stdafx.h does
 * (it includes this file at line 9 and the STL headers at lines 15-27), so it
 * would break essentially all of game/ and db/.
 *
 * The C++ keywords already are what these macros try to provide: FALSE/TRUE
 * below still evaluate to 0 and 1, just with type bool instead of int, and
 * both promote to the same int in every context this tree uses them
 * (comparisons, varargs, assignment to int/BYTE fields).
 *
 * The FreeBSD/Windows path keeps the original #ifndef block verbatim.
 * ------------------------------------------------------------------------- */
#if !(defined(__linux__) && defined(__cplusplus))
#ifndef false
#define false	0
#define true	(!false)
#endif
#endif
/* ### LINUX-BLOCK-END (stdafx.h false/true) ############################# */

#ifndef FALSE
#define FALSE	false
#define TRUE	(!FALSE)
#endif

#include "typedef.h"
#include "heart.h"
#include "fdwatch.h"
#include "socket.h"
#include "kstbl.h"
#include "hangul.h"
#include "buffer.h"
#include "signal.h"
#include "log.h"
#include "main.h"
#include "utils.h"
#include "crypt.h"
#include "memcpy.h"

#endif // __INC_LIBTHECORE_STDAFX_H__
