14485037des/*	$OpenBSD: strtoul.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
27d1750fdes/*
37d1750fdes * Copyright (c) 1990 Regents of the University of California.
47d1750fdes * All rights reserved.
57d1750fdes *
67d1750fdes * Redistribution and use in source and binary forms, with or without
77d1750fdes * modification, are permitted provided that the following conditions
87d1750fdes * are met:
97d1750fdes * 1. Redistributions of source code must retain the above copyright
107d1750fdes *    notice, this list of conditions and the following disclaimer.
117d1750fdes * 2. Redistributions in binary form must reproduce the above copyright
127d1750fdes *    notice, this list of conditions and the following disclaimer in the
137d1750fdes *    documentation and/or other materials provided with the distribution.
147d1750fdes * 3. Neither the name of the University nor the names of its contributors
157d1750fdes *    may be used to endorse or promote products derived from this software
167d1750fdes *    without specific prior written permission.
177d1750fdes *
187d1750fdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
197d1750fdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
207d1750fdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
217d1750fdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
227d1750fdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237d1750fdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247d1750fdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257d1750fdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
267d1750fdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
277d1750fdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
287d1750fdes * SUCH DAMAGE.
297d1750fdes */
307d1750fdes
314485037des/* OPENBSD ORIGINAL: lib/libc/stdlib/strtoul.c */
324485037des
337d1750fdes#include "includes.h"
347d1750fdes#ifndef HAVE_STRTOUL
357d1750fdes
367d1750fdes#include <ctype.h>
377d1750fdes#include <errno.h>
387d1750fdes#include <limits.h>
397d1750fdes#include <stdlib.h>
407d1750fdes
417d1750fdes/*
427d1750fdes * Convert a string to an unsigned long integer.
437d1750fdes *
447d1750fdes * Ignores `locale' stuff.  Assumes that the upper and lower case
457d1750fdes * alphabets and digits are each contiguous.
467d1750fdes */
477d1750fdesunsigned long
484485037desstrtoul(const char *nptr, char **endptr, int base)
497d1750fdes{
504485037des	const char *s;
514485037des	unsigned long acc, cutoff;
524485037des	int c;
534485037des	int neg, any, cutlim;
547d1750fdes
557d1750fdes	/*
567d1750fdes	 * See strtol for comments as to the logic used.
577d1750fdes	 */
587d1750fdes	s = nptr;
597d1750fdes	do {
607d1750fdes		c = (unsigned char) *s++;
617d1750fdes	} while (isspace(c));
627d1750fdes	if (c == '-') {
637d1750fdes		neg = 1;
647d1750fdes		c = *s++;
657d1750fdes	} else {
667d1750fdes		neg = 0;
677d1750fdes		if (c == '+')
687d1750fdes			c = *s++;
697d1750fdes	}
707d1750fdes	if ((base == 0 || base == 16) &&
717d1750fdes	    c == '0' && (*s == 'x' || *s == 'X')) {
727d1750fdes		c = s[1];
737d1750fdes		s += 2;
747d1750fdes		base = 16;
757d1750fdes	}
767d1750fdes	if (base == 0)
777d1750fdes		base = c == '0' ? 8 : 10;
787d1750fdes
797d1750fdes	cutoff = ULONG_MAX / (unsigned long)base;
807d1750fdes	cutlim = ULONG_MAX % (unsigned long)base;
817d1750fdes	for (acc = 0, any = 0;; c = (unsigned char) *s++) {
827d1750fdes		if (isdigit(c))
837d1750fdes			c -= '0';
847d1750fdes		else if (isalpha(c))
857d1750fdes			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
867d1750fdes		else
877d1750fdes			break;
887d1750fdes		if (c >= base)
897d1750fdes			break;
907d1750fdes		if (any < 0)
917d1750fdes			continue;
927d1750fdes		if (acc > cutoff || acc == cutoff && c > cutlim) {
937d1750fdes			any = -1;
947d1750fdes			acc = ULONG_MAX;
957d1750fdes			errno = ERANGE;
967d1750fdes		} else {
977d1750fdes			any = 1;
987d1750fdes			acc *= (unsigned long)base;
997d1750fdes			acc += c;
1007d1750fdes		}
1017d1750fdes	}
1027d1750fdes	if (neg && any > 0)
1037d1750fdes		acc = -acc;
1047d1750fdes	if (endptr != 0)
1057d1750fdes		*endptr = (char *) (any ? s - 1 : nptr);
1067d1750fdes	return (acc);
1077d1750fdes}
1087d1750fdes#endif /* !HAVE_STRTOUL */
109