#define LONG_MAX 2147483647L /* maximum value of a long */
#define ULONG_MAX 0xFFFFFFFFL /* maximum value of an unsigned long */
+/*Definitions about long longs (64 bits, may not be supported). */
+#ifdef __LONG_LONG_SUPPORTED
+#define LLONG_MIN (-0x7FFFFFFFFFFFFFFFLL-1) /* minimum value of a
+ * long long
+ */
+#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL /* maximum value of a
+ * long long
+ */
+#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL /* maximum value of an
+ * unsigned long long
+ */
+#endif
+
#include <minix/dir.h>
/* Minimum sizes required by the POSIX P1003.1 standard (Table 2-3). */
_PROTOTYPE( int setenv, (const char *envname, const char *envval,
int overwrite) );
_PROTOTYPE( int unsetenv, (const char *name) );
+
+#ifdef __LONG_LONG_SUPPORTED
+_PROTOTYPE( long long strtoll, (const char *_nptr, char **_endptr,
+ int _base) );
+_PROTOTYPE( unsigned long long strtoull, (const char *_nptr,
+ char **_endptr, int _base) );
+#endif
+
#endif
#ifdef _MINIX
strlcat.c \
strlcpy.c \
strtok_r.c \
+ strtoll.c \
swab.c \
sys_eniop.c \
syscall.c \
--- /dev/null
+/* Erik van der Kouwe, 8 December 2009, based on lib/ansi/strtol.c */
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __LONG_LONG_SUPPORTED
+
+static unsigned long long string2long(const char *nptr, char **endptr,
+ int base, int is_signed);
+
+long long strtoll(const char *nptr, char **endptr, int base)
+{
+ return (long long) string2long(nptr, endptr, base, 1);
+}
+
+unsigned long long strtoull(const char *nptr, char **endptr, int base)
+{
+ return (unsigned long long) string2long(nptr, endptr, base, 0);
+}
+
+#define between(a, c, z) \
+ ((unsigned long) ((c) - (a)) <= (unsigned long) ((z) - (a)))
+
+static unsigned long long string2long(const char *nptr, char **const endptr,
+ int base, int is_signed)
+{
+ unsigned int v;
+ unsigned long long val = 0;
+ int c;
+ int ovfl = 0, sign = 1;
+ const char *startnptr = nptr, *nrstart;
+
+ if (endptr) *endptr = (char *)nptr;
+ while (isspace(*nptr)) nptr++;
+ c = *nptr;
+
+ if (c == '-' || c == '+') {
+ if (c == '-') sign = -1;
+ nptr++;
+ }
+ nrstart = nptr; /* start of the number */
+
+ /* When base is 0, the syntax determines the actual base */
+ if (base == 0)
+ if (*nptr == '0')
+ if (*++nptr == 'x' || *nptr == 'X') {
+ base = 16;
+ nptr++;
+ }
+ else base = 8;
+ else base = 10;
+ else if (base==16 && *nptr=='0' && (*++nptr =='x' || *nptr =='X'))
+ nptr++;
+
+ for (;;) {
+ c = *nptr;
+ if (between('0', c, '9')) {
+ v = c - '0';
+ } else
+ if (between('a', c, 'z')) {
+ v = c - 'a' + 0xa;
+ } else
+ if (between('A', c, 'Z')) {
+ v = c - 'A' + 0xA;
+ } else {
+ break;
+ }
+ if (v >= base) break;
+ if (val > (ULLONG_MAX - v) / base) ovfl++;
+ val = (val * base) + v;
+ nptr++;
+ }
+ if (endptr) {
+ if (nrstart == nptr) *endptr = (char *)startnptr;
+ else *endptr = (char *)nptr;
+ }
+
+ if (!ovfl) {
+ /* Overflow is only possible when converting a signed long. */
+ if (is_signed
+ && ((sign < 0 && val > -(unsigned long long)LLONG_MIN)
+ || (sign > 0 && val > LLONG_MAX)))
+ ovfl++;
+ }
+
+ if (ovfl) {
+ errno = ERANGE;
+ if (is_signed)
+ if (sign < 0) return LLONG_MIN;
+ else return LLONG_MAX;
+ else return ULLONG_MAX;
+ }
+ return (long) sign * val;
+}
+
+#endif /* defined(__LONG_LONG_SUPPORTED) */
--- /dev/null
+.TH STRTOL 3 "December 9, 2009"
+.UC 4
+.SH NAME
+strtol, strtoll, strtoul, strtoull \- convert string to number
+.SH SYNOPSIS
+.nf
+.ft B
+#include <stdlib.h>
+
+long strtol(const char *\fInptr\fP, char **\fIendptr\fP, int \fIbase\fP);
+unsigned long strtoul(const char *\fInptr\fP, char **\fIendptr\fP, int \fIbase\fP);
+#ifdef __LONG_LONG_SUPPORTED
+long long strtoll(const char *\fInptr\fP, char **\fIendptr\fP, int \fIbase\fP);
+unsigned long long strtoull(const char *\fInptr\fP, char **\fIendptr\fP, int \fIbase\fP);
+#endif
+.fi
+.SH DESCRIPTION
+These functions parse as much from the string \fInptr\fP as possible and return
+it as an integer. The string should consist of any number of whitespace
+characters followed by a sign (either plus or minus) and at least one digit in
+the specified \fIbase\fP. The digits of a hexadecimal string may be preceded by
+the prefix 0x or 0X, which is ignored. If \fIbase\fP is zero, hexadecimal is
+assumed if this prefix is present, octal is assumed if there is a leading zero
+and decimal is assumed otherwise. If not zero, \fIbase\fI must be at least 2
+and at most 36. A pointer to the first character following the numeric string is
+stored in *\fIendptr\fP.
+.PP
+Note that the strtoll and strtoull functions, which return 64-bit values,
+are supported only on GCC as ACK does not support 64-bit arithmatic.
+.SH "RETURN VALUE
+The parsed number is returned.
+.SH "SEE ALSO"
+.BR atoi (3).
# Makefile for the tests.
CC = exec cc
+GCC = /usr/gnu/bin/gcc
CFLAGS= -O -D_MINIX -D_POSIX_SOURCE
+CFLAGS-GCC= $(CFLAGS) -Wall
OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
test10 test12 test13 test14 test15 test16 test17 test18 test19 \
test21 test22 test23 test25 test26 test27 test28 test29 \
test30 test31 test32 test34 test35 test36 test37 test38 \
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
- test42 test44
+ test42 test44 test45
BIGOBJ= test20 test24
ROOTOBJ= test11 test33 test43
+GCCOBJ= test45-gcc
-all: $(OBJ) $(BIGOBJ) $(ROOTOBJ)
+all: $(OBJ) $(BIGOBJ) $(GCCOBJ) $(ROOTOBJ)
chmod 755 *.sh run
$(OBJ):
$(BIGOBJ):
$(CC) $(CFLAGS) -o $@ $@.c
+$(GCCOBJ):
+ [ ! -x $(GCC) ] || $(GCC) $(CFLAGS-GCC) -o $@ $<
+
$(ROOTOBJ):
$(CC) $(CFLAGS) $@.c
@install -c -o root -m 4755 a.out $@
clean:
cd select && make clean
- -rm -rf *.o *.s *.bak test? test?? t10a t11a t11b \
+ -rm -rf *.o *.s *.bak test? test?? test??-gcc t10a t11a t11b \
t40a t40b t40c t40d t40e t40f t43 DIR*
test1: test1.c
test42: test42.c
test43: test43.c
test44: test44.c
+test45: test45.c test45.h
+test45-gcc: test45.c test45.h
+
rm -rf DIR* # remove any old junk lying around
passed=`expr 0` # count number of tests run correctly
failed=`expr 0` # count number of tests that failed
+skipped=`expr 0` # count number of tests that were skipped
total=`expr 0` # total number of tests tried
badones= # list of tests that failed
# Run all the tests, keeping track of who failed.
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
- 41 42 43 44 sh1.sh sh2.sh
-do total=`expr $total + 1`
- FAIL=0
- if [ $USER = root -a \( $i = 11 -o $i = 33 \) ]
- then su - ast -c "cd `pwd`; ./test$i" || FAIL=1
- else ./test$i || FAIL=1
- fi
-
- if [ $FAIL -eq 0 ]
- then passed=`expr $passed + 1`
- else failed=`expr $failed + 1`
- badones=`echo $badones " " $i`
+ 41 42 43 44 45 45-gcc sh1.sh sh2.sh
+do
+ if [ -x ./test$i ]
+ then
+ total=`expr $total + 1`
+ FAIL=0
+ if [ $USER = root -a \( $i = 11 -o $i = 33 \) ]
+ then su - ast -c "cd `pwd`; ./test$i" || FAIL=1
+ else ./test$i || FAIL=1
+ fi
+ if [ $FAIL -eq 0 ]
+ then passed=`expr $passed + 1`
+ else failed=`expr $failed + 1`
+ badones=`echo $badones " " $i`
+ fi
+ else
+ skipped=`expr $skipped + 1`
fi
done
# Print results of the tests.
echo " "
if test $total = $passed
- then echo All $passed tests completed without error.
- else echo Testing completed. Score: $passed passed, $failed failed
+ then echo All $passed tests completed without error \($skipped skipped\).
+ else echo Testing completed. Score: $passed passed, $failed failed, \
+ skipped $skipped
echo The following tests failed: $badones
fi
--- /dev/null
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MAX_ERROR 4
+static int errct;
+
+/* test strtol */
+#define TYPE long
+#define TYPEU unsigned long
+#define TYPE_FUNC strtol
+#include "test45.h"
+#undef TYPE
+#undef TYPEU
+#undef TYPE_FUNC
+
+/* test strtoul */
+#define TYPE unsigned long
+#define TYPEU unsigned long
+#define TYPE_FUNC strtoul
+#include "test45.h"
+#undef TYPE
+#undef TYPEU
+#undef TYPE_FUNC
+
+#ifdef __LONG_LONG_SUPPORTED
+
+/* test strtoll */
+#define TYPE long long
+#define TYPEU unsigned long long
+#define TYPE_FUNC strtoll
+#include "test45.h"
+#undef TYPE
+#undef TYPEU
+#undef TYPE_FUNC
+
+/* test strtoull */
+#define TYPE long long
+#define TYPEU unsigned long long
+#define TYPE_FUNC strtoull
+#include "test45.h"
+#undef TYPE
+#undef TYPEU
+#undef TYPE_FUNC
+
+#endif /* defined(__LONG_LONG_SUPPORTED) */
+
+static void quit(void)
+{
+ if (errct == 0)
+ {
+ printf("ok\n");
+ exit(0);
+ }
+ else
+ {
+ printf("%d errors\n", errct);
+ exit(1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+#ifdef __LONG_LONG_SUPPORTED
+ printf("Test 45 (GCC) ");
+#else
+ printf("Test 45 (ACK) ");
+#endif
+ fflush(stdout);
+
+ /* run long/unsigned long tests */
+ test_strtol();
+ test_strtoul();
+
+ /* run long long/unsigned long long tests (GCC only) */
+#ifdef __LONG_LONG_SUPPORTED
+ test_strtoll();
+ test_strtoull();
+#endif /* defined(__LONG_LONG_SUPPORTED) */
+
+ quit();
+ return -1; /* never happens */
+}
--- /dev/null
+#define GLUE_HELPER(x, y) x ## _ ## y
+#define GLUE(x, y) GLUE_HELPER(x, y)
+#define TOSTRING(x) #x
+
+static const char *GLUE(make_string, TYPE_FUNC)(TYPE value, int base)
+{
+ static char buffer[66];
+ char *s; /* allows 64-bit base 2 value with minus and null */
+ TYPEU valuetemp;
+
+ /* build number string in proper base, work backwards, starting with null */
+ s = buffer + sizeof(buffer);
+ *--s = 0;
+
+ /* fill in the digits */
+ valuetemp = (value < 0) ? -value : value;
+ do
+ {
+ *--s = "0123456789abcdefghijklmnopqrstuvwxyz"[valuetemp % base];
+ valuetemp /= base;
+ } while (valuetemp);
+
+ /* add sign if needed */
+ if (value < 0)
+ *--s = '-';
+
+ return s;
+}
+
+static void GLUE(e, TYPE_FUNC)(int n, const char *s, TYPE result, int base)
+{
+ /* watch out: don't overwrite the static buffer in make_string */
+ printf("Subtest %s, error %d, errno=%d, s=\"%s\", base=%d, ", TOSTRING(TYPE_FUNC), n, errno, s, base);
+ printf("result=%s\n", GLUE(make_string, TYPE_FUNC)(result, base));
+ if (errct++ > MAX_ERROR)
+ {
+ printf("Too many errors; test aborted\n");
+ exit(1);
+ }
+}
+
+static void GLUE(test_string, TYPE_FUNC)(const char *s, TYPE value, int base)
+{
+ char *end;
+ TYPE result;
+
+ /* must convert the entire string, resulting in the requested value */
+ result = TYPE_FUNC(s, &end, base);
+ if (result != value) GLUE(e, TYPE_FUNC)(1, s, result, base);
+ if (*end) GLUE(e, TYPE_FUNC)(2, s, result, base);
+}
+
+static void GLUE(test_value_with_base, TYPE_FUNC)(TYPE value, int base)
+{
+ const char *s;
+
+ /* convert to string, then convert back */
+ s = GLUE(make_string, TYPE_FUNC)(value, base);
+ GLUE(test_string, TYPE_FUNC)(s, value, base);
+}
+
+static void GLUE(test_value, TYPE_FUNC)(TYPE value)
+{
+ int base;
+
+ /* let's get all our bases covered */
+ for (base = 2; base <= 36; base++)
+ GLUE(test_value_with_base, TYPE_FUNC)(value, base);
+}
+
+static void GLUE(test, TYPE_FUNC)(void)
+{
+ int base, i;
+ TYPE value, valuenext;
+
+ /* check 0x0000.... and 0xffff.... */
+ value = 0;
+ for (i = 0; i < 0x10000; i++)
+ {
+ /* test current value */
+ GLUE(test_value, TYPE_FUNC)(value);
+ GLUE(test_value, TYPE_FUNC)(-value);
+ value++;
+ }
+
+ /* check 0x8000.... and 0x7fff.... */
+ value = 0;
+ value = ((~value) << 1) >> 1;
+ for (i = 0; i < 0x10000; i++)
+ {
+ /* test current value */
+ GLUE(test_value, TYPE_FUNC)(value);
+ GLUE(test_value, TYPE_FUNC)(-value);
+ value++;
+ }
+
+ /* check powers of possible bases */
+ for (base = 2; base <= 36; base++)
+ {
+ value = 1;
+ while (1)
+ {
+ /* test current value with offsets */
+ for (i = -36; i <= 36; i++)
+ {
+ GLUE(test_value, TYPE_FUNC)(value + i);
+ GLUE(test_value, TYPE_FUNC)(-value + i);
+ }
+
+ /* stop after overflow */
+ valuenext = value * base;
+ if (valuenext <= value)
+ break;
+
+ value = valuenext;
+ }
+ }
+
+ /* automatic base */
+ GLUE(test_string, TYPE_FUNC)("10", 10, 0);
+ GLUE(test_string, TYPE_FUNC)("010", 010, 0);
+ GLUE(test_string, TYPE_FUNC)("010", 010, 8);
+ GLUE(test_string, TYPE_FUNC)("0x10", 0x10, 0);
+ GLUE(test_string, TYPE_FUNC)("0X10", 0X10, 0);
+ GLUE(test_string, TYPE_FUNC)("0x10", 0x10, 16);
+ GLUE(test_string, TYPE_FUNC)("0X10", 0X10, 16);
+
+ /* ignore plus sign, leading spaces and zeroes */
+ GLUE(test_string, TYPE_FUNC)("10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" 10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" 010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" 0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("\t10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("\t010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("\t0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" \t10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" \t010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" \t0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("+10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("+010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("+0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" +10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" +010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" +0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("\t+10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("\t+010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)("\t+0010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" \t+10", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" \t+010", 10, 10);
+ GLUE(test_string, TYPE_FUNC)(" \t+0010", 10, 10);
+}
+
+#undef GLUE_HELPER
+#undef GLUE
+#undef TOSTRING