/* -*- c -*- ------------------------------------------------------------- *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 *   Copyright 2001-2025 H. Peter Anvin - All Rights Reserved
 *
 * ----------------------------------------------------------------------- */

/*
 * config.h
 *
 * Sets up a common baseline environment, based on "autoconf" findings...
 */

#ifndef CONFIG_H
#define CONFIG_H 1

/* Feature enables for specific environments */
#ifdef __APPLE__
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1070
#define __APPLE_USE_RFC_3542 1
#endif
#endif

/* Must be included before we include any system headers! */
#include "config/config.h"            /* autogenerated configuration header */

/* Standard includes */

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <limits.h>
#include <stdarg.h>

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif

#ifdef HAVE_INTTYPES_H
#ifdef INTTYPES_H_IS_SANE
#include <inttypes.h>
#endif
#else
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_SETJMP_H
#include <setjmp.h>
#endif

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif

#ifdef HAVE_GRP_H
#include <grp.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#if !defined(HAVE_POLL) && !defined(HAVE_PPOLL)
#undef HAVE_POLL_H
#endif

#ifdef HAVE_POLL_H
#include <poll.h>
#elif defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#else
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#else
#ifdef HAVE_WINSOCK_H
#include <winsock.h>
#endif
#endif
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif

#ifdef HAVE_WCHAR_H
#include <wchar.h>
#endif
#ifdef HAVE_WCTYPE_H
#include <wctype.h>
#endif

#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif

#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#else
#include "lib/getopt.h"
#endif

#ifdef HAVE_PATHS_H
#include <paths.h>
#endif

#ifndef _PATH_DEVNULL
#if defined(_WIN32) && !defined(__CYGWIN__)
#define _PATH_DEVNULL "\\\\.\\NUL"
#else
#define _PATH_DEVNULL "/dev/null"
#endif
#endif

#ifdef HAVE_STDNORETURN_H
#include <stdnoreturn.h>
#elif defined(noreturn)
/* Already defined */
#elif defined(__GNUC__)
#define noreturn __attribute__((__noreturn__))
#else
#define noreturn
#endif

/* Test for EAGAIN/EWOULDBLOCK */
#ifdef EAGAIN
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
#define E_WOULD_BLOCK(x) ((x) == EAGAIN || (x) == EWOULDBLOCK)
#else
#define E_WOULD_BLOCK(x) ((x) == EAGAIN)
#endif
#else
#define E_WOULD_BLOCK(x) ((x) == EWOULDBLOCK)
#endif

/* Some broken systems care about text versus binary, but
   real Unix systems don't... */
#if !HAVE_DECL_O_TEXT
#define O_TEXT		0
#endif
#if !HAVE_DECL_O_BINARY
#define O_BINARY	0
#endif

#ifndef HAVE_DECL_O_NONBLOCK
# ifdef HAVE_DECL_O_NDELAY
#  define O_NONBLOCK	O_NDELAY
# else
#  define O_NONBLOCK	0
# endif
#endif

/* If we don't have intmax_t, try creating it */

#ifndef HAVE_INTMAX_T
#ifdef HAVE_LONG_LONG
typedef long long intmax_t;
typedef unsigned long long uintmax_t;
#define PRIdMAX	"lld"
#define PRIuMAX "llu"
#define PRIxMAX "llx"
#define INTMAX_C(x)  (x##LL)
#define UINTMAX_C(x) (x##ULL)
#else
typedef long intmax_t;
typedef unsigned long uintmax_t;
#define PRIdMAX "ld"
#define PRIuMAX "lu"
#define PRIxMAX "lx"
#define INTMAX_C(x)  (x##L)
#define UINTMAX_C(x) (x##UL)
#endif
#endif

/* On some version of AIX, <inttypes.h> is buggy to the point of
   unusability.  We have to use macros here, not typedefs, to override. */
#ifdef HAVE_INTTYPES_H
#ifndef INTTYPES_H_IS_SANE
#undef PRIdMAX
#undef PRIuMAX
#undef PRIxMAX
#undef INTMAX_C
#undef UINTMAX_C
#undef HAVE_STRTOUMAX

#ifdef HAVE_LONG_LONG
#define intmax_t long long
#define uintmax_t unsigned long long
#define PRIdMAX	"Ld"
#define PRIuMAX "Lu"
#define PRIxMAX "Lx"
#define INTMAX_C(x)  (x##LL)
#define UINTMAX_C(x) (x##ULL)
#else
#define intmax_t long
#define uintmax_t unsigned long
#define PRIdMAX	"ld"
#define PRIuMAX "lu"
#define PRIxMAX "lx"
#define INTMAX_C(x)  (x##L)
#define UINTMAX_C(x) (x##UL)
#endif
#endif
#endif

/* Even if intmax_t is defined, we may need this (Solaris 8 braindamage) */
#ifndef HAVE_STRTOUMAX
#if defined(HAVE_LONG_LONG) && defined(HAVE_STRTOULL)
#define strtoumax(p,e,b) ((uintmax_t)strtoull(p,e,b))
#else
#define strtoumax(p,e,b) ((uintmax_t)strtoul(p,e,b))
#endif
#endif

/* A lot of this is old BSD code.  Some newer systems don't approve. */

/* The type used by htons(), ntohs() */
#ifndef HAVE_U_SHORT
#ifdef HAVE_UINT16_T
typedef uint16_t u_short;
#else
typedef unsigned short u_short;
#endif
#endif

/* The type used to htonl(), ntohl() */
#ifndef HAVE_U_LONG
#ifdef HAVE_UINT32_T
typedef uint32_t u_long;
#else
typedef unsigned long u_long;
#endif
#endif

/* socklen_t */
#ifndef HAVE_SOCKLEN_T
typedef int socklen_t;
#endif

/* sysexits.h */

#ifdef HAVE_SYSEXITS_H
#include <sysexits.h>
#else
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */
#define EX_NOUSER       67      /* addressee unknown */
#define EX_NOHOST       68      /* host name unknown */
#define EX_UNAVAILABLE  69      /* service unavailable */
#define EX_SOFTWARE     70      /* internal software error */
#define EX_OSERR        71      /* system error (e.g., can't fork) */
#define EX_OSFILE       72      /* critical OS file missing */
#define EX_CANTCREAT    73      /* can't create (user) output file */
#define EX_IOERR        74      /* input/output error */
#define EX_TEMPFAIL     75      /* temp failure; user is invited to retry */
#define EX_PROTOCOL     76      /* remote error in protocol */
#define EX_NOPERM       77      /* permission denied */
#define EX_CONFIG       78      /* configuration error */
#endif

/* If we don't have sigsetjmp() et all, setjmp() will have to do */

#ifndef HAVE_SIGSETJMP
#define sigsetjmp(x,y)  setjmp(x)
#define siglongjmp(x,y) longjmp(x,y)
#define sigjmp_buf jmp_buf
#endif

/* How do we annotate unused data items? */

#ifndef UNUSED
#ifdef __GNUC__
#define UNUSED __attribute__((unused))
#else
#define UNUSED
#endif
#endif

/* netinet/in.h, and possible missing pieces */

#include <netinet/in.h>

#if !HAVE_DECL_IPPORT_TFTP && !defined(IPPORT_TFTP)
#define IPPORT_TFTP 69
#endif

/* arpa/{inet,tftp}.h, and possible missing pieces */

#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
/* If we don't have arpa/tftp.h we have problems... */
#include <arpa/tftp.h>

#ifndef OACK
#define OACK 6
#endif
#ifndef EOPTNEG
#define EOPTNEG 8
#endif

/* Prototypes for libxtra functions */

#ifndef HAVE_SIGHANDLER_T
typedef void (*sighandler_t)(int);
#endif
int tftp_signal(int, sighandler_t, int);

#ifndef HAVE_DUP2
int dup2(int, int);
#endif
#ifndef HAVE_DAEMON
int daemon(int, int);
#endif

#ifndef HAVE_GETADDRINFO
#ifndef HAVE_STRUCT_ADDRINFO_AI_ADDR
struct addrinfo {
    int     ai_flags;
    int     ai_family;
    int     ai_socktype;
    int     ai_protocol;
    size_t  ai_addrlen;
    struct sockaddr *ai_addr;
    char    *ai_canonname;
    struct addrinfo *ai_next;
};
#endif
int getaddrinfo(const char *, const char *, const struct addrinfo *,
                struct addrinfo **);
void freeaddrinfo(struct addrinfo *);
const char *gai_strerror(int);


#ifndef EAI_NONAME
#define EAI_NONAME      -2    /* NAME or SERVICE is unknown.  */
#endif
#ifndef EAI_ADDRFAMILY
#define EAI_ADDRFAMILY -9    /* Address family for NAME not supported.  */
#endif
#ifndef EAI_MEMORY
#define EAI_MEMORY      -10   /* Memory allocation failure.  */
#endif
#ifndef EAI_SYSTEM
#define EAI_SYSTEM      -11   /* System error returned in `errno'.  */
#endif
#endif

#ifndef AI_CANONNAME
#define AI_CANONNAME    0
#endif

#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG   0
#endif

#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN 46
#endif

#ifndef HAVE_INET_NTOP
const char *inet_ntop(int, const void *, char *, socklen_t);
#endif

/* HAVE_IPV6 as a boolean */
#ifdef HAVE_IPV6
# define WITH_IPV6 1
#else
# define WITH_IPV6 0
#endif

/* tftp-hpa version and configuration strings */

#include "version.h"

#ifdef WITH_READLINE
#define WITH_READLINE_STR ", with readline"
#else
#define WITH_READLINE_STR ", without readline"
#endif

#ifdef WITH_REGEX
#define WITH_REGEX_STR ", with remap"
#else
#define WITH_REGEX_STR ", without remap"
#endif

#ifdef HAVE_PTHREADS
#define WITH_THREADS_STR ", with I/O threads"
#else
#define WITH_THREADS_STR ", without I/O threads"
#endif

#define TFTP_CONFIG_STR VERSION WITH_READLINE_STR
#define TFTPD_CONFIG_STR VERSION WITH_REGEX_STR WITH_THREADS_STR

#endif
