[comp.unix.questions] strtol

pete@eleazar.dartmouth.edu (Peter Robert Schmitt) (06/16/89)

I am looking for any info on the function strtol().  I can't seem to
find it in the man pages on my BSD4.3.  Any help appreciated.

-pete schmitt
Peter R. Schmitt - UNIX User Services Consultant - Peter.Schmitt@dartmouth.edu
	There are two fundamental facts of human enlightenment:
			#1, There is a God.
			#2, You are not Him!

chris@mimsy.UUCP (Chris Torek) (06/20/89)

In article <13949@dartvax.Dartmouth.EDU> pete@eleazar.dartmouth.edu
(Peter Robert Schmitt) writes:
>I am looking for any info on the function strtol().  I can't seem to
>find it in the man pages on my BSD4.3.  Any help appreciated.

You will find neither information nor source---4BSD does (or rather,
`did') not have strtol(), nor strtoul().

Here they are.  These have been tested, although I cannot recall
how strenuously.  (As you can see by the copyright date, I wrote them
last year.  Why Copyright Regents of UC, rather than UM?  Their
license agreement already exists.)

You will have to replace the `#include <limits.h>' line, e.g., with

	#define	LONG_MIN	(-2147483647L - 1)
	 /* cannot use `-2147483648' as the type of the result is unsigned */
	#define	LONG_MAX	2147483647L
	#define	ULONG_MAX	((unsigned long)4294967295)
	 /* old BSD compiler does not have UL suffix */

although I am no longer sure as to whether the types here are correct
(I seem to recall something about `removing suffixes from limits.h
definitions').  In any case, strto*.c below do not depend on the types
in limits.h, just the values.

: Run this shell script with "sh" not "csh"
PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
export PATH
all=false
if [ x$1 = x-a ]; then
	all=true
fi
echo Extracting strtol.c
sed 's/^X//' <<'//go.sysin dd *' >strtol.c
X/*
X * Copyright (c) 1988 Regents of the University of California.
X * All rights reserved.  The Berkeley software License Agreement
X * specifies the terms and conditions for redistribution.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "%W% (Berkeley) %G%";
X#endif /* LIBC_SCCS and not lint */
X
X#include <limits.h>
X#include <ctype.h>
X#include <errno.h>
X
Xint	errno;
X
X/*
X * Convert a string to a long integer.
X *
X * Ignores `locale' stuff.  Assumes that the upper and lower case
X * alphabets and digits are each contiguous.
X */
Xlong
Xstrtol(nptr, endptr, base)
X	char *nptr, **endptr;
X	register int base;
X{
X	register char *s = nptr;
X	register unsigned long acc;
X	register int c;
X	register unsigned long cutoff;
X	register int neg = 0, any, cutlim;
X
X	/*
X	 * Skip white space and pick up leading +/- sign if any.
X	 * If base is 0, allow 0x for hex and 0 for octal, else
X	 * assume decimal; if base is already 16, allow 0x.
X	 */
X	do {
X		c = *s++;
X	} while (isspace(c));
X	if (c == '-') {
X		neg = 1;
X		c = *s++;
X	} else if (c == '+')
X		c = *s++;
X	if ((base == 0 || base == 16) &&
X	    c == '0' && (*s == 'x' || *s == 'X')) {
X		c = s[1];
X		s += 2;
X		base = 16;
X	}
X	if (base == 0)
X		base = c == '0' ? 8 : 10;
X
X	/*
X	 * Compute the cutoff value between legal numbers and illegal
X	 * numbers.  That is the largest legal value, divided by the
X	 * base.  An input number that is greater than this value, if
X	 * followed by a legal input character, is too big.  One that
X	 * is equal to this value may be valid or not; the limit
X	 * between valid and invalid numbers is then based on the last
X	 * digit.  For instance, if the range for longs is
X	 * [-2147483648..2147483647] and the input base is 10,
X	 * cutoff will be set to 214748364 and cutlim to either
X	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
X	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
X	 * the number is too big, and we will return a range error.
X	 *
X	 * Set any if any `digits' consumed; make it negative to indicate
X	 * overflow.
X	 */
X	cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
X	cutlim = cutoff % (unsigned long)base;
X	cutoff /= (unsigned long)base;
X	for (acc = 0, any = 0;; c = *s++) {
X		if (isdigit(c))
X			c -= '0';
X		else if (isalpha(c))
X			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
X		else
X			break;
X		if (c >= base)
X			break;
X		if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
X			any = -1;
X		else {
X			any = 1;
X			acc *= base;
X			acc += c;
X		}
X	}
X	if (any < 0) {
X		acc = neg ? LONG_MIN : LONG_MAX;
X		errno = ERANGE;
X	} else if (neg)
X		acc = -acc;
X	if (endptr != 0)
X		*endptr = any ? s - 1 : nptr;
X	return (acc);
X}
//go.sysin dd *
if [ `wc -c < strtol.c` != 2648 ]; then
	made=false
	echo error transmitting strtol.c --
	echo length should be 2648, not `wc -c < strtol.c`
else
	made=true
fi
if $made; then
	chmod 644 strtol.c
	echo -n '	'; ls -ld strtol.c
fi
echo Extracting strtoul.c
sed 's/^X//' <<'//go.sysin dd *' >strtoul.c
X/*
X * Copyright (c) 1988 Regents of the University of California.
X * All rights reserved.  The Berkeley software License Agreement
X * specifies the terms and conditions for redistribution.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "%W% (Berkeley) %G%";
X#endif /* LIBC_SCCS and not lint */
X
X#include <limits.h>
X#include <ctype.h>
X#include <errno.h>
X
Xint	errno;
X
X/*
X * Convert a string to an unsigned long integer.
X *
X * Ignores `locale' stuff.  Assumes that the upper and lower case
X * alphabets and digits are each contiguous.
X */
Xunsigned long
Xstrtoul(nptr, endptr, base)
X	char *nptr, **endptr;
X	register int base;
X{
X	register char *s = nptr;
X	register unsigned long acc;
X	register int c;
X	register unsigned long cutoff;
X	register int neg = 0, any, cutlim;
X
X	/*
X	 * See strtol for comments as to the logic used.
X	 */
X	do {
X		c = *s++;
X	} while (isspace(c));
X	if (c == '-') {
X		neg = 1;
X		c = *s++;
X	} else if (c == '+')
X		c = *s++;
X	if ((base == 0 || base == 16) &&
X	    c == '0' && (*s == 'x' || *s == 'X')) {
X		c = s[1];
X		s += 2;
X		base = 16;
X	}
X	if (base == 0)
X		base = c == '0' ? 8 : 10;
X	cutoff = (unsigned long)ULONG_MAX / (unsigned long)base;
X	cutlim = (unsigned long)ULONG_MAX % (unsigned long)base;
X	for (acc = 0, any = 0;; c = *s++) {
X		if (isdigit(c))
X			c -= '0';
X		else if (isalpha(c))
X			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
X		else
X			break;
X		if (c >= base)
X			break;
X		if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
X			any = -1;
X		else {
X			any = 1;
X			acc *= base;
X			acc += c;
X		}
X	}
X	if (any < 0) {
X		acc = ULONG_MAX;
X		errno = ERANGE;
X	} else if (neg)
X		acc = -acc;
X	if (endptr != 0)
X		*endptr = any ? s - 1 : nptr;
X	return (acc);
X}
//go.sysin dd *
if [ `wc -c < strtoul.c` != 1697 ]; then
	made=false
	echo error transmitting strtoul.c --
	echo length should be 1697, not `wc -c < strtoul.c`
else
	made=true
fi
if $made; then
	chmod 644 strtoul.c
	echo -n '	'; ls -ld strtoul.c
fi
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

dhesi@bsu-cs.bsu.edu (Rahul Dhesi) (06/21/89)

In article <18164@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>X * All rights reserved.  The Berkeley software License Agreement
>X * specifies the terms and conditions for redistribution.

Doubtful...For one thing, most people on Usenet don't even have a copy
of the Berkeley software license agreement.  For another, they probably
never agreed to it.

Finally, the very act of posting something to the net violates the
Berkeley license agreement, if the one I have is any guide.  It forbids
distribution of software covered by it to anybody who doesn't have an
AT&T source license.

Perhaps the problem lies partly in calling this license agreement
"*The* Berkeley software License Agreement," which implies there is
only one.  There is probably more than one, and we really should
specify which one.  (Presumably not the one in my file cabinet,
-- 
Rahul Dhesi <dhesi@bsu-cs.bsu.edu>
UUCP:    ...!{iuvax,pur-ee}!bsu-cs!dhesi