/******************************************************************************/
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de>                                */
/* This work has been released under the CC0 1.0 Universal license!           */
/******************************************************************************/

#ifndef INC_PLATFORM_H
#define INC_PLATFORM_H

/* Platform configuration */
#ifndef _WIN32
#  define _FILE_OFFSET_BITS 64
#endif

/* MINGW32 support */
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
#  define __MSVCRT_VERSION__ 0x700
#endif

/* Disable MSVC warnings */
#ifdef _MSC_VER
#  define _CRT_SECURE_NO_WARNINGS 1
#endif

/* Standatd library includes*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

/* Required for _wfsopen() support */
#ifdef _WIN32
#  include <share.h>
#  ifndef _SH_SECURE
#  define _SH_SECURE 0x80
#  endif
#endif

/* Detect operating system type */
#if defined(__MINGW32__)
#  define OS_TYPE_NAME "MinGW"
#elif defined(__CYGWIN__)
#  define OS_TYPE_NAME "Cygwin"
#elif defined(_WIN32)
#  define OS_TYPE_NAME "Windows"
#elif defined(__linux__)
#  define OS_TYPE_NAME "Linux"
#elif defined(__gnu_hurd__)
#  define OS_TYPE_NAME "GNU/Hurd"
#elif defined(__FreeBSD__)
#  define OS_TYPE_NAME "FreeBSD"
#elif defined(__DragonFly__)
#  define OS_TYPE_NAME "DragonFly"
#elif defined(__NetBSD__)
#  define OS_TYPE_NAME "NetBSD"
#elif defined(__OpenBSD__)
#  define OS_TYPE_NAME "OpenBSD"
#elif defined(__sun) && defined(__SVR4)
#  define OS_TYPE_NAME "Solaris"
#elif defined(__QNX__)
#  define OS_TYPE_NAME "QNX"
#elif defined(__HAIKU__)
#  define OS_TYPE_NAME "Haiku"
#elif defined(__APPLE__) && defined(__MACH__)
#  define OS_TYPE_NAME "macOS"
#elif defined(__unix__)
#  define OS_TYPE_NAME "Unix"
#else
#  error Unknown operating system!
#endif

/* Detect CPU architecture */
#if defined(__x86_64__) || defined(_M_X64)
#  define CPU_ARCH "x64"
#elif defined(__i386__) || defined(_M_IX86)
#  define CPU_ARCH "x86"
#elif defined(__aarch64__) || defined(_M_ARM64)
#  define CPU_ARCH "arm64"
#elif defined(__arm__) && defined(__ARM_FP)
#  define CPU_ARCH "armhf"
#elif defined(__arm__) && defined(__ARMEL__)
#  define CPU_ARCH "armel"
#elif defined(__arm__) || defined(_M_ARM)
#  define CPU_ARCH "arm"
#elif defined(__mips__) && defined(__mips64) && defined(_MIPSEL)
#  define CPU_ARCH "mips64el"
#elif defined(__mips__) && defined(__mips64)
#  define CPU_ARCH "mips64"
#elif (defined(__mips__) || defined(__mips)) && defined(_MIPSEL)
#  define CPU_ARCH "mipsel"
#elif defined(__mips__) || defined(__mips)
#  define CPU_ARCH "mips"
#else
#  error Unknown CPU architecture!
#endif

/* Platform-specific quirks */
#ifdef _WIN32
#  define MAIN wmain
#  define CHR wchar_t
#  define _T(X) L##X
#  define GETENV(X) _wgetenv((X))
#  define STRLEN(X) wcslen((X))
#  define STRICMP(X,Y) _wcsicmp((X),(Y))
#  define STRNICMP(X,Y,Z) _wcsnicmp((X),(Y),(Z))
#  define STRRCHR(X,Y) wcsrchr((X),(Y))
#  define STRTOUL(X) wcstoul((X), NULL, 0)
#  define STRDUP(X) _wcsdup((X))
#  define strdup(X) _strdup((X))
#  define FPUTS(X,Y) fputws((X),(Y))
#  define FPRINTF(X,Y,...) fwprintf((X),(Y),__VA_ARGS__)
#  define REMOVE(X) _wremove((X))
#  define FOPEN(X,Y) _wfsopen((X),_T(Y) L"S",_SH_SECURE)
#  define STRERROR(X) _wcserror((X))
#  ifndef __USE_MINGW_ANSI_STDIO
#  define __USE_MINGW_ANSI_STDIO 0
#  endif
#  if __USE_MINGW_ANSI_STDIO
#    define PRISTR "ls"
#    define PRIstr "hs"
#    define PRIwcs "ls"
#  else
#    define PRISTR "s"
#    define PRIstr "S"
#    define PRIwcs "s"
#  endif
#else
#  define MAIN main
#  define CHR char
#  define _T(X) X
#  define GETENV(X) getenv((X))
#  define STRLEN(X) strlen((X))
#  define STRICMP(X,Y) strcasecmp((X),(Y))
#  define STRNICMP(X,Y,Z) strncasecmp((X),(Y),(Z))
#  define STRRCHR(X,Y) strrchr((X),(Y))
#  define STRTOUL(X) strtoul((X), NULL, 0)
#  define STRDUP(X) strdup((X))
#  define FPUTS(X,Y) fputs((X),(Y))
#  define FPRINTF(X,Y,...) fprintf((X),(Y),__VA_ARGS__)
#  define REMOVE(X) remove((X))
#  define FOPEN(X,Y) fopen((X),(Y))
#  define STRERROR(X) strerror((X))
#  define PRISTR "s"
#  define PRIstr "s"
#  define PRIwcs "ls"
#endif

#define T(X) _T(X)

#endif
