/*!\file neterr.c
 *
 *  sys_errlist[] with BSD-socket support.
 *
 *  Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. All advertising materials mentioning features or use of this software
 *     must display the following acknowledgement:
 *       This product includes software developed by Gisle Vanem
 *       Bergen, Norway.
 *
 *  THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  05.jan 1998 (GV)  - Created
 *
 *  This module tries to add network related errno/strerror/perror
 *  for all supported Watt-32 targets.
 */

#include "socket.h"

#if !defined(W32_NEW_ERRNO)

/* These should be present in respective './build/x/syserr.c' files.
 */
#if 0
  char __syserr00[]  = "No Error";
  char __syserr000[] = "No Error";
#endif

#if defined(__WATCOMC__) && (__WATCOMC__ > 1290)
  /* data-modifier; near/far depending on model */
  #define DATA_MOD    _WCDATA
#else
  #define DATA_MOD
#endif

#if defined(__TURBOC__) && (__TURBOC__ <= 0x410) /* TCC/BCC <= 3.1 */
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    sys_nerr

  #include "build/borland/syserr.c" /* @NO_DEP */

#elif defined(__BORLANDC__)
  #define SYS_ERRLIST _sys_errlist
  #define SYS_NERR    _sys_nerr

  #include "build/borland/syserr.c" /* @NO_DEP */

#elif defined(__HIGHC__)
  #define SYS_ERRLIST _sys_errlist
  #define SYS_NERR    _sys_nerr

  #include "build/highc/syserr.c"   /* @NO_DEP */

#elif defined(__POCC__)
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    EILSEQ

  #include "build/pellesc/syserr.c" /* @NO_DEP */

#elif defined(__WATCOMC__)
  #if defined(WIN32)
    #define SYS_ERRLIST _w32_sys_errlist
    #define SYS_NERR    _w32_sys_nerr
  #else
    #define SYS_ERRLIST DATA_MOD _sys_errlist
    #define SYS_NERR             _sys_nerr
  #endif

  #include "build/watcom/syserr.c"  /* @NO_DEP */

#elif defined(__DMC__)
  #if defined(WIN32)
    #define SYS_ERRLIST _w32_sys_errlist
    #define SYS_NERR    _w32_sys_nerr
  #else
    #define SYS_ERRLIST sys_errlist
    #define SYS_NERR    sys_nerr
  #endif

  char __syserr37[] = "No Error"; /* !!fixme: isn't generated by dm_err.exe */

  #include "build/digmars/syserr.c" /* @NO_DEP */

#elif defined(__clang__)
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr

  #include "build/clang/syserr.c"   /* @NO_DEP */

  #undef  SYS_ERRLIST
  #define SYS_ERRLIST sys_errlist

#elif defined(_MSC_VER) && (_MSC_VER <= 800)
  #error "Quick-C is no longer supported"

#elif defined(_MSC_VER)    /* Visual C, assuming Win32 */
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr

  #include "build/visualc/syserr.c" /* @NO_DEP */

  #undef  SYS_ERRLIST
  #define SYS_ERRLIST sys_errlist

#elif defined(__DJGPP__)
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    sys_nerr

  #include "build/djgpp/syserr.c"   /* @NO_DEP */

#elif defined(__CCDL__)
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    sys_nerr

  #include "build/ladsoft/syserr.c" /* @NO_DEP */

#elif defined(__LCC__)
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr

  #include "build/lcc/syserr.c"     /* @NO_DEP */

#elif defined(__ORANGEC__)
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    sys_nerr

  #include "build/orangec/syserr.c" /* @NO_DEP */

#elif defined(__CYGWIN__)
  #define SYS_ERRLIST _sys_errlist
  #define SYS_NERR    _sys_nerr

#elif defined(__MINGW64__) || defined(__MINGW64_VERSION_MAJOR)
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr

  #include "build/MinGW64/syserr.c" /* @NO_DEP */

#elif defined(__MINGW32__)
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr

  #include "build/MinGW32/syserr.c" /* @NO_DEP */

#else
  #error Unknown target!
#endif

/*
 * A hack for Watcom.
 */
#if defined(__WATCOMC__) && !defined(WIN32)
  #define SYS_ERRLIST2  _sys_errlist
#else
  #define SYS_ERRLIST2  SYS_ERRLIST
#endif

/*
 * A hack to make the linker use this sys_errlist[]
 * and not the normal one in the C-library.
 * Is there a better way?
 */
int pull_neterr_module = 0;

#if defined(__CYGWIN__)
  /* Nothing to do here */

#elif defined(__POCC__)
  int _w32_sys_nerr = 120; /* pocc bug */

#elif defined(WIN32) && !defined(__LCC__) && !defined(__BORLANDC__)
  #if defined(_MSC_VER) || defined(__WATCOMC__)
    int _w32_sys_nerr     = DIM(_w32_sys_errlist);
  #else
    int DATA_MOD SYS_NERR = DIM(SYS_ERRLIST2);
  #endif

  int *_sys_nerr_dll   = &_w32_sys_nerr;
  int *_imp___sys_nerr = &_w32_sys_nerr;
#endif

#if !defined(_MSC_VER) && defined(__MSDOS__)
void MS_CDECL perror (const char *str)
{
  if (str && *str)
     fprintf (stderr, "%s: ", str);

#if defined(__GNUC__) /* Posix (?) dictates a newline */
  fprintf (stderr, "%s\n", strerror(errno));
#else
  fprintf (stderr, "%s", strerror(errno));
#endif
}

/**
 * For Win32/Win64, this doesn't replace the `strerror()` in the Runtime Library,
 * but replacing `sys_nerr` (i.e. `*_sys_nerr_dll`) should give the same effect (?).
 */
char * MS_CDECL strerror (int errnum)
{
  static char buf[70];

  if (errnum >= 0 && errnum < SYS_NERR)
       _strlcpy (buf, SYS_ERRLIST2[errnum], sizeof(buf));
  else sprintf (buf, "Unknown error: %d", errnum);

#if !defined(__GNUC__)
 /*
  * Posix doesn't specify a newline at the end.
  */
  strcat (buf, "\n");
#endif

  return (buf);
}
#endif  /* !_MSC_VER && __MSDOS__ */

/*
 * For non-Win32 errno == _w32_errno for all network calls
 */
#if defined(WIN32)
/*
 * Winsock compatibility.
 */
int __stdcall WSAGetLastError (void)
{
  int err = _w32_errno;
  _w32_errno = 0;
  return (err);
}

void __stdcall WSASetLastError (int err)
{
#if defined(__POCC__)
  #if defined(_DLL) || defined(_MT)
    *__errno() = err;
  #else
    errno = err;
  #endif

#elif defined(_MSC_VER) || defined(__DMC__)
  #if defined(_DLL) || defined(_MT)
    *_errno() = err;
  #else
    errno = err;
  #endif

#elif defined(__ORANGEC__)
  #if defined(_DLL) || defined(_MT)
    *__errno() = err;
  #else
    errno = err;
  #endif

#elif defined(__MINGW32__) || defined(__MINGW64__)
  *_errno() = err;

#elif defined(__CYGWIN__)
  *__errno() = err;

#elif defined(__BORLANDC__)
  int * _RTLENTRY _EXPFUNC __errno (void);
  *__errno() = err;

#elif defined(__LCC__)
  #undef errno
  *errno() = err;

#elif defined(__WATCOMC__)
  *__get_errno_ptr() = err;
  errno = err;

#else
  #error Help me!
#endif

  _w32_errno = err;
}
#endif  /* WIN32 */
#endif  /* W32_NEW_ERRNO */


#if defined(USE_DEBUG)
/*
 * Return only the Exx part of strerror()
 */
const char *short_strerror (int errnum)
{
  static char buf[256];
  char  *l_par, *r_par;

  _strlcpy (buf, strerror(errnum), sizeof(buf));
  l_par = strchr (buf, '(');
  if (!l_par)
  {
    sprintf (buf, "errno %d", errnum);
    return (buf);
  }

  r_par = strchr (l_par, ')');
  if (r_par)
     *r_par = '\0';
  return (l_par+1);
}
#endif

/*
 * Incase you have trouble with multiple defined symbols,
 * make sure the following functions are used before
 * perror/strerror/sys_errlist in your C-library.
 */
void W32_CALL perror_s (const char *str)
{
#if defined(__LCC__)
  perror ((char*)str);
#else
  perror (str);
#endif
}

char * W32_CALL strerror_s_ (int errnum)
{
  return strerror (errnum);
}

