/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
*     National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
*     Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution. 
\*************************************************************************/
/* $Id$ */
/*
 *  To get strtoul and strerror a sunos system must have
 *  /usr/lang/SC2.0.1patch installed. See CONFIG_SITE.Unix.sun4.
 *  Andrew Johnson has created this file named sun4ansi.c containg code
 *  for strtoul and strerror which is available in the base/libCom
 *  directory so that any site that needs it can add it to the Makefile.Unix.
 */


#ifdef SUNOS4

/*
 * Routines which are needed but SunOS 4.x doesn't provide.
 * These definitions obtained from GNU libiberty directory.
 * Note that Sun's Ansi C compiler provides these routines,
 * so there ought to be a way of excluding this file if you
 * have that...
 *
 */

/*
 * strtol : convert a string to long.
 *
 * Andy Wilson, 2-Oct-89.
 */

#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <limits.h>

extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];


unsigned long
strtoul(const char *s, char **ptr, int base)
{
  unsigned long total = 0, tmp = 0;
  unsigned digit;
  const char *start=s;
  int did_conversion=0;
  int negate = 0;

  if (s==NULL)
    {
      errno = ERANGE;
      if (!ptr)
	*ptr = (char *)start;
      return 0L;
    }

  while (isspace(*s))
    s++;
  if (*s == '+')
    s++;
  else if (*s == '-')
    s++, negate = 1;
  if (base==0 || base==16) /*  the 'base==16' is for handling 0x */
    {
      /*
       * try to infer base from the string
       */
      if (*s != '0')
        tmp = 10;	/* doesn't start with 0 - assume decimal */
      else if (s[1] == 'X' || s[1] == 'x')
	tmp = 16, s += 2; /* starts with 0x or 0X - hence hex */
      else
	tmp = 8;	/* starts with 0 - hence octal */
      if (base==0)
	base = (int)tmp;
    }

  while ( digit = *s )
    {
      if (digit >= '0' && digit < ('0'+base))
	digit -= '0';
      else
	if (base > 10)
	  {
	    if (digit >= 'a' && digit < ('a'+(base-10)))
	      digit = digit - 'a' + 10;
	    else if (digit >= 'A' && digit < ('A'+(base-10)))
	      digit = digit - 'A' + 10;
	    else
	      break;
	  }
	else
	  break;
      did_conversion = 1;
      tmp = (total * base) + digit;
      if (tmp < total)	/* check overflow */
	{
	  errno = ERANGE;
	  if (ptr != NULL)
	    *ptr = (char *)s;
	  return (ULONG_MAX);
	}
      total = tmp;
      s++;
    }
  if (ptr != NULL)
    *ptr = (char *) ((did_conversion) ? (char *)s : (char *)start);
  return negate ? -total : total;
}

/*
 * strerror
 *
 * convert an error number into a string
 */

char *
strerror (errnoval)
  int errnoval;
{
  char *msg;
  static char buf[32];

  if ((errnoval < 0) || (errnoval >= sys_nerr))
    {
      /* Out of range, just return NULL */
      msg = NULL;
    }
  else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
    {
      /* In range, but no sys_errlist or no entry at this index. */
      sprintf (buf, "Error %d", errnoval);
      msg = buf;
    }
  else
    {
      /* In range, and a valid message.  Just return the message. */
      msg = sys_errlist[errnoval];
    }
  
  return (msg);
}

#endif
