
/*
 *  %W%	(Jukka Ukkonen)	%E%
 *
 * Copyright (c) 1992-%E% Jukka A. Ukkonen
 * All rights reserved.
 *
 * This software is not subject to any license of the following
 *  - American Telephone and Telegraph Company (AT&T),
 *  - UNIX System Laboratories (the owner of UNIX & SysV),
 *  - the Regents of the University of California (the owner of BSD) or
 *  - the Free Software Foundation (the owner of GNU).
 *
 * 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 at Centre for Scientific
 *      Computing by Jukka Ukkonen.
 *
 * 4. None of the names Jukka Antero Ukkonen or Centre for Scientific
 *    Computing may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * 5. The origin of this software must not be misrepresented, either by
 *    explicit claim or by omission.  Since few users ever read sources,
 *    credits must appear in the documentation.
 *
 * 6. Altered versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.  Since few users
 *    ever read sources, credits must appear in the documentation.
 *
 * 7. This notice may not be removed or altered.
 *
 * 8. This software is provided by Jukka Antero Ukkonen ``AS IS'' and
 *    any express or implied warranties, including, but NOT LIMITED TO,
 *    the implied warranties of merchantability and fitness for any
 *    particular purpose are DISCLAIMED.
 *
 * 9. IN NO EVENT shall Jukka Antero Ukkonen 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.
 */

#ifndef	__STDC__
# define const	/**/
#endif

#ifndef	lint
static const char sccsid[] = "%W%\t(Jukka Ukkonen)\t%E%";
#endif


#include <stdlib.h>
#include <string.h>
#if defined(sun)
#  include <memory.h>
#endif
#include <limits.h>
#include <ctype.h>
#include <errno.h>

#ifndef ULONG_MAX
# define ULONG_MAX  (~ (unsigned long) 0x0)
#endif

static const char   digits[] =
    "0123456789abcdefghijklmnopqrstuvwxyz";

unsigned long
strtoul (start, end, base)
    register const char     *start;
    char                    **end;
    register int	    base;
{
    register const char         *ptr,
                                *initial,
				*digit;
    register unsigned long      value,
                                prev;
    register unsigned		negat,
				ch;

    if (base && (base < 2) || (base > (sizeof (digits) - 1))) {
        if (end)
            *end = (char *) start;

        errno = EINVAL;

        return (0);
    }

    errno = 0;                  /* To make sure there is no errno when OK. */

    for (ptr = start; isspace (*ptr); ptr++) ;

    if (*ptr == '-') {
        negat = 1;
        ptr++;
    }
    else {
        negat = 0;

	if (*ptr == '+')
	    ptr++;
    }

    initial = ptr;

    if (*ptr == '0') {
	/*
	 *  Skip the '0'
	 */
	if (((*++ptr == 'x') || (*ptr == 'X')) && (! base || (base == 16))) {
	    base = 16;
	    initial = ++ptr;	    /* Now skip the 'x' */
	}
	else if (! base)
	    base = 8;
    }

    if (! base)
	base = 10;

    while (*ptr == '0')
        ptr++;              /* Try get easy. Strip off any leading zeros! */

    prev = 0;

    for (value = 0; (ch = (isupper (*ptr) ? tolower (*ptr) : *ptr)) &&
                    ((digit = memchr (digits, ch, base)) >= digits); ptr++) {

        value *= base;
        value += digit - digits;

        if (value < prev) {         /* Oops! An overflow has happened. */
            value = ULONG_MAX;
            errno = ERANGE;
            break;
        }

        prev = value;
    }

    if (ptr == initial) {
        if (end)
            *end = (char *) start;

        errno = EINVAL;

        return (0);
    }

    if (negat)
        value = -value;

    if (end)
        *end = (char *) ptr;

    return (value);
}

#ifdef	DEBUG_STRTOUL

#include <stdio.h>

main ()
{
    char    buff[64];
    char    *ptr;
    unsigned	val;

    strcpy (buff, "10000000");
    val = strtoul (buff, &ptr, 2);
    printf (":: %lu/0x%8.8x", val, val);
    printf (" (%u)\n", ptr - buff);
    fflush (stdout);

    strcpy (buff, "-10000000");
    val = strtoul (buff, &ptr, 2);
    printf (":: %lu/0x%8.8x", val, val);
    printf (" (%u)\n", ptr - buff);
    fflush (stdout);

    while (fgets (buff, sizeof (buff), stdin)) {
	val = strtoul (buff, &ptr, 0);
	printf (":: %lu/0x%8.8x", val, val);
	printf (" (%u)\n", ptr - buff);
	fflush (stdout);
    }

    exit (0);
}

#endif

