summaryrefslogtreecommitdiff
path: root/test/stdlib
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@uclibc-ng.org>2016-10-24 20:22:12 +0200
committerWaldemar Brodkorb <wbx@uclibc-ng.org>2016-10-24 20:22:12 +0200
commit7988979a722b4cdf287b2093956a76a3f19b9897 (patch)
treed35e251d0472ceca55a2eef61cff261c8ee68fab /test/stdlib
add uClibc-ng test directory
Diffstat (limited to 'test/stdlib')
-rw-r--r--test/stdlib/Makefile8
-rw-r--r--test/stdlib/Makefile.in15
-rw-r--r--test/stdlib/ptytest.c20
-rw-r--r--test/stdlib/qsort.c53
-rw-r--r--test/stdlib/test-canon.c251
-rw-r--r--test/stdlib/test-canon2.c86
-rw-r--r--test/stdlib/test-mkostemp-O_CLOEXEC.c45
-rw-r--r--test/stdlib/test-mkostemp-child.c22
-rw-r--r--test/stdlib/testarc4random.c10
-rw-r--r--test/stdlib/testatexit.c81
-rw-r--r--test/stdlib/teston_exit.c82
-rw-r--r--test/stdlib/teststrtol.c109
-rw-r--r--test/stdlib/teststrtoq.c89
13 files changed, 871 insertions, 0 deletions
diff --git a/test/stdlib/Makefile b/test/stdlib/Makefile
new file mode 100644
index 0000000..567e0e3
--- /dev/null
+++ b/test/stdlib/Makefile
@@ -0,0 +1,8 @@
+# uClibc stdlib tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+top_builddir=../../
+top_srcdir=../../
+include ../Rules.mak
+-include Makefile.in
+include ../Test.mak
diff --git a/test/stdlib/Makefile.in b/test/stdlib/Makefile.in
new file mode 100644
index 0000000..f39941d
--- /dev/null
+++ b/test/stdlib/Makefile.in
@@ -0,0 +1,15 @@
+# uClibc stdlib tests
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+
+DODIFF_qsort := 1
+DODIFF_testatexit := 1
+DODIFF_teston_exit := 1
+DODIFF_teststrtol := 1
+
+TESTS_DISABLED :=
+ifeq ($(UCLIBC_HAS_PTY),)
+TESTS_DISABLED += ptytest
+endif
+ifeq ($(UCLIBC_HAS_ARC4RANDOM),)
+TESTS_DISABLED += testarc4random
+endif
diff --git a/test/stdlib/ptytest.c b/test/stdlib/ptytest.c
new file mode 100644
index 0000000..a795638
--- /dev/null
+++ b/test/stdlib/ptytest.c
@@ -0,0 +1,20 @@
+#define _XOPEN_SOURCE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ int fd;
+ char *cp;
+
+ fd=open("/dev/ptmx",O_NOCTTY|O_RDWR);
+ cp=ptsname(fd);
+ if (cp==NULL)
+ return EXIT_FAILURE;
+ printf("ptsname %s\n",cp);
+ return EXIT_SUCCESS;
+}
+
diff --git a/test/stdlib/qsort.c b/test/stdlib/qsort.c
new file mode 100644
index 0000000..74f9331
--- /dev/null
+++ b/test/stdlib/qsort.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int select_files(const struct dirent *dirbuf)
+{
+ if (dirbuf->d_name[0] == '.')
+ return 0;
+ else
+ return 1;
+}
+
+int main(void)
+{
+ struct dirent **array;
+ struct dirent *dirbuf;
+
+ int i, numdir;
+
+ chdir("/");
+ numdir = scandir(".", &array, select_files, NULL);
+ printf("\nGot %d entries from scandir().\n", numdir);
+ for (i = 0; i < numdir; ++i) {
+ dirbuf = array[i];
+ printf("[%d] %s\n", i, dirbuf->d_name);
+ free(array[i]);
+ }
+ free(array);
+ numdir = scandir(".", &array, select_files, alphasort);
+ printf("\nGot %d entries from scandir() using alphasort().\n", numdir);
+ for (i = 0; i < numdir; ++i) {
+ dirbuf = array[i];
+ printf("[%d] %s\n", i, dirbuf->d_name);
+ }
+ printf("\nCalling qsort()\n");
+ /* Even though some manpages say that alphasort should be
+ * int alphasort(const void *a, const void *b),
+ * in reality glibc and uclibc have const struct dirent**
+ * instead of const void*.
+ * Therefore we get a warning here unless we use a cast,
+ * which makes people think that alphasort prototype
+ * needs to be fixed in uclibc headers.
+ */
+ qsort(array, numdir, sizeof(struct dirent *), (void*) alphasort);
+ for (i = 0; i < numdir; ++i) {
+ dirbuf = array[i];
+ printf("[%d] %s\n", i, dirbuf->d_name);
+ free(array[i]);
+ }
+ free(array);
+ return (0);
+}
diff --git a/test/stdlib/test-canon.c b/test/stdlib/test-canon.c
new file mode 100644
index 0000000..1b43ded
--- /dev/null
+++ b/test/stdlib/test-canon.c
@@ -0,0 +1,251 @@
+/* Test program for returning the canonical absolute name of a given file.
+ Copyright (C) 1996,1997,2000,2002,2004,2005,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by David Mosberger <davidm@azstarnet.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file must be run from within a directory called "stdlib". */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+/* Prototype for our test function. */
+extern int do_test (int argc, char *argv[]);
+#include "../test-skeleton.c"
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+static char cwd[PATH_MAX];
+static size_t cwd_len;
+
+struct {
+ const char * name;
+ const char * value;
+} symlinks[] = {
+ {"SYMLINK_LOOP", "SYMLINK_LOOP"},
+ {"SYMLINK_1", "."},
+ {"SYMLINK_2", "//////./../../etc"},
+ {"SYMLINK_3", "SYMLINK_1"},
+ {"SYMLINK_4", "SYMLINK_2"},
+ {"SYMLINK_5", "doesNotExist"},
+};
+
+struct {
+ const char * in;
+ const char * retval; /* what realpath should return */
+ const char * retbuf; /* what realpath should store in buf */
+ /* if both of the above are NULL, we won't check for result,
+ * it's undefined */
+ int error; /* expected errno value */
+} tests[] = {
+ /* 0 */
+ {"/", "/"},
+ {"/////////////////////////////////", "/"},
+ {"/.././.././.././..///", "/"},
+ {"/etc", "/etc"},
+ {"/etc/../etc", "/etc"},
+ /* 5 */
+ {"/doesNotExist/../etc", 0, "/doesNotExist", ENOENT},
+ {"./././././././././.", "."},
+ {"/etc/.//doesNotExist", 0, "/etc/doesNotExist", ENOENT},
+ {"./doesExist", "./doesExist"},
+ {"./doesExist/", "./doesExist"},
+ /* 10 */
+ {"./doesExist/../doesExist", "./doesExist"},
+ {"foobar", 0, "./foobar", ENOENT},
+ {".", "."},
+ {"./foobar", 0, "./foobar", ENOENT},
+ {"SYMLINK_LOOP", 0, 0, ELOOP},
+ /* 15 */
+ {"./SYMLINK_LOOP", 0, 0, ELOOP},
+ {"SYMLINK_1", "."},
+ {"SYMLINK_1/foobar", 0, "./foobar", ENOENT},
+ {"SYMLINK_2", "/etc"},
+ {"SYMLINK_3", "."},
+ /* 20 */
+ {"SYMLINK_4", "/etc"},
+ {"../stdlib/SYMLINK_1", "."},
+ {"../stdlib/SYMLINK_2", "/etc"},
+ {"../stdlib/SYMLINK_3", "."},
+ {"../stdlib/SYMLINK_4", "/etc"},
+ /* 25 */
+ {"./SYMLINK_5", 0, "./doesNotExist", ENOENT},
+ {"SYMLINK_5", 0, "./doesNotExist", ENOENT},
+ {"SYMLINK_5/foobar", 0, "./doesNotExist", ENOENT},
+ {"doesExist/../../stdlib/doesExist", "./doesExist"},
+ {"doesExist/.././../stdlib/.", "."},
+#ifndef __UCLIBC__
+ /* we dont check for ENOTDIR in readlink() which causes failures to
+ * propogate up to realpath() ... so disable for now ... */
+ /* 30 */
+ {"./doesExist/someFile/", 0, "./doesExist/someFile", ENOTDIR},
+ {"./doesExist/someFile/..", 0, "./doesExist/someFile", ENOTDIR},
+#endif
+};
+
+
+static int
+check_path (const char * result, const char * expected)
+{
+ int good;
+
+ if (!result)
+ return (expected == NULL);
+
+ if (!expected)
+ return 0;
+
+ if (expected[0] == '.' && (expected[1] == '/' || expected[1] == '\0'))
+ good = (strncmp (result, cwd, cwd_len) == 0
+ && strcmp (result + cwd_len, expected + 1) == 0);
+ else
+ good = (strcmp (expected, result) == 0);
+
+ return good;
+}
+
+
+int
+do_test (int argc, char ** argv)
+{
+ char * result;
+ int i, errors = 0;
+ char buf[PATH_MAX];
+
+ getcwd (cwd, sizeof(buf));
+ cwd_len = strlen (cwd);
+
+#ifndef __UCLIBC__
+ /* we choose to crash in uClibc when given a NULL */
+ errno = 0;
+ if (realpath (NULL, buf) != NULL || errno != EINVAL)
+ {
+ printf ("%s: expected return value NULL and errno set to EINVAL"
+ " for realpath(NULL,...)\n", argv[0]);
+ ++errors;
+ }
+#endif
+
+#if 0
+ /* This is now allowed. The test is invalid. */
+ errno = 0;
+ if (realpath ("/", NULL) != NULL || errno != EINVAL)
+ {
+ printf ("%s: expected return value NULL and errno set to EINVAL"
+ " for realpath(...,NULL)\n", argv[0]);
+ ++errors;
+ }
+#endif
+
+ errno = 0;
+ if (realpath ("", buf) != NULL || errno != ENOENT)
+ {
+ printf ("%s: expected return value NULL and set errno to ENOENT"
+ " for realpath(\"\",...)\n", argv[0]);
+ ++errors;
+ }
+
+ for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
+ symlink (symlinks[i].value, symlinks[i].name);
+
+ int has_dir = mkdir ("doesExist", 0777) == 0;
+
+ int fd = has_dir ? creat ("doesExist/someFile", 0777) : -1;
+
+ for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i)
+ {
+ buf[0] = '\0';
+ errno = 0;
+ result = realpath (tests[i].in, buf);
+
+ if (!check_path (result, tests[i].retval))
+ {
+ printf ("%s: flunked test %d (expected `%s', got `%s')\n",
+ argv[0], i, tests[i].retval ? tests[i].retval : "NULL",
+ result ? result : "NULL");
+ ++errors;
+ continue;
+ }
+
+ if (result && !check_path (buf, tests[i].retval ? tests[i].retval : tests[i].retbuf))
+ {
+ printf ("%s: flunked test %d (expected resolved `%s', got `%s')\n",
+ argv[0], i, tests[i].retval ? tests[i].retval : tests[i].retbuf,
+ buf);
+ ++errors;
+ continue;
+ }
+
+ if (errno != tests[i].error)
+ {
+ printf ("%s: flunked test %d (expected errno %d, got %d)\n",
+ argv[0], i, tests[i].error, errno);
+ ++errors;
+ continue;
+ }
+
+#ifndef __UCLIBC__
+ /* we choose to crash in uClibc when given a NULL */
+ char *result2 = realpath (tests[i].in, NULL);
+ if ((result2 == NULL && result != NULL)
+ || (result2 != NULL && strcmp (result, result2) != 0))
+ {
+ printf ("\
+%s: realpath(..., NULL) produced different result than realpath(..., buf): '%s' vs '%s'\n",
+ argv[0], result2, result);
+ ++errors;
+ }
+ free (result2);
+#endif
+ }
+
+ getcwd (buf, sizeof(buf));
+ if (strcmp (buf, cwd))
+ {
+ printf ("%s: current working directory changed from %s to %s\n",
+ argv[0], cwd, buf);
+ ++errors;
+ }
+
+ if (fd >= 0)
+ {
+ close (fd);
+ unlink ("doesExist/someFile");
+ }
+
+ if (has_dir)
+ rmdir ("doesExist");
+
+ for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
+ unlink (symlinks[i].name);
+
+ if (errors != 0)
+ {
+ printf ("%d errors.\n", errors);
+ return EXIT_FAILURE;
+ }
+
+ puts ("No errors.");
+ return EXIT_SUCCESS;
+}
diff --git a/test/stdlib/test-canon2.c b/test/stdlib/test-canon2.c
new file mode 100644
index 0000000..4a03b2d
--- /dev/null
+++ b/test/stdlib/test-canon2.c
@@ -0,0 +1,86 @@
+/* Test for realpath/canonicalize function.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <string.h>
+
+
+/* Prototype for our test function. */
+extern void do_prepare (int argc, char *argv[]);
+extern int do_test (int argc, char *argv[]);
+
+/* We have a preparation function. */
+#define PREPARE do_prepare
+
+#include <test-skeleton.c>
+
+/* Name of the temporary files we create. */
+char *name1;
+char *name2;
+
+/* Preparation. */
+void
+do_prepare (int argc, char *argv[])
+{
+ size_t test_dir_len;
+ int tfd;
+
+ test_dir_len = strlen (test_dir);
+
+ /* Generate the circular symlinks. */
+ name1 = malloc (test_dir_len + sizeof ("/canonXXXXXX"));
+ mempcpy (mempcpy (name1, test_dir, test_dir_len),
+ "/canonXXXXXX", sizeof ("/canonXXXXXX"));
+ name2 = strdup (name1);
+ tfd = mkstemp(name1);
+ if (tfd < 0) {
+ printf("%s: cannot generate temp file name\n", __FUNCTION__);
+ exit(1);
+ }
+ close(tfd);
+ add_temp_file (name1);
+ tfd = mkstemp(name2);
+ if (tfd < 0) {
+ printf("%s: cannot generate temp file name\n", __FUNCTION__);
+ exit(1);
+ }
+ close(tfd);
+ add_temp_file (name2);
+}
+
+
+/* Run the test. */
+int
+do_test (int argc, char *argv[])
+{
+ char *canon;
+
+ printf ("create symlinks from %s to %s and vice versa\n", name1, name2);
+ if (symlink (name1, name2) == -1
+ || symlink (name2, name1) == -1)
+ /* We cannot test this. */
+ return 0;
+
+ /* Call the function. This is equivalent the using `realpath' but the
+ function allocates the room for the result. */
+ errno = 0;
+ canon = canonicalize_file_name (name1);
+
+ return canon != NULL || errno != ELOOP;
+}
diff --git a/test/stdlib/test-mkostemp-O_CLOEXEC.c b/test/stdlib/test-mkostemp-O_CLOEXEC.c
new file mode 100644
index 0000000..9ff229a
--- /dev/null
+++ b/test/stdlib/test-mkostemp-O_CLOEXEC.c
@@ -0,0 +1,45 @@
+#define _XOPEN_SOURCE_EXTENDED
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#if !defined __ARCH_USE_MMU__
+# define fork vfork
+#endif
+
+int main(int argc, char *argv[]) {
+ int fd, status;
+ char buff[5];
+ char template[] = "/tmp/test-mkostemp.XXXXXX";
+
+ fd = mkostemp(template, O_CLOEXEC);
+ unlink(template);
+
+ snprintf(buff, 5, "%d", fd);
+
+ if(!fork())
+ if(execl("./test-mkostemp-child", "test-mkostemp-child", buff, NULL) == -1)
+ exit(EXIT_FAILURE);
+
+ wait(&status);
+
+ memset(buff, 0, 5);
+ lseek(fd, 0, SEEK_SET);
+ errno = 0;
+ if(read(fd, buff, 5) == -1)
+ exit(EXIT_FAILURE);
+
+ if(!strncmp(buff, "test", 5))
+ exit(EXIT_FAILURE);
+ else
+ exit(EXIT_SUCCESS);
+
+ close(fd);
+ exit(EXIT_SUCCESS);
+}
diff --git a/test/stdlib/test-mkostemp-child.c b/test/stdlib/test-mkostemp-child.c
new file mode 100644
index 0000000..708bd80
--- /dev/null
+++ b/test/stdlib/test-mkostemp-child.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+ int fd;
+
+ /* This file gets built and run as a test, but its
+ * really just a helper for test-mkostemp-O_CLOEXEC.c.
+ * So, we'll always return succcess.
+ */
+ if(argc != 2)
+ exit(EXIT_SUCCESS);
+
+ sscanf(argv[1], "%d", &fd);
+
+ if(write(fd, "test\0", 5) == -1)
+ ; /* Don't Panic! Failure is okay here. */
+
+ close(fd);
+ exit(EXIT_SUCCESS);
+}
diff --git a/test/stdlib/testarc4random.c b/test/stdlib/testarc4random.c
new file mode 100644
index 0000000..14ff1cc
--- /dev/null
+++ b/test/stdlib/testarc4random.c
@@ -0,0 +1,10 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void)
+{
+ int random_number;
+ random_number = arc4random() % 65536;
+ printf("%d\n", random_number);
+ return 0;
+}
diff --git a/test/stdlib/testatexit.c b/test/stdlib/testatexit.c
new file mode 100644
index 0000000..01874fd
--- /dev/null
+++ b/test/stdlib/testatexit.c
@@ -0,0 +1,81 @@
+/*
+ * This test program will register the maximum number of exit functions
+ * with atexit(). When this program exits, each exit function should get
+ * called in the reverse order in which it was registered. (If the system
+ * supports more than 25 exit functions, the function names will loop, but
+ * the effect will be the same. Feel free to add more functions if desired)
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef void (*vfuncp) (void);
+
+/* All functions call exit(), in order to test that exit functions can call
+ * exit() without screwing everything up. :)
+ */
+#define make_exitfunc(num) \
+__attribute__ ((__noreturn__)) static \
+void exitfunc##num(void) \
+{ \
+ printf("Executing exitfunc"#num".\n"); \
+ exit(0); \
+}
+make_exitfunc(0)
+make_exitfunc(1)
+make_exitfunc(2)
+make_exitfunc(3)
+make_exitfunc(4)
+make_exitfunc(5)
+make_exitfunc(6)
+make_exitfunc(7)
+make_exitfunc(8)
+make_exitfunc(9)
+make_exitfunc(10)
+make_exitfunc(11)
+make_exitfunc(12)
+make_exitfunc(13)
+make_exitfunc(14)
+make_exitfunc(15)
+make_exitfunc(16)
+make_exitfunc(17)
+make_exitfunc(18)
+make_exitfunc(19)
+make_exitfunc(20)
+make_exitfunc(21)
+make_exitfunc(22)
+make_exitfunc(23)
+make_exitfunc(24)
+
+static vfuncp func_table[] =
+ {
+ exitfunc0, exitfunc1, exitfunc2, exitfunc3, exitfunc4,
+ exitfunc5, exitfunc6, exitfunc7, exitfunc8, exitfunc9,
+ exitfunc10, exitfunc11, exitfunc12, exitfunc13, exitfunc14,
+ exitfunc15, exitfunc16, exitfunc17, exitfunc18, exitfunc19,
+ exitfunc20, exitfunc21, exitfunc22, exitfunc23, exitfunc24
+ };
+
+/* glibc dynamically adds exit functions, so it will keep adding until
+ * it runs out of memory! So this will limit the number of exit functions
+ * we add in the loop below. uClibc has a set limit (currently 20), so the
+ * loop will go until it can't add any more (so it should not hit this limit).
+ */
+#define ATEXIT_LIMIT 20
+
+int
+main ( void )
+{
+ int i = 0;
+ int count = 0;
+ int numfuncs = sizeof(func_table)/sizeof(vfuncp);
+
+ /* loop until no more can be added */
+ while(count < ATEXIT_LIMIT && atexit(func_table[i]) >= 0) {
+ printf("Registered exitfunc%d with atexit()\n", i);
+ count++;
+ i = (i+1) % numfuncs;
+ }
+ printf("%d functions registered with atexit.\n", count);
+
+ return 0;
+}
diff --git a/test/stdlib/teston_exit.c b/test/stdlib/teston_exit.c
new file mode 100644
index 0000000..f7e8fd0
--- /dev/null
+++ b/test/stdlib/teston_exit.c
@@ -0,0 +1,82 @@
+/*
+ * This test program will register the maximum number of exit functions
+ * with on_exit(). When this program exits, each exit function should get
+ * called in the reverse order in which it was registered. (If the system
+ * supports more than 25 exit functions, the function names will loop, but
+ * the effect will be the same. Feel free to add more functions if desired)
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef void (*efuncp) (int, void *);
+
+/* All functions call exit(), in order to test that exit functions can call
+ * exit() without screwing everything up. The value passed in through arg gets
+ * used as the next exit status.
+ */
+#define make_exitfunc(num) \
+__attribute__ ((__noreturn__)) static \
+void exitfunc##num(int status, void *arg) \
+{ \
+ printf("Executing exitfunc"#num" (status=%d, arg=%lu)\n", status, (unsigned long)arg); \
+ exit((unsigned long)arg); \
+}
+make_exitfunc(0)
+make_exitfunc(1)
+make_exitfunc(2)
+make_exitfunc(3)
+make_exitfunc(4)
+make_exitfunc(5)
+make_exitfunc(6)
+make_exitfunc(7)
+make_exitfunc(8)
+make_exitfunc(9)
+make_exitfunc(10)
+make_exitfunc(11)
+make_exitfunc(12)
+make_exitfunc(13)
+make_exitfunc(14)
+make_exitfunc(15)
+make_exitfunc(16)
+make_exitfunc(17)
+make_exitfunc(18)
+make_exitfunc(19)
+make_exitfunc(20)
+make_exitfunc(21)
+make_exitfunc(22)
+make_exitfunc(23)
+make_exitfunc(24)
+
+static efuncp func_table[] =
+ {
+ exitfunc0, exitfunc1, exitfunc2, exitfunc3, exitfunc4,
+ exitfunc5, exitfunc6, exitfunc7, exitfunc8, exitfunc9,
+ exitfunc10, exitfunc11, exitfunc12, exitfunc13, exitfunc14,
+ exitfunc15, exitfunc16, exitfunc17, exitfunc18, exitfunc19,
+ exitfunc20, exitfunc21, exitfunc22, exitfunc23, exitfunc24
+ };
+
+/* glibc dynamically adds exit functions, so it will keep adding until
+ * it runs out of memory! So this will limit the number of exit functions
+ * we add in the loop below. uClibc has a set limit (currently 20), so the
+ * loop will go until it can't add any more (so it should not hit this limit).
+ */
+#define ON_EXIT_LIMIT 20
+
+int
+main ( void )
+{
+ int i = 0;
+ unsigned long count = 0;
+ int numfuncs = sizeof(func_table)/sizeof(efuncp);
+
+ /* loop until no more can be added */
+ while(count < ON_EXIT_LIMIT && on_exit(func_table[i], (void *)count) >= 0) {
+ count++;
+ printf("Registered exitfunc%d with on_exit()\n", i);
+ i = (i+1) % numfuncs;
+ }
+ printf("%lu functions registered with on_exit.\n", count);
+ exit(count);
+}
+
diff --git a/test/stdlib/teststrtol.c b/test/stdlib/teststrtol.c
new file mode 100644
index 0000000..5b43a9b
--- /dev/null
+++ b/test/stdlib/teststrtol.c
@@ -0,0 +1,109 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+const char *strings[]={
+ /* some simple stuff */
+ "0", "1", "10",
+ "100", "1000", "10000", "100000", "1000000",
+ "10000000", "100000000", "1000000000",
+
+ /* negative */
+ "-0", "-1", "-10",
+ "-100", "-1000", "-10000", "-100000", "-1000000",
+ "-10000000", "-100000000", "-1000000000",
+
+ /* test base>10 */
+ "a", "b", "f", "g", "z",
+
+ /* test hex */
+ "0x0", "0x1", "0xa", "0xf", "0x10",
+
+ /* test octal */
+ "00", "01", "07", "08", "0a", "010",
+
+ /* other */
+ "0x8000000",
+
+ /* check overflow cases: (for 32 bit) */
+ "2147483645",
+ "2147483646",
+ "2147483647",
+ "2147483648",
+ "2147483649",
+ "-2147483645",
+ "-2147483646",
+ "-2147483647",
+ "-2147483648",
+ "-2147483649",
+ "4294967293",
+ "4294967294",
+ "4294967295",
+ "4294967296",
+ "4294967297",
+ "-4294967293",
+ "-4294967294",
+ "-4294967295",
+ "-4294967296",
+ "-4294967297",
+
+ /* bad input tests */
+ "",
+ "00",
+ "0x",
+ "0x0",
+ "-",
+ "+",
+ " ",
+ " -",
+ " - 0",
+};
+int n_tests=sizeof(strings)/sizeof(strings[0]);
+
+void do_test(int base);
+void do_utest(int base);
+
+int main(int argc,char *argv[])
+{
+ do_test(0);
+ do_test(8);
+ do_test(10);
+ do_test(16);
+ do_test(36);
+
+ do_utest(0);
+ do_utest(8);
+ do_utest(10);
+ do_utest(16);
+ do_utest(36);
+
+ return 0;
+}
+
+void do_test(int base)
+{
+ int i;
+ long n;
+ char *endptr;
+
+ for(i=0;i<n_tests;i++){
+ n=strtol(strings[i],&endptr,base);
+ printf("strtol(\"%s\",%d) len=%lu res=%ld\n",
+ strings[i],base,(unsigned long)(endptr-strings[i]),n);
+ }
+}
+
+void do_utest(int base)
+{
+ int i;
+ unsigned long n;
+ char *endptr;
+
+ for(i=0;i<n_tests;i++){
+ n=strtoul(strings[i],&endptr,base);
+ printf("strtoul(\"%s\",%d) len=%lu res=%lu\n",
+ strings[i],base,(unsigned long)(endptr-strings[i]),n);
+ }
+}
+
diff --git a/test/stdlib/teststrtoq.c b/test/stdlib/teststrtoq.c
new file mode 100644
index 0000000..6e1a4cb
--- /dev/null
+++ b/test/stdlib/teststrtoq.c
@@ -0,0 +1,89 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+const char *strings[]={
+ /* some simple stuff */
+ "0", "1", "10",
+ "100", "1000", "10000", "100000", "1000000",
+ "10000000", "100000000", "1000000000",
+
+ /* negative */
+ "-0", "-1", "-10",
+ "-100", "-1000", "-10000", "-100000", "-1000000",
+ "-10000000", "-100000000", "-1000000000",
+
+ /* test base>10 */
+ "a", "b", "f", "g", "z",
+
+ /* test hex */
+ "0x0", "0x1", "0xa", "0xf", "0x10",
+
+ /* test octal */
+ "00", "01", "07", "08", "0a", "010",
+
+ /* other */
+ "0x8000000",
+
+ /* check overflow cases: (for 32 bit) */
+ "2147483645",
+ "2147483646",
+ "2147483647",
+ "2147483648",
+ "2147483649",
+ "-2147483645",
+ "-2147483646",
+ "-2147483647",
+ "-2147483648",
+ "-2147483649",
+ "4294967293",
+ "4294967294",
+ "4294967295",
+ "4294967296",
+ "4294967297",
+ "-4294967293",
+ "-4294967294",
+ "-4294967295",
+ "-4294967296",
+ "-4294967297",
+
+ /* bad input tests */
+ "",
+ "00",
+ "0x",
+ "0x0",
+ "-",
+ "+",
+ " ",
+ " -",
+ " - 0",
+};
+int n_tests=sizeof(strings)/sizeof(strings[0]);
+
+
+
+void do_test(int base);
+void do_test(int base)
+{
+ int i;
+ quad_t n;
+ char *endptr;
+
+ for(i=0;i<n_tests;i++){
+ n=strtoq(strings[i],&endptr,base);
+ printf("strtoq(\"%s\",%d) len=%lu res=%qd\n",
+ strings[i],base,(unsigned long)(endptr-strings[i]),n);
+ }
+}
+
+int main(int argc,char *argv[])
+{
+ do_test(0);
+ do_test(8);
+ do_test(10);
+ do_test(16);
+ do_test(36);
+
+ return 0;
+}