/*!\file neterr.c
 *
 *  sys_errlist[] with BSD-socket support.
 *
 *  Copyright (c) 1997-2002 Gisle Vanem <giva@bgnett.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"

char __syserr00[] = "No Error";

#if defined(__WATCOMC__)   /* data-modifier; near/far depending on model */
  #define DATA_MOD _WCNEAR
#elif defined(_MSC_VER) && (_MSC_VER <= 800)
  #define DATA_MOD _near   /* even for large model */
#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 "borland/syserr.c" /* @NO_DEP */

#elif defined(__BORLANDC__)
  #define SYS_ERRLIST _sys_errlist
  #define SYS_NERR    _sys_nerr
  #include "borland/syserr.c" /* @NO_DEP */

#elif defined(__HIGHC__)
  #define SYS_ERRLIST _sys_errlist
  #define SYS_NERR    _sys_nerr
  #include "highc/syserr.c"   /* @NO_DEP */

#elif defined(__POCC__)
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    EILSEQ
  #include "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 _sys_errlist
    #define SYS_NERR    _sys_nerr
  #endif

  #include "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 "digmars/syserr.c" /* @NO_DEP */

#elif defined(_MSC_VER) && (_MSC_VER <= 800)
  #define SYS_ERRLIST DATA_MOD sys_errlist
  #define SYS_NERR             sys_nerr
  #include "quickc/syserr.c"  /* @NO_DEP */

  #undef  SYS_ERRLIST
  #define SYS_ERRLIST sys_errlist

#elif defined(_MSC_VER) && (_MSC_VER > 800)    /* Visual C, assuming Win32 */
  #define SYS_ERRLIST DATA_MOD _w32_sys_errlist
  #define SYS_NERR             _w32_sys_nerr
  #include "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 "djgpp/syserr.c"   /* @NO_DEP */

#elif defined(__CCDL__)
  #define SYS_ERRLIST sys_errlist
  #define SYS_NERR    sys_nerr
  #include "ladsoft/syserr.c" /* @NO_DEP */

#elif defined(__LCC__)
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr
  #include "lcc/syserr.c"     /* @NO_DEP */

#elif defined(__MINGW32__)
  #define SYS_ERRLIST _w32_sys_errlist
  #define SYS_NERR    _w32_sys_nerr
  #include "mingw32/syserr.c" /* @NO_DEP */

#else
  #error Unknown target!
#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(__POCC__)
  int _w32_sys_nerr = 120; /* pocc bug */

#elif defined(WIN32) && !defined(__LCC__) && !defined(__BORLANDC__)
  int _w32_sys_nerr    = DIM(_w32_sys_errlist);
  int *_sys_nerr_dll   = &_w32_sys_nerr;
  int *_imp___sys_nerr = &_w32_sys_nerr;
#else
  int DATA_MOD SYS_NERR = DIM(SYS_ERRLIST);
#endif

#if !defined(_MSC_VER) && !defined(WIN32)
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, this doesn't replace the strerror() in the RTL,
 * but replacing sys_nerr (*_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_ERRLIST[errnum], sizeof(buf));
  else sprintf (buf, "Unknown error: %d", errnum);

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

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

/*
 * 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(__MINGW32__)
  *_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;

#else
  #error Help me!
#endif

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


#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)
  {
    strcpy (buf, "errno ");
    return itoa (errnum, buf+6, 10);
  }

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


#if defined(__GNUC__) && 0
  #define ALIAS(func) __attribute__((weak, alias(func)))

  char *strerror_s (int err) ALIAS(strerror);
#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 perror_s (const char *str)
{
#if defined(__LCC__)
  perror ((char*)str);
#else
  perror (str);
#endif
}

char *strerror_s (int errnum)
{
  return strerror (errnum);
}

